changeset 51208:fa727a4d7934

8203641: Refactor String Deduplication into shared Summary: Allows string deduplication to be shared among different collectors Reviewed-by: tschatzl, rkennke
author zgu
date Thu, 14 Jun 2018 09:59:21 -0400
parents 64ca9fbcf85f
children 72c694f035ee
files src/hotspot/share/gc/g1/g1StringDedup.cpp src/hotspot/share/gc/g1/g1StringDedup.hpp src/hotspot/share/gc/g1/g1StringDedupQueue.cpp src/hotspot/share/gc/g1/g1StringDedupQueue.hpp src/hotspot/share/gc/g1/g1StringDedupStat.cpp src/hotspot/share/gc/g1/g1StringDedupStat.hpp src/hotspot/share/gc/g1/g1StringDedupTable.cpp src/hotspot/share/gc/g1/g1StringDedupTable.hpp src/hotspot/share/gc/g1/g1StringDedupThread.cpp src/hotspot/share/gc/g1/g1StringDedupThread.hpp src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp src/hotspot/share/gc/shared/stringdedup/stringDedup.inline.hpp src/hotspot/share/gc/shared/stringdedup/stringDedupQueue.cpp src/hotspot/share/gc/shared/stringdedup/stringDedupQueue.hpp src/hotspot/share/gc/shared/stringdedup/stringDedupQueue.inline.hpp src/hotspot/share/gc/shared/stringdedup/stringDedupStat.cpp src/hotspot/share/gc/shared/stringdedup/stringDedupStat.hpp src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp src/hotspot/share/gc/shared/stringdedup/stringDedupTable.hpp src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp src/hotspot/share/gc/shared/stringdedup/stringDedupThread.hpp src/hotspot/share/gc/shared/stringdedup/stringDedupThread.inline.hpp
diffstat 23 files changed, 2087 insertions(+), 1561 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/gc/g1/g1StringDedup.cpp	Thu Jun 14 15:27:49 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedup.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -29,26 +29,16 @@
 #include "gc/g1/g1StringDedup.hpp"
 #include "gc/g1/g1StringDedupQueue.hpp"
 #include "gc/g1/g1StringDedupStat.hpp"
-#include "gc/g1/g1StringDedupTable.hpp"
-#include "gc/g1/g1StringDedupThread.hpp"
+#include "gc/shared/stringdedup/stringDedup.inline.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
+#include "gc/shared/stringdedup/stringDedupTable.hpp"
+#include "gc/shared/stringdedup/stringDedupThread.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/atomic.hpp"
 
-bool G1StringDedup::_enabled = false;
-
 void G1StringDedup::initialize() {
-  assert(UseG1GC, "String deduplication only available with G1");
-  if (UseStringDeduplication) {
-    _enabled = true;
-    G1StringDedupQueue::create();
-    G1StringDedupTable::create();
-    G1StringDedupThread::create();
-  }
-}
-
-void G1StringDedup::stop() {
-  assert(is_enabled(), "String deduplication not enabled");
-  G1StringDedupThread::thread()->stop();
+  assert(UseG1GC, "String deduplication available with G1");
+  StringDedup::initialize_impl<G1StringDedupQueue, G1StringDedupStat>();
 }
 
 bool G1StringDedup::is_candidate_from_mark(oop obj) {
@@ -99,12 +89,6 @@
   }
 }
 
-void G1StringDedup::deduplicate(oop java_string) {
-  assert(is_enabled(), "String deduplication not enabled");
-  G1StringDedupStat dummy; // Statistics from this path is never used
-  G1StringDedupTable::deduplicate(java_string, dummy);
-}
-
 void G1StringDedup::oops_do(OopClosure* keep_alive) {
   assert(is_enabled(), "String deduplication not enabled");
   unlink_or_oops_do(NULL, keep_alive, true /* allow_resize_and_rehash */);
@@ -112,8 +96,8 @@
 
 void G1StringDedup::parallel_unlink(G1StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id) {
   assert(is_enabled(), "String deduplication not enabled");
-  G1StringDedupQueue::unlink_or_oops_do(unlink);
-  G1StringDedupTable::unlink_or_oops_do(unlink, worker_id);
+  StringDedupQueue::unlink_or_oops_do(unlink);
+  StringDedupTable::unlink_or_oops_do(unlink, worker_id);
 }
 
 //
@@ -136,11 +120,11 @@
   virtual void work(uint worker_id) {
     {
       G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupQueueFixup, worker_id);
-      G1StringDedupQueue::unlink_or_oops_do(&_cl);
+      StringDedupQueue::unlink_or_oops_do(&_cl);
     }
     {
       G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupTableFixup, worker_id);
-      G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id);
+      StringDedupTable::unlink_or_oops_do(&_cl, worker_id);
     }
   }
 };
@@ -155,61 +139,3 @@
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
   g1h->workers()->run_task(&task);
 }
-
-void G1StringDedup::threads_do(ThreadClosure* tc) {
-  assert(is_enabled(), "String deduplication not enabled");
-  tc->do_thread(G1StringDedupThread::thread());
-}
-
-void G1StringDedup::print_worker_threads_on(outputStream* st) {
-  assert(is_enabled(), "String deduplication not enabled");
-  G1StringDedupThread::thread()->print_on(st);
-  st->cr();
-}
-
-void G1StringDedup::verify() {
-  assert(is_enabled(), "String deduplication not enabled");
-  G1StringDedupQueue::verify();
-  G1StringDedupTable::verify();
-}
-
-G1StringDedupUnlinkOrOopsDoClosure::G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
-                                                                       OopClosure* keep_alive,
-                                                                       bool allow_resize_and_rehash) :
-  _is_alive(is_alive),
-  _keep_alive(keep_alive),
-  _resized_table(NULL),
-  _rehashed_table(NULL),
-  _next_queue(0),
-  _next_bucket(0) {
-  if (allow_resize_and_rehash) {
-    // If both resize and rehash is needed, only do resize. Rehash of
-    // the table will eventually happen if the situation persists.
-    _resized_table = G1StringDedupTable::prepare_resize();
-    if (!is_resizing()) {
-      _rehashed_table = G1StringDedupTable::prepare_rehash();
-    }
-  }
-}
-
-G1StringDedupUnlinkOrOopsDoClosure::~G1StringDedupUnlinkOrOopsDoClosure() {
-  assert(!is_resizing() || !is_rehashing(), "Can not both resize and rehash");
-  if (is_resizing()) {
-    G1StringDedupTable::finish_resize(_resized_table);
-  } else if (is_rehashing()) {
-    G1StringDedupTable::finish_rehash(_rehashed_table);
-  }
-}
-
-// Atomically claims the next available queue for exclusive access by
-// the current thread. Returns the queue number of the claimed queue.
-size_t G1StringDedupUnlinkOrOopsDoClosure::claim_queue() {
-  return Atomic::add((size_t)1, &_next_queue) - 1;
-}
-
-// Atomically claims the next available table partition for exclusive
-// access by the current thread. Returns the table bucket number where
-// the claimed partition starts.
-size_t G1StringDedupUnlinkOrOopsDoClosure::claim_table_partition(size_t partition_size) {
-  return Atomic::add(partition_size, &_next_bucket) - partition_size;
-}
--- a/src/hotspot/share/gc/g1/g1StringDedup.hpp	Thu Jun 14 15:27:49 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedup.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,30 +26,7 @@
 #define SHARE_VM_GC_G1_G1STRINGDEDUP_HPP
 
 //
-// String Deduplication
-//
-// String deduplication aims to reduce the heap live-set by deduplicating identical
-// instances of String so that they share the same backing character array.
-//
-// The deduplication process is divided in two main parts, 1) finding the objects to
-// deduplicate, and 2) deduplicating those objects. The first part is done as part of
-// a normal GC cycle when objects are marked or evacuated. At this time a check is
-// applied on each object to check if it is a candidate for deduplication. If so, the
-// object is placed on the deduplication queue for later processing. The second part,
-// processing the objects on the deduplication queue, is a concurrent phase which
-// starts right after the stop-the-wold marking/evacuation phase. This phase is
-// executed by the deduplication thread, which pulls deduplication candidates of the
-// deduplication queue and tries to deduplicate them.
-//
-// A deduplication hashtable is used to keep track of all unique character arrays
-// used by String objects. When deduplicating, a lookup is made in this table to see
-// if there is already an identical character array somewhere on the heap. If so, the
-// String object is adjusted to point to that character array, releasing the reference
-// to the original array allowing it to eventually be garbage collected. If the lookup
-// fails the character array is instead inserted into the hashtable so that this array
-// can be shared at some point in the future.
-//
-// Candidate selection
+// G1 string deduplication candidate selection
 //
 // An object is considered a deduplication candidate if all of the following
 // statements are true:
@@ -70,36 +47,21 @@
 // than the deduplication age threshold, is will never become a candidate again.
 // This approach avoids making the same object a candidate more than once.
 //
-// Interned strings are a bit special. They are explicitly deduplicated just before
-// being inserted into the StringTable (to avoid counteracting C2 optimizations done
-// on string literals), then they also become deduplication candidates if they reach
-// the deduplication age threshold or are evacuated to an old heap region. The second
-// attempt to deduplicate such strings will be in vain, but we have no fast way of
-// filtering them out. This has not shown to be a problem, as the number of interned
-// strings is usually dwarfed by the number of normal (non-interned) strings.
-//
-// For additional information on string deduplication, please see JEP 192,
-// http://openjdk.java.net/jeps/192
-//
 
+#include "gc/shared/stringdedup/stringDedup.hpp"
 #include "memory/allocation.hpp"
 #include "oops/oop.hpp"
 
 class OopClosure;
 class BoolObjectClosure;
-class ThreadClosure;
-class outputStream;
-class G1StringDedupTable;
+class G1GCPhaseTimes;
 class G1StringDedupUnlinkOrOopsDoClosure;
-class G1GCPhaseTimes;
 
 //
-// Main interface for interacting with string deduplication.
+// G1 interface for interacting with string deduplication.
 //
-class G1StringDedup : public AllStatic {
+class G1StringDedup : public StringDedup {
 private:
-  // Single state for checking if both G1 and string deduplication is enabled.
-  static bool _enabled;
 
   // Candidate selection policies, returns true if the given object is
   // candidate for string deduplication.
@@ -107,21 +69,9 @@
   static bool is_candidate_from_evacuation(bool from_young, bool to_young, oop obj);
 
 public:
-  // Returns true if both G1 and string deduplication is enabled.
-  static bool is_enabled() {
-    return _enabled;
-  }
-
   // Initialize string deduplication.
   static void initialize();
 
-  // Stop the deduplication thread.
-  static void stop();
-
-  // Immediately deduplicates the given String object, bypassing the
-  // the deduplication queue.
-  static void deduplicate(oop java_string);
-
   // Enqueues a deduplication candidate for later processing by the deduplication
   // thread. Before enqueuing, these functions apply the appropriate candidate
   // selection policy to filters out non-candidates.
@@ -133,70 +83,28 @@
   static void parallel_unlink(G1StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id);
   static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive,
                                 bool allow_resize_and_rehash, G1GCPhaseTimes* phase_times = NULL);
-
-  static void threads_do(ThreadClosure* tc);
-  static void print_worker_threads_on(outputStream* st);
-  static void verify();
 };
 
 //
 // This closure encapsulates the state and the closures needed when scanning
 // the deduplication queue and table during the unlink_or_oops_do() operation.
 // A single instance of this closure is created and then shared by all worker
-// threads participating in the scan. The _next_queue and _next_bucket fields
-// provide a simple mechanism for GC workers to claim exclusive access to a
-// queue or a table partition.
+// threads participating in the scan.
 //
-class G1StringDedupUnlinkOrOopsDoClosure : public StackObj {
-private:
-  BoolObjectClosure*  _is_alive;
-  OopClosure*         _keep_alive;
-  G1StringDedupTable* _resized_table;
-  G1StringDedupTable* _rehashed_table;
-  size_t              _next_queue;
-  size_t              _next_bucket;
-
+class G1StringDedupUnlinkOrOopsDoClosure : public StringDedupUnlinkOrOopsDoClosure {
 public:
   G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
                                      OopClosure* keep_alive,
-                                     bool allow_resize_and_rehash);
-  ~G1StringDedupUnlinkOrOopsDoClosure();
+                                     bool allow_resize_and_rehash) :
+    StringDedupUnlinkOrOopsDoClosure(is_alive, keep_alive) {
+      if (G1StringDedup::is_enabled()) {
+        G1StringDedup::gc_prologue(allow_resize_and_rehash);
+      }
+    }
 
-  bool is_resizing() {
-    return _resized_table != NULL;
-  }
-
-  G1StringDedupTable* resized_table() {
-    return _resized_table;
-  }
-
-  bool is_rehashing() {
-    return _rehashed_table != NULL;
-  }
-
-  // Atomically claims the next available queue for exclusive access by
-  // the current thread. Returns the queue number of the claimed queue.
-  size_t claim_queue();
-
-  // Atomically claims the next available table partition for exclusive
-  // access by the current thread. Returns the table bucket number where
-  // the claimed partition starts.
-  size_t claim_table_partition(size_t partition_size);
-
-  // Applies and returns the result from the is_alive closure, or
-  // returns true if no such closure was provided.
-  bool is_alive(oop o) {
-    if (_is_alive != NULL) {
-      return _is_alive->do_object_b(o);
-    }
-    return true;
-  }
-
-  // Applies the keep_alive closure, or does nothing if no such
-  // closure was provided.
-  void keep_alive(oop* p) {
-    if (_keep_alive != NULL) {
-      _keep_alive->do_oop(p);
+  ~G1StringDedupUnlinkOrOopsDoClosure() {
+    if (G1StringDedup::is_enabled()) {
+      G1StringDedup::gc_epilogue();
     }
   }
 };
--- a/src/hotspot/share/gc/g1/g1StringDedupQueue.cpp	Thu Jun 14 15:27:49 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedupQueue.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@
 #include "runtime/safepointVerifiers.hpp"
 #include "utilities/stack.inline.hpp"
 
-G1StringDedupQueue* G1StringDedupQueue::_queue = NULL;
 const size_t        G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue
 const size_t        G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue
 
@@ -54,54 +53,49 @@
   ShouldNotReachHere();
 }
 
-void G1StringDedupQueue::create() {
-  assert(_queue == NULL, "One string deduplication queue allowed");
-  _queue = new G1StringDedupQueue();
-}
-
-void G1StringDedupQueue::wait() {
+void G1StringDedupQueue::wait_impl() {
   MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
-  while (_queue->_empty && !_queue->_cancel) {
+  while (_empty && !_cancel) {
     ml.wait(Mutex::_no_safepoint_check_flag);
   }
 }
 
-void G1StringDedupQueue::cancel_wait() {
+void G1StringDedupQueue::cancel_wait_impl() {
   MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
-  _queue->_cancel = true;
+  _cancel = true;
   ml.notify();
 }
 
-void G1StringDedupQueue::push(uint worker_id, oop java_string) {
+void G1StringDedupQueue::push_impl(uint worker_id, oop java_string) {
   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");
-  assert(worker_id < _queue->_nqueues, "Invalid queue");
+  assert(worker_id < _nqueues, "Invalid queue");
 
   // Push and notify waiter
-  G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id];
+  G1StringDedupWorkerQueue& worker_queue = _queues[worker_id];
   if (!worker_queue.is_full()) {
     worker_queue.push(java_string);
-    if (_queue->_empty) {
+    if (_empty) {
       MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
-      if (_queue->_empty) {
+      if (_empty) {
         // Mark non-empty and notify waiter
-        _queue->_empty = false;
+        _empty = false;
         ml.notify();
       }
     }
   } else {
     // Queue is full, drop the string and update the statistics
-    Atomic::inc(&_queue->_dropped);
+    Atomic::inc(&_dropped);
   }
 }
 
-oop G1StringDedupQueue::pop() {
+oop G1StringDedupQueue::pop_impl() {
   assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint");
   NoSafepointVerifier nsv;
 
   // Try all queues before giving up
-  for (size_t tries = 0; tries < _queue->_nqueues; tries++) {
+  for (size_t tries = 0; tries < _nqueues; tries++) {
     // The cursor indicates where we left of last time
-    G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor];
+    G1StringDedupWorkerQueue* queue = &_queues[_cursor];
     while (!queue->is_empty()) {
       oop obj = queue->pop();
       // The oop we pop can be NULL if it was marked
@@ -112,34 +106,18 @@
     }
 
     // Try next queue
-    _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues;
+    _cursor = (_cursor + 1) % _nqueues;
   }
 
   // Mark empty
-  _queue->_empty = true;
+  _empty = true;
 
   return NULL;
 }
 
-void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) {
-  // A worker thread first claims a queue, which ensures exclusive
-  // access to that queue, then continues to process it.
-  for (;;) {
-    // Grab next queue to scan
-    size_t queue = cl->claim_queue();
-    if (queue >= _queue->_nqueues) {
-      // End of queues
-      break;
-    }
-
-    // Scan the queue
-    unlink_or_oops_do(cl, queue);
-  }
-}
-
-void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) {
-  assert(queue < _queue->_nqueues, "Invalid queue");
-  StackIterator<oop, mtGC> iter(_queue->_queues[queue]);
+void G1StringDedupQueue::unlink_or_oops_do_impl(StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) {
+  assert(queue < _nqueues, "Invalid queue");
+  StackIterator<oop, mtGC> iter(_queues[queue]);
   while (!iter.is_empty()) {
     oop* p = iter.next_addr();
     if (*p != NULL) {
@@ -153,14 +131,14 @@
   }
 }
 
-void G1StringDedupQueue::print_statistics() {
+void G1StringDedupQueue::print_statistics_impl() {
   log_debug(gc, stringdedup)("  Queue");
-  log_debug(gc, stringdedup)("    Dropped: " UINTX_FORMAT, _queue->_dropped);
+  log_debug(gc, stringdedup)("    Dropped: " UINTX_FORMAT, _dropped);
 }
 
-void G1StringDedupQueue::verify() {
-  for (size_t i = 0; i < _queue->_nqueues; i++) {
-    StackIterator<oop, mtGC> iter(_queue->_queues[i]);
+void G1StringDedupQueue::verify_impl() {
+  for (size_t i = 0; i < _nqueues; i++) {
+    StackIterator<oop, mtGC> iter(_queues[i]);
     while (!iter.is_empty()) {
       oop obj = iter.next();
       if (obj != NULL) {
--- a/src/hotspot/share/gc/g1/g1StringDedupQueue.hpp	Thu Jun 14 15:27:49 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedupQueue.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,40 +25,21 @@
 #ifndef SHARE_VM_GC_G1_G1STRINGDEDUPQUEUE_HPP
 #define SHARE_VM_GC_G1_G1STRINGDEDUPQUEUE_HPP
 
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
 #include "memory/allocation.hpp"
 #include "oops/oop.hpp"
 #include "utilities/stack.hpp"
 
-class G1StringDedupUnlinkOrOopsDoClosure;
+class StringDedupUnlinkOrOopsDoClosure;
 
 //
-// The deduplication queue acts as the communication channel between the stop-the-world
-// mark/evacuation phase and the concurrent deduplication phase. Deduplication candidates
-// found during mark/evacuation are placed on this queue for later processing in the
-// deduplication thread. A queue entry is an oop pointing to a String object (as opposed
-// to entries in the deduplication hashtable which points to character arrays).
+// G1 enqueues candidates during the stop-the-world mark/evacuation phase.
 //
-// While users of the queue treat it as a single queue, it is implemented as a set of
-// queues, one queue per GC worker thread, to allow lock-free and cache-friendly enqueue
-// operations by the GC workers.
-//
-// The oops in the queue are treated as weak pointers, meaning the objects they point to
-// can become unreachable and pruned (cleared) before being popped by the deduplication
-// thread.
-//
-// Pushing to the queue is thread safe (this relies on each thread using a unique worker
-// id), but only allowed during a safepoint. Popping from the queue is NOT thread safe
-// and can only be done by the deduplication thread outside a safepoint.
-//
-// The StringDedupQueue_lock is only used for blocking and waking up the deduplication
-// thread in case the queue is empty or becomes non-empty, respectively. This lock does
-// not otherwise protect the queue content.
-//
-class G1StringDedupQueue : public CHeapObj<mtGC> {
+
+class G1StringDedupQueue : public StringDedupQueue {
 private:
   typedef Stack<oop, mtGC> G1StringDedupWorkerQueue;
 
-  static G1StringDedupQueue* _queue;
   static const size_t        _max_size;
   static const size_t        _max_cache_size;
 
@@ -71,31 +52,36 @@
   // Statistics counter, only used for logging.
   uintx                      _dropped;
 
-  G1StringDedupQueue();
   ~G1StringDedupQueue();
 
-  static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue);
+  void unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl, size_t queue);
 
 public:
-  static void create();
+  G1StringDedupQueue();
+
+protected:
 
   // Blocks and waits for the queue to become non-empty.
-  static void wait();
+  void wait_impl();
 
   // Wakes up any thread blocked waiting for the queue to become non-empty.
-  static void cancel_wait();
+  void cancel_wait_impl();
 
   // Pushes a deduplication candidate onto a specific GC worker queue.
-  static void push(uint worker_id, oop java_string);
+  void push_impl(uint worker_id, oop java_string);
 
   // Pops a deduplication candidate from any queue, returns NULL if
   // all queues are empty.
-  static oop pop();
+  oop pop_impl();
 
-  static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl);
+  size_t num_queues() const {
+    return _nqueues;
+  }
 
-  static void print_statistics();
-  static void verify();
+  void unlink_or_oops_do_impl(StringDedupUnlinkOrOopsDoClosure* cl, size_t queue);
+
+  void print_statistics_impl();
+  void verify_impl();
 };
 
 #endif // SHARE_VM_GC_G1_G1STRINGDEDUPQUEUE_HPP
--- a/src/hotspot/share/gc/g1/g1StringDedupStat.cpp	Thu Jun 14 15:27:49 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedupStat.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,121 +23,60 @@
  */
 
 #include "precompiled.hpp"
+
+#include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1StringDedupStat.hpp"
 #include "logging/log.hpp"
 
-G1StringDedupStat::G1StringDedupStat() :
-  _inspected(0),
-  _skipped(0),
-  _hashed(0),
-  _known(0),
-  _new(0),
-  _new_bytes(0),
-  _deduped(0),
-  _deduped_bytes(0),
+G1StringDedupStat::G1StringDedupStat() : StringDedupStat(),
   _deduped_young(0),
   _deduped_young_bytes(0),
   _deduped_old(0),
   _deduped_old_bytes(0),
-  _idle(0),
-  _exec(0),
-  _block(0),
-  _start_concurrent(0.0),
-  _end_concurrent(0.0),
-  _start_phase(0.0),
-  _idle_elapsed(0.0),
-  _exec_elapsed(0.0),
-  _block_elapsed(0.0) {
+  _heap(G1CollectedHeap::heap()) {
 }
 
-void G1StringDedupStat::add(const G1StringDedupStat& stat) {
-  _inspected           += stat._inspected;
-  _skipped             += stat._skipped;
-  _hashed              += stat._hashed;
-  _known               += stat._known;
-  _new                 += stat._new;
-  _new_bytes           += stat._new_bytes;
-  _deduped             += stat._deduped;
-  _deduped_bytes       += stat._deduped_bytes;
-  _deduped_young       += stat._deduped_young;
-  _deduped_young_bytes += stat._deduped_young_bytes;
-  _deduped_old         += stat._deduped_old;
-  _deduped_old_bytes   += stat._deduped_old_bytes;
-  _idle                += stat._idle;
-  _exec                += stat._exec;
-  _block               += stat._block;
-  _idle_elapsed        += stat._idle_elapsed;
-  _exec_elapsed        += stat._exec_elapsed;
-  _block_elapsed       += stat._block_elapsed;
+
+
+void G1StringDedupStat::deduped(oop obj, uintx bytes) {
+  StringDedupStat::deduped(obj, bytes);
+  if (_heap->is_in_young(obj)) {
+    _deduped_young ++;
+    _deduped_young_bytes += bytes;
+  } else {
+    _deduped_old ++;
+    _deduped_old_bytes += bytes;
+  }
 }
 
-void G1StringDedupStat::print_start(const G1StringDedupStat& last_stat) {
-  log_info(gc, stringdedup)(
-     "Concurrent String Deduplication (" G1_STRDEDUP_TIME_FORMAT ")",
-     G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent));
+void G1StringDedupStat::add(const StringDedupStat* const stat) {
+  StringDedupStat::add(stat);
+  const G1StringDedupStat* const g1_stat = (const G1StringDedupStat* const)stat;
+  _deduped_young += g1_stat->_deduped_young;
+  _deduped_young_bytes += g1_stat->_deduped_young_bytes;
+  _deduped_old += g1_stat->_deduped_old;
+  _deduped_old_bytes += g1_stat->_deduped_old_bytes;
 }
 
-void G1StringDedupStat::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
-  double total_deduped_bytes_percent = 0.0;
+void G1StringDedupStat::print_statistics(bool total) const {
+  StringDedupStat::print_statistics(total);
 
-  if (total_stat._new_bytes > 0) {
-    // Avoid division by zero
-    total_deduped_bytes_percent = percent_of(total_stat._deduped_bytes, total_stat._new_bytes);
-  }
+  double deduped_young_percent       = percent_of(_deduped_young, _deduped);
+  double deduped_young_bytes_percent = percent_of(_deduped_young_bytes, _deduped_bytes);
+  double deduped_old_percent         = percent_of(_deduped_old, _deduped);
+  double deduped_old_bytes_percent   = percent_of(_deduped_old_bytes, _deduped_bytes);
 
-  log_info(gc, stringdedup)(
-    "Concurrent String Deduplication "
-    G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS ") "
-    "avg " G1_STRDEDUP_PERCENT_FORMAT_NS " "
-    "(" G1_STRDEDUP_TIME_FORMAT ", " G1_STRDEDUP_TIME_FORMAT ") " G1_STRDEDUP_TIME_FORMAT_MS,
-    G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes),
-    G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes),
-    G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes),
-    total_deduped_bytes_percent,
-    G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent),
-    G1_STRDEDUP_TIME_PARAM(last_stat._end_concurrent),
-    G1_STRDEDUP_TIME_PARAM_MS(last_stat._exec_elapsed));
+  log_debug(gc, stringdedup)("      Young:      " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ") " STRDEDUP_BYTES_FORMAT "(" STRDEDUP_PERCENT_FORMAT ")",
+                             _deduped_young, deduped_young_percent, STRDEDUP_BYTES_PARAM(_deduped_young_bytes), deduped_young_bytes_percent);
+  log_debug(gc, stringdedup)("      Old:        " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ") " STRDEDUP_BYTES_FORMAT "(" STRDEDUP_PERCENT_FORMAT ")",
+                             _deduped_old, deduped_old_percent, STRDEDUP_BYTES_PARAM(_deduped_old_bytes), deduped_old_bytes_percent);
+
 }
 
-void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) {
-  double skipped_percent             = percent_of(stat._skipped, stat._inspected);
-  double hashed_percent              = percent_of(stat._hashed, stat._inspected);
-  double known_percent               = percent_of(stat._known, stat._inspected);
-  double new_percent                 = percent_of(stat._new, stat._inspected);
-  double deduped_percent             = percent_of(stat._deduped, stat._new);
-  double deduped_bytes_percent       = percent_of(stat._deduped_bytes, stat._new_bytes);
-  double deduped_young_percent       = percent_of(stat._deduped_young, stat._deduped);
-  double deduped_young_bytes_percent = percent_of(stat._deduped_young_bytes, stat._deduped_bytes);
-  double deduped_old_percent         = percent_of(stat._deduped_old, stat._deduped);
-  double deduped_old_bytes_percent   = percent_of(stat._deduped_old_bytes, stat._deduped_bytes);
-
-  if (total) {
-    log_debug(gc, stringdedup)(
-      "  Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
-      ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
-      ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
-      stat._exec, G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
-      stat._idle, G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
-      stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
-  } else {
-    log_debug(gc, stringdedup)(
-      "  Last Exec: " G1_STRDEDUP_TIME_FORMAT_MS
-      ", Idle: " G1_STRDEDUP_TIME_FORMAT_MS
-      ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
-      G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
-      G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
-      stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
-  }
-  log_debug(gc, stringdedup)("    Inspected:    " G1_STRDEDUP_OBJECTS_FORMAT, stat._inspected);
-  log_debug(gc, stringdedup)("      Skipped:    " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._skipped, skipped_percent);
-  log_debug(gc, stringdedup)("      Hashed:     " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._hashed, hashed_percent);
-  log_debug(gc, stringdedup)("      Known:      " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._known, known_percent);
-  log_debug(gc, stringdedup)("      New:        " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT,
-                             stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes));
-  log_debug(gc, stringdedup)("    Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
-                             stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent);
-  log_debug(gc, stringdedup)("      Young:      " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
-                             stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent);
-  log_debug(gc, stringdedup)("      Old:        " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
-                             stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent);
+void G1StringDedupStat::reset() {
+  StringDedupStat::reset();
+  _deduped_young = 0;
+  _deduped_young_bytes = 0;
+  _deduped_old = 0;
+  _deduped_old_bytes = 0;
 }
--- a/src/hotspot/share/gc/g1/g1StringDedupStat.hpp	Thu Jun 14 15:27:49 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedupStat.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,126 +25,28 @@
 #ifndef SHARE_VM_GC_G1_G1STRINGDEDUPSTAT_HPP
 #define SHARE_VM_GC_G1_G1STRINGDEDUPSTAT_HPP
 
-#include "memory/allocation.hpp"
-#include "runtime/os.hpp"
+#include "gc/shared/stringdedup/stringDedupStat.hpp"
 
-// Macros for GC log output formating
-#define G1_STRDEDUP_OBJECTS_FORMAT         UINTX_FORMAT_W(12)
-#define G1_STRDEDUP_TIME_FORMAT            "%.3fs"
-#define G1_STRDEDUP_TIME_PARAM(time)       (time)
-#define G1_STRDEDUP_TIME_FORMAT_MS         "%.3fms"
-#define G1_STRDEDUP_TIME_PARAM_MS(time)    ((time) * MILLIUNITS)
-#define G1_STRDEDUP_PERCENT_FORMAT         "%5.1f%%"
-#define G1_STRDEDUP_PERCENT_FORMAT_NS      "%.1f%%"
-#define G1_STRDEDUP_BYTES_FORMAT           "%8.1f%s"
-#define G1_STRDEDUP_BYTES_FORMAT_NS        "%.1f%s"
-#define G1_STRDEDUP_BYTES_PARAM(bytes)     byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes))
-
-//
-// Statistics gathered by the deduplication thread.
-//
-class G1StringDedupStat : public StackObj {
+// G1 extension for gathering/reporting generational statistics
+class G1StringDedupStat : public StringDedupStat {
 private:
-  // Counters
-  uintx  _inspected;
-  uintx  _skipped;
-  uintx  _hashed;
-  uintx  _known;
-  uintx  _new;
-  uintx  _new_bytes;
-  uintx  _deduped;
-  uintx  _deduped_bytes;
   uintx  _deduped_young;
   uintx  _deduped_young_bytes;
   uintx  _deduped_old;
   uintx  _deduped_old_bytes;
-  uintx  _idle;
-  uintx  _exec;
-  uintx  _block;
 
-  // Time spent by the deduplication thread in different phases
-  double _start_concurrent;
-  double _end_concurrent;
-  double _start_phase;
-  double _idle_elapsed;
-  double _exec_elapsed;
-  double _block_elapsed;
+  G1CollectedHeap* const _heap;
 
 public:
   G1StringDedupStat();
 
-  void inc_inspected() {
-    _inspected++;
-  }
+  void deduped(oop obj, uintx bytes);
 
-  void inc_skipped() {
-    _skipped++;
-  }
+  void add(const StringDedupStat* const stat);
 
-  void inc_hashed() {
-    _hashed++;
-  }
+  void print_statistics(bool total) const;
 
-  void inc_known() {
-    _known++;
-  }
-
-  void inc_new(uintx bytes) {
-    _new++;
-    _new_bytes += bytes;
-  }
-
-  void inc_deduped_young(uintx bytes) {
-    _deduped++;
-    _deduped_bytes += bytes;
-    _deduped_young++;
-    _deduped_young_bytes += bytes;
-  }
-
-  void inc_deduped_old(uintx bytes) {
-    _deduped++;
-    _deduped_bytes += bytes;
-    _deduped_old++;
-    _deduped_old_bytes += bytes;
-  }
-
-  void mark_idle() {
-    _start_phase = os::elapsedTime();
-    _idle++;
-  }
-
-  void mark_exec() {
-    double now = os::elapsedTime();
-    _idle_elapsed = now - _start_phase;
-    _start_phase = now;
-    _start_concurrent = now;
-    _exec++;
-  }
-
-  void mark_block() {
-    double now = os::elapsedTime();
-    _exec_elapsed += now - _start_phase;
-    _start_phase = now;
-    _block++;
-  }
-
-  void mark_unblock() {
-    double now = os::elapsedTime();
-    _block_elapsed += now - _start_phase;
-    _start_phase = now;
-  }
-
-  void mark_done() {
-    double now = os::elapsedTime();
-    _exec_elapsed += now - _start_phase;
-    _end_concurrent = now;
-  }
-
-  void add(const G1StringDedupStat& stat);
-
-  static void print_start(const G1StringDedupStat& last_stat);
-  static void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
-  static void print_statistics(const G1StringDedupStat& stat, bool total);
+  void reset();
 };
 
 #endif // SHARE_VM_GC_G1_G1STRINGDEDUPSTAT_HPP
--- a/src/hotspot/share/gc/g1/g1StringDedupTable.cpp	Thu Jun 14 15:27:49 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,625 +0,0 @@
-/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "classfile/altHashing.hpp"
-#include "classfile/javaClasses.inline.hpp"
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1StringDedup.hpp"
-#include "gc/g1/g1StringDedupTable.hpp"
-#include "logging/log.hpp"
-#include "memory/padded.inline.hpp"
-#include "oops/arrayOop.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "oops/typeArrayOop.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/safepointVerifiers.hpp"
-
-//
-// List of deduplication table entries. Links table
-// entries together using their _next fields.
-//
-class G1StringDedupEntryList : public CHeapObj<mtGC> {
-private:
-  G1StringDedupEntry* _list;
-  size_t              _length;
-
-public:
-  G1StringDedupEntryList() :
-    _list(NULL),
-    _length(0) {
-  }
-
-  void add(G1StringDedupEntry* entry) {
-    entry->set_next(_list);
-    _list = entry;
-    _length++;
-  }
-
-  G1StringDedupEntry* remove() {
-    G1StringDedupEntry* entry = _list;
-    if (entry != NULL) {
-      _list = entry->next();
-      _length--;
-    }
-    return entry;
-  }
-
-  G1StringDedupEntry* remove_all() {
-    G1StringDedupEntry* list = _list;
-    _list = NULL;
-    return list;
-  }
-
-  size_t length() {
-    return _length;
-  }
-};
-
-//
-// Cache of deduplication table entries. This cache provides fast allocation and
-// reuse of table entries to lower the pressure on the underlying allocator.
-// But more importantly, it provides fast/deferred freeing of table entries. This
-// is important because freeing of table entries is done during stop-the-world
-// phases and it is not uncommon for large number of entries to be freed at once.
-// Tables entries that are freed during these phases are placed onto a freelist in
-// the cache. The deduplication thread, which executes in a concurrent phase, will
-// later reuse or free the underlying memory for these entries.
-//
-// The cache allows for single-threaded allocations and multi-threaded frees.
-// Allocations are synchronized by StringDedupTable_lock as part of a table
-// modification.
-//
-class G1StringDedupEntryCache : public CHeapObj<mtGC> {
-private:
-  // One cache/overflow list per GC worker to allow lock less freeing of
-  // entries while doing a parallel scan of the table. Using PaddedEnd to
-  // avoid false sharing.
-  size_t                             _nlists;
-  size_t                             _max_list_length;
-  PaddedEnd<G1StringDedupEntryList>* _cached;
-  PaddedEnd<G1StringDedupEntryList>* _overflowed;
-
-public:
-  G1StringDedupEntryCache(size_t max_size);
-  ~G1StringDedupEntryCache();
-
-  // Set max number of table entries to cache.
-  void set_max_size(size_t max_size);
-
-  // Get a table entry from the cache, or allocate a new entry if the cache is empty.
-  G1StringDedupEntry* alloc();
-
-  // Insert a table entry into the cache.
-  void free(G1StringDedupEntry* entry, uint worker_id);
-
-  // Returns current number of entries in the cache.
-  size_t size();
-
-  // Deletes overflowed entries.
-  void delete_overflowed();
-};
-
-G1StringDedupEntryCache::G1StringDedupEntryCache(size_t max_size) :
-  _nlists(ParallelGCThreads),
-  _max_list_length(0),
-  _cached(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)),
-  _overflowed(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)) {
-  set_max_size(max_size);
-}
-
-G1StringDedupEntryCache::~G1StringDedupEntryCache() {
-  ShouldNotReachHere();
-}
-
-void G1StringDedupEntryCache::set_max_size(size_t size) {
-  _max_list_length = size / _nlists;
-}
-
-G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
-  for (size_t i = 0; i < _nlists; i++) {
-    G1StringDedupEntry* entry = _cached[i].remove();
-    if (entry != NULL) {
-      return entry;
-    }
-  }
-  return new G1StringDedupEntry();
-}
-
-void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) {
-  assert(entry->obj() != NULL, "Double free");
-  assert(worker_id < _nlists, "Invalid worker id");
-
-  entry->set_obj(NULL);
-  entry->set_hash(0);
-
-  if (_cached[worker_id].length() < _max_list_length) {
-    // Cache is not full
-    _cached[worker_id].add(entry);
-  } else {
-    // Cache is full, add to overflow list for later deletion
-    _overflowed[worker_id].add(entry);
-  }
-}
-
-size_t G1StringDedupEntryCache::size() {
-  size_t size = 0;
-  for (size_t i = 0; i < _nlists; i++) {
-    size += _cached[i].length();
-  }
-  return size;
-}
-
-void G1StringDedupEntryCache::delete_overflowed() {
-  double start = os::elapsedTime();
-  uintx count = 0;
-
-  for (size_t i = 0; i < _nlists; i++) {
-    G1StringDedupEntry* entry;
-
-    {
-      // The overflow list can be modified during safepoints, therefore
-      // we temporarily join the suspendible thread set while removing
-      // all entries from the list.
-      SuspendibleThreadSetJoiner sts_join;
-      entry = _overflowed[i].remove_all();
-    }
-
-    // Delete all entries
-    while (entry != NULL) {
-      G1StringDedupEntry* next = entry->next();
-      delete entry;
-      entry = next;
-      count++;
-    }
-  }
-
-  double end = os::elapsedTime();
-  log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT_MS,
-                             count, G1_STRDEDUP_TIME_PARAM_MS(end - start));
-}
-
-G1StringDedupTable*      G1StringDedupTable::_table = NULL;
-G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL;
-
-const size_t             G1StringDedupTable::_min_size = (1 << 10);   // 1024
-const size_t             G1StringDedupTable::_max_size = (1 << 24);   // 16777216
-const double             G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load
-const double             G1StringDedupTable::_shrink_load_factor = _grow_load_factor / 3.0; // Shrink table at 67% load
-const double             G1StringDedupTable::_max_cache_factor = 0.1; // Cache a maximum of 10% of the table size
-const uintx              G1StringDedupTable::_rehash_multiple = 60;   // Hash bucket has 60 times more collisions than expected
-const uintx              G1StringDedupTable::_rehash_threshold = (uintx)(_rehash_multiple * _grow_load_factor);
-
-uintx                    G1StringDedupTable::_entries_added = 0;
-uintx                    G1StringDedupTable::_entries_removed = 0;
-uintx                    G1StringDedupTable::_resize_count = 0;
-uintx                    G1StringDedupTable::_rehash_count = 0;
-
-G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) :
-  _size(size),
-  _entries(0),
-  _grow_threshold((uintx)(size * _grow_load_factor)),
-  _shrink_threshold((uintx)(size * _shrink_load_factor)),
-  _rehash_needed(false),
-  _hash_seed(hash_seed) {
-  assert(is_power_of_2(size), "Table size must be a power of 2");
-  _buckets = NEW_C_HEAP_ARRAY(G1StringDedupEntry*, _size, mtGC);
-  memset(_buckets, 0, _size * sizeof(G1StringDedupEntry*));
-}
-
-G1StringDedupTable::~G1StringDedupTable() {
-  FREE_C_HEAP_ARRAY(G1StringDedupEntry*, _buckets);
-}
-
-void G1StringDedupTable::create() {
-  assert(_table == NULL, "One string deduplication table allowed");
-  _entry_cache = new G1StringDedupEntryCache(_min_size * _max_cache_factor);
-  _table = new G1StringDedupTable(_min_size);
-}
-
-void G1StringDedupTable::add(typeArrayOop value, bool latin1, unsigned int hash, G1StringDedupEntry** list) {
-  G1StringDedupEntry* entry = _entry_cache->alloc();
-  entry->set_obj(value);
-  entry->set_hash(hash);
-  entry->set_latin1(latin1);
-  entry->set_next(*list);
-  *list = entry;
-  _entries++;
-}
-
-void G1StringDedupTable::remove(G1StringDedupEntry** pentry, uint worker_id) {
-  G1StringDedupEntry* entry = *pentry;
-  *pentry = entry->next();
-  _entry_cache->free(entry, worker_id);
-}
-
-void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) {
-  G1StringDedupEntry* entry = *pentry;
-  *pentry = entry->next();
-  unsigned int hash = entry->hash();
-  size_t index = dest->hash_to_index(hash);
-  G1StringDedupEntry** list = dest->bucket(index);
-  entry->set_next(*list);
-  *list = entry;
-}
-
-bool G1StringDedupTable::equals(typeArrayOop value1, typeArrayOop value2) {
-  return (value1 == value2 ||
-          (value1->length() == value2->length() &&
-           (!memcmp(value1->base(T_BYTE),
-                    value2->base(T_BYTE),
-                    value1->length() * sizeof(jbyte)))));
-}
-
-typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, bool latin1, unsigned int hash,
-                                        G1StringDedupEntry** list, uintx &count) {
-  for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) {
-    if (entry->hash() == hash && entry->latin1() == latin1) {
-      typeArrayOop existing_value = entry->obj();
-      if (equals(value, existing_value)) {
-        // Match found
-        return existing_value;
-      }
-    }
-    count++;
-  }
-
-  // Not found
-  return NULL;
-}
-
-typeArrayOop G1StringDedupTable::lookup_or_add_inner(typeArrayOop value, bool latin1, unsigned int hash) {
-  size_t index = hash_to_index(hash);
-  G1StringDedupEntry** list = bucket(index);
-  uintx count = 0;
-
-  // Lookup in list
-  typeArrayOop existing_value = lookup(value, latin1, hash, list, count);
-
-  // Check if rehash is needed
-  if (count > _rehash_threshold) {
-    _rehash_needed = true;
-  }
-
-  if (existing_value == NULL) {
-    // Not found, add new entry
-    add(value, latin1, hash, list);
-
-    // Update statistics
-    _entries_added++;
-  }
-
-  return existing_value;
-}
-
-unsigned int G1StringDedupTable::hash_code(typeArrayOop value, bool latin1) {
-  unsigned int hash;
-  int length = value->length();
-  if (latin1) {
-    const jbyte* data = (jbyte*)value->base(T_BYTE);
-    if (use_java_hash()) {
-      hash = java_lang_String::hash_code(data, length);
-    } else {
-      hash = AltHashing::murmur3_32(_table->_hash_seed, data, length);
-    }
-  } else {
-    length /= sizeof(jchar) / sizeof(jbyte); // Convert number of bytes to number of chars
-    const jchar* data = (jchar*)value->base(T_CHAR);
-    if (use_java_hash()) {
-      hash = java_lang_String::hash_code(data, length);
-    } else {
-      hash = AltHashing::murmur3_32(_table->_hash_seed, data, length);
-    }
-  }
-
-  return hash;
-}
-
-void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) {
-  assert(java_lang_String::is_instance(java_string), "Must be a string");
-  NoSafepointVerifier nsv;
-
-  stat.inc_inspected();
-
-  typeArrayOop value = java_lang_String::value(java_string);
-  if (value == NULL) {
-    // String has no value
-    stat.inc_skipped();
-    return;
-  }
-
-  bool latin1 = java_lang_String::is_latin1(java_string);
-  unsigned int hash = 0;
-
-  if (use_java_hash()) {
-    // Get hash code from cache
-    hash = java_lang_String::hash(java_string);
-  }
-
-  if (hash == 0) {
-    // Compute hash
-    hash = hash_code(value, latin1);
-    stat.inc_hashed();
-
-    if (use_java_hash() && hash != 0) {
-      // Store hash code in cache
-      java_lang_String::set_hash(java_string, hash);
-    }
-  }
-
-  typeArrayOop existing_value = lookup_or_add(value, latin1, hash);
-  if (existing_value == value) {
-    // Same value, already known
-    stat.inc_known();
-    return;
-  }
-
-  // Get size of value array
-  uintx size_in_bytes = value->size() * HeapWordSize;
-  stat.inc_new(size_in_bytes);
-
-  if (existing_value != NULL) {
-    // Enqueue the reference to make sure it is kept alive. Concurrent mark might
-    // otherwise declare it dead if there are no other strong references to this object.
-    G1BarrierSet::enqueue(existing_value);
-
-    // Existing value found, deduplicate string
-    java_lang_String::set_value(java_string, existing_value);
-
-    if (G1CollectedHeap::heap()->is_in_young(value)) {
-      stat.inc_deduped_young(size_in_bytes);
-    } else {
-      stat.inc_deduped_old(size_in_bytes);
-    }
-  }
-}
-
-G1StringDedupTable* G1StringDedupTable::prepare_resize() {
-  size_t size = _table->_size;
-
-  // Check if the hashtable needs to be resized
-  if (_table->_entries > _table->_grow_threshold) {
-    // Grow table, double the size
-    size *= 2;
-    if (size > _max_size) {
-      // Too big, don't resize
-      return NULL;
-    }
-  } else if (_table->_entries < _table->_shrink_threshold) {
-    // Shrink table, half the size
-    size /= 2;
-    if (size < _min_size) {
-      // Too small, don't resize
-      return NULL;
-    }
-  } else if (StringDeduplicationResizeALot) {
-    // Force grow
-    size *= 2;
-    if (size > _max_size) {
-      // Too big, force shrink instead
-      size /= 4;
-    }
-  } else {
-    // Resize not needed
-    return NULL;
-  }
-
-  // Update statistics
-  _resize_count++;
-
-  // Update max cache size
-  _entry_cache->set_max_size(size * _max_cache_factor);
-
-  // Allocate the new table. The new table will be populated by workers
-  // calling unlink_or_oops_do() and finally installed by finish_resize().
-  return new G1StringDedupTable(size, _table->_hash_seed);
-}
-
-void G1StringDedupTable::finish_resize(G1StringDedupTable* resized_table) {
-  assert(resized_table != NULL, "Invalid table");
-
-  resized_table->_entries = _table->_entries;
-
-  // Free old table
-  delete _table;
-
-  // Install new table
-  _table = resized_table;
-}
-
-void G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id) {
-  // The table is divided into partitions to allow lock-less parallel processing by
-  // multiple worker threads. A worker thread first claims a partition, which ensures
-  // exclusive access to that part of the table, then continues to process it. To allow
-  // shrinking of the table in parallel we also need to make sure that the same worker
-  // thread processes all partitions where entries will hash to the same destination
-  // partition. Since the table size is always a power of two and we always shrink by
-  // dividing the table in half, we know that for a given partition there is only one
-  // other partition whoes entries will hash to the same destination partition. That
-  // other partition is always the sibling partition in the second half of the table.
-  // For example, if the table is divided into 8 partitions, the sibling of partition 0
-  // is partition 4, the sibling of partition 1 is partition 5, etc.
-  size_t table_half = _table->_size / 2;
-
-  // Let each partition be one page worth of buckets
-  size_t partition_size = MIN2(table_half, os::vm_page_size() / sizeof(G1StringDedupEntry*));
-  assert(table_half % partition_size == 0, "Invalid partition size");
-
-  // Number of entries removed during the scan
-  uintx removed = 0;
-
-  for (;;) {
-    // Grab next partition to scan
-    size_t partition_begin = cl->claim_table_partition(partition_size);
-    size_t partition_end = partition_begin + partition_size;
-    if (partition_begin >= table_half) {
-      // End of table
-      break;
-    }
-
-    // Scan the partition followed by the sibling partition in the second half of the table
-    removed += unlink_or_oops_do(cl, partition_begin, partition_end, worker_id);
-    removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id);
-  }
-
-  // Delayed update to avoid contention on the table lock
-  if (removed > 0) {
-    MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
-    _table->_entries -= removed;
-    _entries_removed += removed;
-  }
-}
-
-uintx G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl,
-                                            size_t partition_begin,
-                                            size_t partition_end,
-                                            uint worker_id) {
-  uintx removed = 0;
-  for (size_t bucket = partition_begin; bucket < partition_end; bucket++) {
-    G1StringDedupEntry** entry = _table->bucket(bucket);
-    while (*entry != NULL) {
-      oop* p = (oop*)(*entry)->obj_addr();
-      if (cl->is_alive(*p)) {
-        cl->keep_alive(p);
-        if (cl->is_resizing()) {
-          // We are resizing the table, transfer entry to the new table
-          _table->transfer(entry, cl->resized_table());
-        } else {
-          if (cl->is_rehashing()) {
-            // We are rehashing the table, rehash the entry but keep it
-            // in the table. We can't transfer entries into the new table
-            // at this point since we don't have exclusive access to all
-            // destination partitions. finish_rehash() will do a single
-            // threaded transfer of all entries.
-            typeArrayOop value = (typeArrayOop)*p;
-            bool latin1 = (*entry)->latin1();
-            unsigned int hash = hash_code(value, latin1);
-            (*entry)->set_hash(hash);
-          }
-
-          // Move to next entry
-          entry = (*entry)->next_addr();
-        }
-      } else {
-        // Not alive, remove entry from table
-        _table->remove(entry, worker_id);
-        removed++;
-      }
-    }
-  }
-
-  return removed;
-}
-
-G1StringDedupTable* G1StringDedupTable::prepare_rehash() {
-  if (!_table->_rehash_needed && !StringDeduplicationRehashALot) {
-    // Rehash not needed
-    return NULL;
-  }
-
-  // Update statistics
-  _rehash_count++;
-
-  // Compute new hash seed
-  _table->_hash_seed = AltHashing::compute_seed();
-
-  // Allocate the new table, same size and hash seed
-  return new G1StringDedupTable(_table->_size, _table->_hash_seed);
-}
-
-void G1StringDedupTable::finish_rehash(G1StringDedupTable* rehashed_table) {
-  assert(rehashed_table != NULL, "Invalid table");
-
-  // Move all newly rehashed entries into the correct buckets in the new table
-  for (size_t bucket = 0; bucket < _table->_size; bucket++) {
-    G1StringDedupEntry** entry = _table->bucket(bucket);
-    while (*entry != NULL) {
-      _table->transfer(entry, rehashed_table);
-    }
-  }
-
-  rehashed_table->_entries = _table->_entries;
-
-  // Free old table
-  delete _table;
-
-  // Install new table
-  _table = rehashed_table;
-}
-
-void G1StringDedupTable::verify() {
-  for (size_t bucket = 0; bucket < _table->_size; bucket++) {
-    // Verify entries
-    G1StringDedupEntry** entry = _table->bucket(bucket);
-    while (*entry != NULL) {
-      typeArrayOop value = (*entry)->obj();
-      guarantee(value != NULL, "Object must not be NULL");
-      guarantee(G1CollectedHeap::heap()->is_in_reserved(value), "Object must be on the heap");
-      guarantee(!value->is_forwarded(), "Object must not be forwarded");
-      guarantee(value->is_typeArray(), "Object must be a typeArrayOop");
-      bool latin1 = (*entry)->latin1();
-      unsigned int hash = hash_code(value, latin1);
-      guarantee((*entry)->hash() == hash, "Table entry has inorrect hash");
-      guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index");
-      entry = (*entry)->next_addr();
-    }
-
-    // Verify that we do not have entries with identical oops or identical arrays.
-    // We only need to compare entries in the same bucket. If the same oop or an
-    // identical array has been inserted more than once into different/incorrect
-    // buckets the verification step above will catch that.
-    G1StringDedupEntry** entry1 = _table->bucket(bucket);
-    while (*entry1 != NULL) {
-      typeArrayOop value1 = (*entry1)->obj();
-      bool latin1_1 = (*entry1)->latin1();
-      G1StringDedupEntry** entry2 = (*entry1)->next_addr();
-      while (*entry2 != NULL) {
-        typeArrayOop value2 = (*entry2)->obj();
-        bool latin1_2 = (*entry2)->latin1();
-        guarantee(latin1_1 != latin1_2 || !equals(value1, value2), "Table entries must not have identical arrays");
-        entry2 = (*entry2)->next_addr();
-      }
-      entry1 = (*entry1)->next_addr();
-    }
-  }
-}
-
-void G1StringDedupTable::clean_entry_cache() {
-  _entry_cache->delete_overflowed();
-}
-
-void G1StringDedupTable::print_statistics() {
-  Log(gc, stringdedup) log;
-  log.debug("  Table");
-  log.debug("    Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS,
-            G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)));
-  log.debug("    Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT, _table->_size, _min_size, _max_size);
-  log.debug("    Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT,
-            _table->_entries, percent_of(_table->_entries, _table->_size), _entry_cache->size(), _entries_added, _entries_removed);
-  log.debug("    Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")",
-            _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0);
-  log.debug("    Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x", _rehash_count, _rehash_threshold, _table->_hash_seed);
-  log.debug("    Age Threshold: " UINTX_FORMAT, StringDeduplicationAgeThreshold);
-}
--- a/src/hotspot/share/gc/g1/g1StringDedupTable.hpp	Thu Jun 14 15:27:49 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_G1STRINGDEDUPTABLE_HPP
-#define SHARE_VM_GC_G1_G1STRINGDEDUPTABLE_HPP
-
-#include "gc/g1/g1StringDedupStat.hpp"
-#include "runtime/mutexLocker.hpp"
-
-class G1StringDedupEntryCache;
-class G1StringDedupUnlinkOrOopsDoClosure;
-
-//
-// Table entry in the deduplication hashtable. Points weakly to the
-// character array. Can be chained in a linked list in case of hash
-// collisions or when placed in a freelist in the entry cache.
-//
-class G1StringDedupEntry : public CHeapObj<mtGC> {
-private:
-  G1StringDedupEntry* _next;
-  unsigned int      _hash;
-  bool              _latin1;
-  typeArrayOop      _obj;
-
-public:
-  G1StringDedupEntry() :
-    _next(NULL),
-    _hash(0),
-    _latin1(false),
-    _obj(NULL) {
-  }
-
-  G1StringDedupEntry* next() {
-    return _next;
-  }
-
-  G1StringDedupEntry** next_addr() {
-    return &_next;
-  }
-
-  void set_next(G1StringDedupEntry* next) {
-    _next = next;
-  }
-
-  unsigned int hash() {
-    return _hash;
-  }
-
-  void set_hash(unsigned int hash) {
-    _hash = hash;
-  }
-
-  bool latin1() {
-    return _latin1;
-  }
-
-  void set_latin1(bool latin1) {
-    _latin1 = latin1;
-  }
-
-  typeArrayOop obj() {
-    return _obj;
-  }
-
-  typeArrayOop* obj_addr() {
-    return &_obj;
-  }
-
-  void set_obj(typeArrayOop obj) {
-    _obj = obj;
-  }
-};
-
-//
-// The deduplication hashtable keeps track of all unique character arrays used
-// by String objects. Each table entry weakly points to an character array, allowing
-// otherwise unreachable character arrays to be declared dead and pruned from the
-// table.
-//
-// The table is dynamically resized to accommodate the current number of table entries.
-// The table has hash buckets with chains for hash collision. If the average chain
-// length goes above or below given thresholds the table grows or shrinks accordingly.
-//
-// The table is also dynamically rehashed (using a new hash seed) if it becomes severely
-// unbalanced, i.e., a hash chain is significantly longer than average.
-//
-// All access to the table is protected by the StringDedupTable_lock, except under
-// safepoints in which case GC workers are allowed to access a table partitions they
-// have claimed without first acquiring the lock. Note however, that this applies only
-// the table partition (i.e. a range of elements in _buckets), not other parts of the
-// table such as the _entries field, statistics counters, etc.
-//
-class G1StringDedupTable : public CHeapObj<mtGC> {
-private:
-  // The currently active hashtable instance. Only modified when
-  // the table is resizes or rehashed.
-  static G1StringDedupTable*      _table;
-
-  // Cache for reuse and fast alloc/free of table entries.
-  static G1StringDedupEntryCache* _entry_cache;
-
-  G1StringDedupEntry**            _buckets;
-  size_t                          _size;
-  uintx                           _entries;
-  uintx                           _shrink_threshold;
-  uintx                           _grow_threshold;
-  bool                            _rehash_needed;
-
-  // The hash seed also dictates which hash function to use. A
-  // zero hash seed means we will use the Java compatible hash
-  // function (which doesn't use a seed), and a non-zero hash
-  // seed means we use the murmur3 hash function.
-  jint                            _hash_seed;
-
-  // Constants governing table resize/rehash/cache.
-  static const size_t             _min_size;
-  static const size_t             _max_size;
-  static const double             _grow_load_factor;
-  static const double             _shrink_load_factor;
-  static const uintx              _rehash_multiple;
-  static const uintx              _rehash_threshold;
-  static const double             _max_cache_factor;
-
-  // Table statistics, only used for logging.
-  static uintx                    _entries_added;
-  static uintx                    _entries_removed;
-  static uintx                    _resize_count;
-  static uintx                    _rehash_count;
-
-  G1StringDedupTable(size_t size, jint hash_seed = 0);
-  ~G1StringDedupTable();
-
-  // Returns the hash bucket at the given index.
-  G1StringDedupEntry** bucket(size_t index) {
-    return _buckets + index;
-  }
-
-  // Returns the hash bucket index for the given hash code.
-  size_t hash_to_index(unsigned int hash) {
-    return (size_t)hash & (_size - 1);
-  }
-
-  // Adds a new table entry to the given hash bucket.
-  void add(typeArrayOop value, bool latin1, unsigned int hash, G1StringDedupEntry** list);
-
-  // Removes the given table entry from the table.
-  void remove(G1StringDedupEntry** pentry, uint worker_id);
-
-  // Transfers a table entry from the current table to the destination table.
-  void transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest);
-
-  // Returns an existing character array in the given hash bucket, or NULL
-  // if no matching character array exists.
-  typeArrayOop lookup(typeArrayOop value, bool latin1, unsigned int hash,
-                      G1StringDedupEntry** list, uintx &count);
-
-  // Returns an existing character array in the table, or inserts a new
-  // table entry if no matching character array exists.
-  typeArrayOop lookup_or_add_inner(typeArrayOop value, bool latin1, unsigned int hash);
-
-  // Thread safe lookup or add of table entry
-  static typeArrayOop lookup_or_add(typeArrayOop value, bool latin1, unsigned int hash) {
-    // Protect the table from concurrent access. Also note that this lock
-    // acts as a fence for _table, which could have been replaced by a new
-    // instance if the table was resized or rehashed.
-    MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
-    return _table->lookup_or_add_inner(value, latin1, hash);
-  }
-
-  // Returns true if the hashtable is currently using a Java compatible
-  // hash function.
-  static bool use_java_hash() {
-    return _table->_hash_seed == 0;
-  }
-
-  static bool equals(typeArrayOop value1, typeArrayOop value2);
-
-  // Computes the hash code for the given character array, using the
-  // currently active hash function and hash seed.
-  static unsigned int hash_code(typeArrayOop value, bool latin1);
-
-  static uintx unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl,
-                                 size_t partition_begin,
-                                 size_t partition_end,
-                                 uint worker_id);
-
-public:
-  static void create();
-
-  // Deduplicates the given String object, or adds its backing
-  // character array to the deduplication hashtable.
-  static void deduplicate(oop java_string, G1StringDedupStat& stat);
-
-  // If a table resize is needed, returns a newly allocated empty
-  // hashtable of the proper size.
-  static G1StringDedupTable* prepare_resize();
-
-  // Installs a newly resized table as the currently active table
-  // and deletes the previously active table.
-  static void finish_resize(G1StringDedupTable* resized_table);
-
-  // If a table rehash is needed, returns a newly allocated empty
-  // hashtable and updates the hash seed.
-  static G1StringDedupTable* prepare_rehash();
-
-  // Transfers rehashed entries from the currently active table into
-  // the new table. Installs the new table as the currently active table
-  // and deletes the previously active table.
-  static void finish_rehash(G1StringDedupTable* rehashed_table);
-
-  // If the table entry cache has grown too large, delete overflowed entries.
-  static void clean_entry_cache();
-
-  static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id);
-
-  static void print_statistics();
-  static void verify();
-};
-
-#endif // SHARE_VM_GC_G1_G1STRINGDEDUPTABLE_HPP
--- a/src/hotspot/share/gc/g1/g1StringDedupThread.cpp	Thu Jun 14 15:27:49 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "classfile/stringTable.hpp"
-#include "gc/g1/g1StringDedup.hpp"
-#include "gc/g1/g1StringDedupQueue.hpp"
-#include "gc/g1/g1StringDedupTable.hpp"
-#include "gc/g1/g1StringDedupThread.hpp"
-#include "gc/shared/suspendibleThreadSet.hpp"
-#include "logging/log.hpp"
-#include "oops/access.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/atomic.hpp"
-
-G1StringDedupThread* G1StringDedupThread::_thread = NULL;
-
-G1StringDedupThread::G1StringDedupThread() :
-  ConcurrentGCThread() {
-  set_name("G1 StrDedup");
-  create_and_start();
-}
-
-G1StringDedupThread::~G1StringDedupThread() {
-  ShouldNotReachHere();
-}
-
-void G1StringDedupThread::create() {
-  assert(G1StringDedup::is_enabled(), "String deduplication not enabled");
-  assert(_thread == NULL, "One string deduplication thread allowed");
-  _thread = new G1StringDedupThread();
-}
-
-G1StringDedupThread* G1StringDedupThread::thread() {
-  assert(G1StringDedup::is_enabled(), "String deduplication not enabled");
-  assert(_thread != NULL, "String deduplication thread not created");
-  return _thread;
-}
-
-class G1StringDedupSharedClosure: public OopClosure {
- private:
-  G1StringDedupStat& _stat;
-
- public:
-  G1StringDedupSharedClosure(G1StringDedupStat& stat) : _stat(stat) {}
-
-  virtual void do_oop(oop* p) { ShouldNotReachHere(); }
-  virtual void do_oop(narrowOop* p) {
-    oop java_string = RawAccess<>::oop_load(p);
-    G1StringDedupTable::deduplicate(java_string, _stat);
-  }
-};
-
-// The CDS archive does not include the string dedupication table. Only the string
-// table is saved in the archive. The shared strings from CDS archive need to be
-// added to the string dedupication table before deduplication occurs. That is
-// done in the begining of the G1StringDedupThread (see G1StringDedupThread::run()
-// below).
-void G1StringDedupThread::deduplicate_shared_strings(G1StringDedupStat& stat) {
-  G1StringDedupSharedClosure sharedStringDedup(stat);
-  StringTable::shared_oops_do(&sharedStringDedup);
-}
-
-void G1StringDedupThread::run_service() {
-  G1StringDedupStat total_stat;
-
-  deduplicate_shared_strings(total_stat);
-
-  // Main loop
-  for (;;) {
-    G1StringDedupStat stat;
-
-    stat.mark_idle();
-
-    // Wait for the queue to become non-empty
-    G1StringDedupQueue::wait();
-    if (should_terminate()) {
-      break;
-    }
-
-    {
-      // Include thread in safepoints
-      SuspendibleThreadSetJoiner sts_join;
-
-      stat.mark_exec();
-      print_start(stat);
-
-      // Process the queue
-      for (;;) {
-        oop java_string = G1StringDedupQueue::pop();
-        if (java_string == NULL) {
-          break;
-        }
-
-        G1StringDedupTable::deduplicate(java_string, stat);
-
-        // Safepoint this thread if needed
-        if (sts_join.should_yield()) {
-          stat.mark_block();
-          sts_join.yield();
-          stat.mark_unblock();
-        }
-      }
-
-      stat.mark_done();
-
-      total_stat.add(stat);
-      print_end(stat, total_stat);
-    }
-
-    G1StringDedupTable::clean_entry_cache();
-  }
-}
-
-void G1StringDedupThread::stop_service() {
-  G1StringDedupQueue::cancel_wait();
-}
-
-void G1StringDedupThread::print_start(const G1StringDedupStat& last_stat) {
-  G1StringDedupStat::print_start(last_stat);
-}
-
-void G1StringDedupThread::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
-  G1StringDedupStat::print_end(last_stat, total_stat);
-  if (log_is_enabled(Debug, gc, stringdedup)) {
-    G1StringDedupStat::print_statistics(last_stat, false);
-    G1StringDedupStat::print_statistics(total_stat, true);
-    G1StringDedupTable::print_statistics();
-    G1StringDedupQueue::print_statistics();
-  }
-}
--- a/src/hotspot/share/gc/g1/g1StringDedupThread.hpp	Thu Jun 14 15:27:49 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_G1STRINGDEDUPTHREAD_HPP
-#define SHARE_VM_GC_G1_G1STRINGDEDUPTHREAD_HPP
-
-#include "gc/g1/g1StringDedupStat.hpp"
-#include "gc/shared/concurrentGCThread.hpp"
-
-//
-// The deduplication thread is where the actual deduplication occurs. It waits for
-// deduplication candidates to appear on the deduplication queue, removes them from
-// the queue and tries to deduplicate them. It uses the deduplication hashtable to
-// find identical, already existing, character arrays on the heap. The thread runs
-// concurrently with the Java application but participates in safepoints to allow
-// the GC to adjust and unlink oops from the deduplication queue and table.
-//
-class G1StringDedupThread: public ConcurrentGCThread {
-private:
-  static G1StringDedupThread* _thread;
-
-  G1StringDedupThread();
-  ~G1StringDedupThread();
-
-  void print_start(const G1StringDedupStat& last_stat);
-  void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
-
-  void run_service();
-  void stop_service();
-
-public:
-  static void create();
-
-  static G1StringDedupThread* thread();
-
-  void deduplicate_shared_strings(G1StringDedupStat& stat);
-};
-
-#endif // SHARE_VM_GC_G1_G1STRINGDEDUPTHREAD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
+#include "gc/shared/stringdedup/stringDedupTable.hpp"
+#include "gc/shared/stringdedup/stringDedupThread.hpp"
+
+bool StringDedup::_enabled = false;
+
+void StringDedup::gc_prologue(bool resize_and_rehash_table) {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupQueue::gc_prologue();
+  StringDedupTable::gc_prologue(resize_and_rehash_table);
+
+}
+void StringDedup::gc_epilogue() {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupQueue::gc_epilogue();
+  StringDedupTable::gc_epilogue();
+}
+
+void StringDedup::stop() {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupThread::thread()->stop();
+}
+
+void StringDedup::deduplicate(oop java_string) {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupStat dummy; // Statistics from this path is never used
+  StringDedupTable::deduplicate(java_string, &dummy);
+}
+
+
+void StringDedup::parallel_unlink(StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id) {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupQueue::unlink_or_oops_do(unlink);
+  StringDedupTable::unlink_or_oops_do(unlink, worker_id);
+}
+
+void StringDedup::threads_do(ThreadClosure* tc) {
+  assert(is_enabled(), "String deduplication not enabled");
+  tc->do_thread(StringDedupThread::thread());
+}
+
+void StringDedup::print_worker_threads_on(outputStream* st) {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupThread::thread()->print_on(st);
+  st->cr();
+}
+
+void StringDedup::verify() {
+  assert(is_enabled(), "String deduplication not enabled");
+  StringDedupQueue::verify();
+  StringDedupTable::verify();
+}
+
+
+StringDedupUnlinkOrOopsDoClosure::StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
+                                                                   OopClosure* keep_alive) :
+  _is_alive(is_alive), _keep_alive(keep_alive) {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP
+
+//
+// String Deduplication
+//
+// String deduplication aims to reduce the heap live-set by deduplicating identical
+// instances of String so that they share the same backing character array.
+//
+// The deduplication process is divided in two main parts, 1) finding the objects to
+// deduplicate, and 2) deduplicating those objects. The first part is done as part of
+// a normal GC cycle when objects are marked or evacuated. At this time a check is
+// applied on each object to check if it is a candidate for deduplication. If so, the
+// object is placed on the deduplication queue for later processing. The second part,
+// processing the objects on the deduplication queue, is a concurrent phase which
+// starts right after the stop-the-wold marking/evacuation phase. This phase is
+// executed by the deduplication thread, which pulls deduplication candidates of the
+// deduplication queue and tries to deduplicate them.
+//
+// A deduplication hashtable is used to keep track of all unique character arrays
+// used by String objects. When deduplicating, a lookup is made in this table to see
+// if there is already an identical character array somewhere on the heap. If so, the
+// String object is adjusted to point to that character array, releasing the reference
+// to the original array allowing it to eventually be garbage collected. If the lookup
+// fails the character array is instead inserted into the hashtable so that this array
+// can be shared at some point in the future.
+//
+// Candidate selection criteria is GC specific.
+//
+// Interned strings are a bit special. They are explicitly deduplicated just before
+// being inserted into the StringTable (to avoid counteracting C2 optimizations done
+// on string literals), then they also become deduplication candidates if they reach
+// the deduplication age threshold or are evacuated to an old heap region. The second
+// attempt to deduplicate such strings will be in vain, but we have no fast way of
+// filtering them out. This has not shown to be a problem, as the number of interned
+// strings is usually dwarfed by the number of normal (non-interned) strings.
+//
+// For additional information on string deduplication, please see JEP 192,
+// http://openjdk.java.net/jeps/192
+//
+
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
+#include "gc/shared/stringdedup/stringDedupStat.hpp"
+#include "gc/shared/stringdedup/stringDedupTable.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/thread.hpp"
+
+//
+// Main interface for interacting with string deduplication.
+//
+class StringDedup : public AllStatic {
+private:
+  // Single state for checking if string deduplication is enabled.
+  static bool _enabled;
+
+public:
+  // Returns true if string deduplication is enabled.
+  static bool is_enabled() {
+    return _enabled;
+  }
+
+  // Stop the deduplication thread.
+  static void stop();
+
+  // Immediately deduplicates the given String object, bypassing the
+  // the deduplication queue.
+  static void deduplicate(oop java_string);
+
+  static void parallel_unlink(StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id);
+
+  static void threads_do(ThreadClosure* tc);
+  static void print_worker_threads_on(outputStream* st);
+  static void verify();
+
+  // GC support
+  static void gc_prologue(bool resize_and_rehash_table);
+  static void gc_epilogue();
+
+protected:
+  // Initialize string deduplication.
+  // QUEUE: String Dedup Queue implementation
+  // STAT:  String Dedup Stat implementation
+  template <typename QUEUE, typename STAT>
+  static void initialize_impl();
+};
+
+//
+// This closure encapsulates the closures needed when scanning
+// the deduplication queue and table during the unlink_or_oops_do() operation.
+//
+class StringDedupUnlinkOrOopsDoClosure : public StackObj {
+private:
+  BoolObjectClosure*  _is_alive;
+  OopClosure*         _keep_alive;
+
+public:
+  StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
+                                     OopClosure* keep_alive);
+
+  // Applies and returns the result from the is_alive closure, or
+  // returns true if no such closure was provided.
+  bool is_alive(oop o) {
+    if (_is_alive != NULL) {
+      return _is_alive->do_object_b(o);
+    }
+    return true;
+  }
+
+  // Applies the keep_alive closure, or does nothing if no such
+  // closure was provided.
+  void keep_alive(oop* p) {
+    if (_keep_alive != NULL) {
+      _keep_alive->do_oop(p);
+    }
+  }
+};
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.inline.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUP_INLINE_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUP_INLINE_HPP
+
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupThread.inline.hpp"
+
+template <typename Q, typename S>
+void StringDedup::initialize_impl() {
+  if (UseStringDeduplication) {
+    _enabled = true;
+    StringDedupQueue::create<Q>();
+    StringDedupTable::create();
+    StringDedupThreadImpl<S>::create();
+  }
+}
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUP_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupQueue.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
+#include "runtime/atomic.hpp"
+
+StringDedupQueue* StringDedupQueue::_queue = NULL;
+volatile size_t   StringDedupQueue::_claimed_index = 0;
+
+size_t StringDedupQueue::claim() {
+  return Atomic::add(size_t(1), &_claimed_index) - 1;
+}
+
+void StringDedupQueue::unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl) {
+  size_t claimed_queue = claim();
+  while (claimed_queue < queue()->num_queues()) {
+    queue()->unlink_or_oops_do_impl(cl, claimed_queue);
+    claimed_queue = claim();
+  }
+}
+
+void StringDedupQueue::print_statistics() {
+  queue()->print_statistics_impl();
+}
+
+void StringDedupQueue::verify() {
+  queue()->verify_impl();
+}
+
+StringDedupQueue* const StringDedupQueue::queue() {
+  assert(_queue != NULL, "Not yet initialized");
+  return _queue;
+}
+
+
+void StringDedupQueue::gc_prologue() {
+  _claimed_index = 0;
+}
+
+void StringDedupQueue::gc_epilogue() {
+  assert(_claimed_index >= queue()->num_queues() || _claimed_index == 0, "All or nothing");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupQueue.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPQUEUE_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPQUEUE_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/oop.hpp"
+
+class StringDedupUnlinkOrOopsDoClosure;
+
+//
+// The deduplication queue acts as the communication channel between mark/evacuation
+// phase and the concurrent deduplication phase. Deduplication candidates
+// found during mark/evacuation are placed on this queue for later processing in the
+// deduplication thread. A queue entry is an oop pointing to a String object (as opposed
+// to entries in the deduplication hashtable which points to character arrays).
+//
+// While users of the queue treat it as a single queue, it is implemented as a set of
+// queues, one queue per GC worker thread, to allow lock-free and cache-friendly enqueue
+// operations by the GC workers.
+//
+// The oops in the queue are treated as weak pointers, meaning the objects they point to
+// can become unreachable and pruned (cleared) before being popped by the deduplication
+// thread.
+//
+// Pushing to the queue is thread safe (this relies on each thread using a unique worker
+// id). Popping from the queue is NOT thread safe and can only be done by the deduplication
+// thread outside a safepoint.
+//
+
+class StringDedupQueue : public CHeapObj<mtGC> {
+private:
+  static StringDedupQueue*   _queue;
+  static volatile size_t     _claimed_index;
+
+public:
+  template <typename Q>
+  static void create();
+
+  // Blocks and waits for the queue to become non-empty.
+  static inline void wait();
+
+  // Wakes up any thread blocked waiting for the queue to become non-empty.
+  static inline void cancel_wait();
+
+  // Pushes a deduplication candidate onto a specific GC worker queue.
+  static inline void push(uint worker_id, oop java_string);
+
+  // Pops a deduplication candidate from any queue, returns NULL if
+  // all queues are empty.
+  static inline oop pop();
+
+  static void unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl);
+
+  static void print_statistics();
+  static void verify();
+
+  // GC support
+  static void gc_prologue();
+  static void gc_epilogue();
+
+protected:
+  static StringDedupQueue* const queue();
+
+  // Queue interface.
+
+  // Blocks and waits for the queue to become non-empty.
+  virtual void wait_impl() = 0;
+
+  // Wakes up any thread blocked waiting for the queue to become non-empty.
+  virtual void cancel_wait_impl() = 0;
+
+  // Pushes a deduplication candidate onto a specific GC worker queue.
+  virtual void push_impl(uint worker_id, oop java_string) = 0;
+
+  // Pops a deduplication candidate from any queue, returns NULL if
+  // all queues are empty.
+  virtual oop pop_impl() = 0;
+
+  virtual void unlink_or_oops_do_impl(StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) = 0;
+
+  virtual void print_statistics_impl() = 0;
+  virtual void verify_impl() = 0;
+
+  virtual size_t num_queues() const = 0;
+
+  static size_t claim();
+};
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPQUEUE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupQueue.inline.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPQUEUE_INLINE_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPQUEUE_INLINE_HPP
+
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
+
+template <typename Q>
+void StringDedupQueue::create() {
+  assert(StringDedup::is_enabled(), "Must be enabled");
+  assert(_queue == NULL, "Can have only one queue");
+  _queue = new Q;
+}
+
+void StringDedupQueue::wait() {
+  queue()->wait_impl();
+}
+
+void StringDedupQueue::cancel_wait() {
+  queue()->cancel_wait_impl();
+}
+
+void StringDedupQueue::push(uint worker_id, oop java_string) {
+  queue()->push_impl(worker_id, java_string);
+}
+
+oop StringDedupQueue::pop() {
+  return queue()->pop_impl();
+}
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPQUEUE_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupStat.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/shared/stringdedup/stringDedupStat.hpp"
+#include "logging/log.hpp"
+
+StringDedupStat::StringDedupStat() :
+  _inspected(0),
+  _skipped(0),
+  _hashed(0),
+  _known(0),
+  _new(0),
+  _new_bytes(0),
+  _deduped(0),
+  _deduped_bytes(0),
+  _idle(0),
+  _exec(0),
+  _block(0),
+  _start_concurrent(0.0),
+  _end_concurrent(0.0),
+  _start_phase(0.0),
+  _idle_elapsed(0.0),
+  _exec_elapsed(0.0),
+  _block_elapsed(0.0) {
+}
+
+void StringDedupStat::add(const StringDedupStat* const stat) {
+  _inspected           += stat->_inspected;
+  _skipped             += stat->_skipped;
+  _hashed              += stat->_hashed;
+  _known               += stat->_known;
+  _new                 += stat->_new;
+  _new_bytes           += stat->_new_bytes;
+  _deduped             += stat->_deduped;
+  _deduped_bytes       += stat->_deduped_bytes;
+  _idle                += stat->_idle;
+  _exec                += stat->_exec;
+  _block               += stat->_block;
+  _idle_elapsed        += stat->_idle_elapsed;
+  _exec_elapsed        += stat->_exec_elapsed;
+  _block_elapsed       += stat->_block_elapsed;
+}
+
+void StringDedupStat::print_start(const StringDedupStat* last_stat) {
+  log_info(gc, stringdedup)(
+     "Concurrent String Deduplication (" STRDEDUP_TIME_FORMAT ")",
+     STRDEDUP_TIME_PARAM(last_stat->_start_concurrent));
+}
+
+void StringDedupStat::print_end(const StringDedupStat* last_stat, const StringDedupStat* total_stat) {
+  double total_deduped_bytes_percent = 0.0;
+
+  if (total_stat->_new_bytes > 0) {
+    // Avoid division by zero
+    total_deduped_bytes_percent = percent_of(total_stat->_deduped_bytes, total_stat->_new_bytes);
+  }
+
+  log_info(gc, stringdedup)(
+    "Concurrent String Deduplication "
+    STRDEDUP_BYTES_FORMAT_NS "->" STRDEDUP_BYTES_FORMAT_NS "(" STRDEDUP_BYTES_FORMAT_NS ") "
+    "avg " STRDEDUP_PERCENT_FORMAT_NS " "
+    "(" STRDEDUP_TIME_FORMAT ", " STRDEDUP_TIME_FORMAT ") " STRDEDUP_TIME_FORMAT_MS,
+    STRDEDUP_BYTES_PARAM(last_stat->_new_bytes),
+    STRDEDUP_BYTES_PARAM(last_stat->_new_bytes - last_stat->_deduped_bytes),
+    STRDEDUP_BYTES_PARAM(last_stat->_deduped_bytes),
+    total_deduped_bytes_percent,
+    STRDEDUP_TIME_PARAM(last_stat->_start_concurrent),
+    STRDEDUP_TIME_PARAM(last_stat->_end_concurrent),
+    STRDEDUP_TIME_PARAM_MS(last_stat->_exec_elapsed));
+}
+
+void StringDedupStat::reset() {
+  _inspected = 0;
+  _skipped = 0;
+  _hashed = 0;
+  _known = 0;
+  _new = 0;
+  _new_bytes = 0;
+  _deduped = 0;
+  _deduped_bytes = 0;
+  _idle = 0;
+  _exec = 0;
+  _block = 0;
+  _start_concurrent = 0.0;
+  _end_concurrent = 0.0;
+  _start_phase = 0.0;
+  _idle_elapsed = 0.0;
+  _exec_elapsed = 0.0;
+  _block_elapsed = 0.0;
+}
+
+void StringDedupStat::print_statistics(bool total) const {
+  double skipped_percent             = percent_of(_skipped, _inspected);
+  double hashed_percent              = percent_of(_hashed, _inspected);
+  double known_percent               = percent_of(_known, _inspected);
+  double new_percent                 = percent_of(_new, _inspected);
+  double deduped_percent             = percent_of(_deduped, _new);
+  double deduped_bytes_percent       = percent_of(_deduped_bytes, _new_bytes);
+/*
+  double deduped_young_percent       = percent_of(stat._deduped_young, stat._deduped);
+  double deduped_young_bytes_percent = percent_of(stat._deduped_young_bytes, stat._deduped_bytes);
+  double deduped_old_percent         = percent_of(stat._deduped_old, stat._deduped);
+  double deduped_old_bytes_percent   = percent_of(stat._deduped_old_bytes, stat._deduped_bytes);
+*/
+  if (total) {
+    log_debug(gc, stringdedup)(
+      "  Total Exec: " UINTX_FORMAT "/" STRDEDUP_TIME_FORMAT_MS
+      ", Idle: " UINTX_FORMAT "/" STRDEDUP_TIME_FORMAT_MS
+      ", Blocked: " UINTX_FORMAT "/" STRDEDUP_TIME_FORMAT_MS,
+      _exec, STRDEDUP_TIME_PARAM_MS(_exec_elapsed),
+      _idle, STRDEDUP_TIME_PARAM_MS(_idle_elapsed),
+      _block, STRDEDUP_TIME_PARAM_MS(_block_elapsed));
+  } else {
+    log_debug(gc, stringdedup)(
+      "  Last Exec: " STRDEDUP_TIME_FORMAT_MS
+      ", Idle: " STRDEDUP_TIME_FORMAT_MS
+      ", Blocked: " UINTX_FORMAT "/" STRDEDUP_TIME_FORMAT_MS,
+      STRDEDUP_TIME_PARAM_MS(_exec_elapsed),
+      STRDEDUP_TIME_PARAM_MS(_idle_elapsed),
+      _block, STRDEDUP_TIME_PARAM_MS(_block_elapsed));
+  }
+  log_debug(gc, stringdedup)("    Inspected:    " STRDEDUP_OBJECTS_FORMAT, _inspected);
+  log_debug(gc, stringdedup)("      Skipped:    " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ")", _skipped, skipped_percent);
+  log_debug(gc, stringdedup)("      Hashed:     " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ")", _hashed, hashed_percent);
+  log_debug(gc, stringdedup)("      Known:      " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ")", _known, known_percent);
+  log_debug(gc, stringdedup)("      New:        " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ") " STRDEDUP_BYTES_FORMAT,
+                             _new, new_percent, STRDEDUP_BYTES_PARAM(_new_bytes));
+  log_debug(gc, stringdedup)("    Deduplicated: " STRDEDUP_OBJECTS_FORMAT "(" STRDEDUP_PERCENT_FORMAT ") " STRDEDUP_BYTES_FORMAT "(" STRDEDUP_PERCENT_FORMAT ")",
+                             _deduped, deduped_percent, STRDEDUP_BYTES_PARAM(_deduped_bytes), deduped_bytes_percent);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupStat.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPSTAT_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPSTAT_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/os.hpp"
+
+// Macros for GC log output formating
+#define STRDEDUP_OBJECTS_FORMAT         UINTX_FORMAT_W(12)
+#define STRDEDUP_TIME_FORMAT            "%.3fs"
+#define STRDEDUP_TIME_PARAM(time)       (time)
+#define STRDEDUP_TIME_FORMAT_MS         "%.3fms"
+#define STRDEDUP_TIME_PARAM_MS(time)    ((time) * MILLIUNITS)
+#define STRDEDUP_PERCENT_FORMAT         "%5.1f%%"
+#define STRDEDUP_PERCENT_FORMAT_NS      "%.1f%%"
+#define STRDEDUP_BYTES_FORMAT           "%8.1f%s"
+#define STRDEDUP_BYTES_FORMAT_NS        "%.1f%s"
+#define STRDEDUP_BYTES_PARAM(bytes)     byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes))
+
+//
+// Statistics gathered by the deduplication thread.
+//
+class StringDedupStat : public CHeapObj<mtGC> {
+protected:
+  // Counters
+  uintx  _inspected;
+  uintx  _skipped;
+  uintx  _hashed;
+  uintx  _known;
+  uintx  _new;
+  uintx  _new_bytes;
+  uintx  _deduped;
+  uintx  _deduped_bytes;
+  uintx  _idle;
+  uintx  _exec;
+  uintx  _block;
+
+  // Time spent by the deduplication thread in different phases
+  double _start_concurrent;
+  double _end_concurrent;
+  double _start_phase;
+  double _idle_elapsed;
+  double _exec_elapsed;
+  double _block_elapsed;
+
+public:
+  StringDedupStat();
+
+  void inc_inspected() {
+    _inspected++;
+  }
+
+  void inc_skipped() {
+    _skipped++;
+  }
+
+  void inc_hashed() {
+    _hashed++;
+  }
+
+  void inc_known() {
+    _known++;
+  }
+
+  void inc_new(uintx bytes) {
+    _new++;
+    _new_bytes += bytes;
+  }
+
+  virtual void deduped(oop obj, uintx bytes) {
+    _deduped++;
+    _deduped_bytes += bytes;
+  }
+
+  void mark_idle() {
+    _start_phase = os::elapsedTime();
+    _idle++;
+  }
+
+  void mark_exec() {
+    double now = os::elapsedTime();
+    _idle_elapsed = now - _start_phase;
+    _start_phase = now;
+    _start_concurrent = now;
+    _exec++;
+  }
+
+  void mark_block() {
+    double now = os::elapsedTime();
+    _exec_elapsed += now - _start_phase;
+    _start_phase = now;
+    _block++;
+  }
+
+  void mark_unblock() {
+    double now = os::elapsedTime();
+    _block_elapsed += now - _start_phase;
+    _start_phase = now;
+  }
+
+  void mark_done() {
+    double now = os::elapsedTime();
+    _exec_elapsed += now - _start_phase;
+    _end_concurrent = now;
+  }
+
+  virtual void reset();
+  virtual void add(const StringDedupStat* const stat);
+  virtual void print_statistics(bool total) const;
+
+  static void print_start(const StringDedupStat* last_stat);
+  static void print_end(const StringDedupStat* last_stat, const StringDedupStat* total_stat);
+};
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPSTAT_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/altHashing.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupTable.hpp"
+#include "gc/shared/suspendibleThreadSet.hpp"
+#include "logging/log.hpp"
+#include "memory/padded.inline.hpp"
+#include "oops/access.inline.hpp"
+#include "oops/arrayOop.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/typeArrayOop.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepointVerifiers.hpp"
+
+//
+// List of deduplication table entries. Links table
+// entries together using their _next fields.
+//
+class StringDedupEntryList : public CHeapObj<mtGC> {
+private:
+  StringDedupEntry*   _list;
+  size_t              _length;
+
+public:
+  StringDedupEntryList() :
+    _list(NULL),
+    _length(0) {
+  }
+
+  void add(StringDedupEntry* entry) {
+    entry->set_next(_list);
+    _list = entry;
+    _length++;
+  }
+
+  StringDedupEntry* remove() {
+    StringDedupEntry* entry = _list;
+    if (entry != NULL) {
+      _list = entry->next();
+      _length--;
+    }
+    return entry;
+  }
+
+  StringDedupEntry* remove_all() {
+    StringDedupEntry* list = _list;
+    _list = NULL;
+    return list;
+  }
+
+  size_t length() {
+    return _length;
+  }
+};
+
+//
+// Cache of deduplication table entries. This cache provides fast allocation and
+// reuse of table entries to lower the pressure on the underlying allocator.
+// But more importantly, it provides fast/deferred freeing of table entries. This
+// is important because freeing of table entries is done during stop-the-world
+// phases and it is not uncommon for large number of entries to be freed at once.
+// Tables entries that are freed during these phases are placed onto a freelist in
+// the cache. The deduplication thread, which executes in a concurrent phase, will
+// later reuse or free the underlying memory for these entries.
+//
+// The cache allows for single-threaded allocations and multi-threaded frees.
+// Allocations are synchronized by StringDedupTable_lock as part of a table
+// modification.
+//
+class StringDedupEntryCache : public CHeapObj<mtGC> {
+private:
+  // One cache/overflow list per GC worker to allow lock less freeing of
+  // entries while doing a parallel scan of the table. Using PaddedEnd to
+  // avoid false sharing.
+  size_t                             _nlists;
+  size_t                             _max_list_length;
+  PaddedEnd<StringDedupEntryList>*   _cached;
+  PaddedEnd<StringDedupEntryList>*   _overflowed;
+
+public:
+  StringDedupEntryCache(size_t max_size);
+  ~StringDedupEntryCache();
+
+  // Set max number of table entries to cache.
+  void set_max_size(size_t max_size);
+
+  // Get a table entry from the cache, or allocate a new entry if the cache is empty.
+  StringDedupEntry* alloc();
+
+  // Insert a table entry into the cache.
+  void free(StringDedupEntry* entry, uint worker_id);
+
+  // Returns current number of entries in the cache.
+  size_t size();
+
+  // Deletes overflowed entries.
+  void delete_overflowed();
+};
+
+StringDedupEntryCache::StringDedupEntryCache(size_t max_size) :
+  _nlists(ParallelGCThreads),
+  _max_list_length(0),
+  _cached(PaddedArray<StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)),
+  _overflowed(PaddedArray<StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)) {
+  set_max_size(max_size);
+}
+
+StringDedupEntryCache::~StringDedupEntryCache() {
+  ShouldNotReachHere();
+}
+
+void StringDedupEntryCache::set_max_size(size_t size) {
+  _max_list_length = size / _nlists;
+}
+
+StringDedupEntry* StringDedupEntryCache::alloc() {
+  for (size_t i = 0; i < _nlists; i++) {
+    StringDedupEntry* entry = _cached[i].remove();
+    if (entry != NULL) {
+      return entry;
+    }
+  }
+  return new StringDedupEntry();
+}
+
+void StringDedupEntryCache::free(StringDedupEntry* entry, uint worker_id) {
+  assert(entry->obj() != NULL, "Double free");
+  assert(worker_id < _nlists, "Invalid worker id");
+
+  entry->set_obj(NULL);
+  entry->set_hash(0);
+
+  if (_cached[worker_id].length() < _max_list_length) {
+    // Cache is not full
+    _cached[worker_id].add(entry);
+  } else {
+    // Cache is full, add to overflow list for later deletion
+    _overflowed[worker_id].add(entry);
+  }
+}
+
+size_t StringDedupEntryCache::size() {
+  size_t size = 0;
+  for (size_t i = 0; i < _nlists; i++) {
+    size += _cached[i].length();
+  }
+  return size;
+}
+
+void StringDedupEntryCache::delete_overflowed() {
+  double start = os::elapsedTime();
+  uintx count = 0;
+
+  for (size_t i = 0; i < _nlists; i++) {
+    StringDedupEntry* entry;
+
+    {
+      // The overflow list can be modified during safepoints, therefore
+      // we temporarily join the suspendible thread set while removing
+      // all entries from the list.
+      SuspendibleThreadSetJoiner sts_join;
+      entry = _overflowed[i].remove_all();
+    }
+
+    // Delete all entries
+    while (entry != NULL) {
+      StringDedupEntry* next = entry->next();
+      delete entry;
+      entry = next;
+      count++;
+    }
+  }
+
+  double end = os::elapsedTime();
+  log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " STRDEDUP_TIME_FORMAT_MS,
+                             count, STRDEDUP_TIME_PARAM_MS(end - start));
+}
+
+StringDedupTable*        StringDedupTable::_table = NULL;
+StringDedupEntryCache*   StringDedupTable::_entry_cache = NULL;
+
+const size_t             StringDedupTable::_min_size = (1 << 10);   // 1024
+const size_t             StringDedupTable::_max_size = (1 << 24);   // 16777216
+const double             StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load
+const double             StringDedupTable::_shrink_load_factor = _grow_load_factor / 3.0; // Shrink table at 67% load
+const double             StringDedupTable::_max_cache_factor = 0.1; // Cache a maximum of 10% of the table size
+const uintx              StringDedupTable::_rehash_multiple = 60;   // Hash bucket has 60 times more collisions than expected
+const uintx              StringDedupTable::_rehash_threshold = (uintx)(_rehash_multiple * _grow_load_factor);
+
+uintx                    StringDedupTable::_entries_added = 0;
+uintx                    StringDedupTable::_entries_removed = 0;
+uintx                    StringDedupTable::_resize_count = 0;
+uintx                    StringDedupTable::_rehash_count = 0;
+
+StringDedupTable*        StringDedupTable::_resized_table = NULL;
+StringDedupTable*        StringDedupTable::_rehashed_table = NULL;
+volatile size_t          StringDedupTable::_claimed_index = 0;
+
+StringDedupTable::StringDedupTable(size_t size, jint hash_seed) :
+  _size(size),
+  _entries(0),
+  _grow_threshold((uintx)(size * _grow_load_factor)),
+  _shrink_threshold((uintx)(size * _shrink_load_factor)),
+  _rehash_needed(false),
+  _hash_seed(hash_seed) {
+  assert(is_power_of_2(size), "Table size must be a power of 2");
+  _buckets = NEW_C_HEAP_ARRAY(StringDedupEntry*, _size, mtGC);
+  memset(_buckets, 0, _size * sizeof(StringDedupEntry*));
+}
+
+StringDedupTable::~StringDedupTable() {
+  FREE_C_HEAP_ARRAY(G1StringDedupEntry*, _buckets);
+}
+
+void StringDedupTable::create() {
+  assert(_table == NULL, "One string deduplication table allowed");
+  _entry_cache = new StringDedupEntryCache(_min_size * _max_cache_factor);
+  _table = new StringDedupTable(_min_size);
+}
+
+void StringDedupTable::add(typeArrayOop value, bool latin1, unsigned int hash, StringDedupEntry** list) {
+  StringDedupEntry* entry = _entry_cache->alloc();
+  entry->set_obj(value);
+  entry->set_hash(hash);
+  entry->set_latin1(latin1);
+  entry->set_next(*list);
+  *list = entry;
+  _entries++;
+}
+
+void StringDedupTable::remove(StringDedupEntry** pentry, uint worker_id) {
+  StringDedupEntry* entry = *pentry;
+  *pentry = entry->next();
+  _entry_cache->free(entry, worker_id);
+}
+
+void StringDedupTable::transfer(StringDedupEntry** pentry, StringDedupTable* dest) {
+  StringDedupEntry* entry = *pentry;
+  *pentry = entry->next();
+  unsigned int hash = entry->hash();
+  size_t index = dest->hash_to_index(hash);
+  StringDedupEntry** list = dest->bucket(index);
+  entry->set_next(*list);
+  *list = entry;
+}
+
+bool StringDedupTable::equals(typeArrayOop value1, typeArrayOop value2) {
+  return (oopDesc::equals(value1, value2) ||
+          (value1->length() == value2->length() &&
+          (!memcmp(value1->base(T_BYTE),
+                    value2->base(T_BYTE),
+                    value1->length() * sizeof(jbyte)))));
+}
+
+typeArrayOop StringDedupTable::lookup(typeArrayOop value, bool latin1, unsigned int hash,
+                                      StringDedupEntry** list, uintx &count) {
+  for (StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) {
+    if (entry->hash() == hash && entry->latin1() == latin1) {
+      typeArrayOop existing_value = entry->obj();
+      if (equals(value, existing_value)) {
+        // Apply proper barrier to make sure it is kept alive. Concurrent mark might
+        // otherwise declare it dead if there are no other strong references to this object.
+        oop* obj_addr = (oop*)entry->obj_addr();
+        oop obj = RootAccess<IN_CONCURRENT_ROOT | ON_WEAK_OOP_REF>::oop_load(obj_addr);
+        return typeArrayOop(obj);
+      }
+    }
+    count++;
+  }
+
+  // Not found
+  return NULL;
+}
+
+typeArrayOop StringDedupTable::lookup_or_add_inner(typeArrayOop value, bool latin1, unsigned int hash) {
+  size_t index = hash_to_index(hash);
+  StringDedupEntry** list = bucket(index);
+  uintx count = 0;
+
+  // Lookup in list
+  typeArrayOop existing_value = lookup(value, latin1, hash, list, count);
+
+  // Check if rehash is needed
+  if (count > _rehash_threshold) {
+    _rehash_needed = true;
+  }
+
+  if (existing_value == NULL) {
+    // Not found, add new entry
+    add(value, latin1, hash, list);
+
+    // Update statistics
+    _entries_added++;
+  }
+
+  return existing_value;
+}
+
+unsigned int StringDedupTable::hash_code(typeArrayOop value, bool latin1) {
+  unsigned int hash;
+  int length = value->length();
+  if (latin1) {
+    const jbyte* data = (jbyte*)value->base(T_BYTE);
+    if (use_java_hash()) {
+      hash = java_lang_String::hash_code(data, length);
+    } else {
+      hash = AltHashing::murmur3_32(_table->_hash_seed, data, length);
+    }
+  } else {
+    length /= sizeof(jchar) / sizeof(jbyte); // Convert number of bytes to number of chars
+    const jchar* data = (jchar*)value->base(T_CHAR);
+    if (use_java_hash()) {
+      hash = java_lang_String::hash_code(data, length);
+    } else {
+      hash = AltHashing::murmur3_32(_table->_hash_seed, data, length);
+    }
+  }
+
+  return hash;
+}
+
+void StringDedupTable::deduplicate(oop java_string, StringDedupStat* stat) {
+  assert(java_lang_String::is_instance(java_string), "Must be a string");
+  NoSafepointVerifier nsv;
+
+  stat->inc_inspected();
+
+  typeArrayOop value = java_lang_String::value(java_string);
+  if (value == NULL) {
+    // String has no value
+    stat->inc_skipped();
+    return;
+  }
+
+  bool latin1 = java_lang_String::is_latin1(java_string);
+  unsigned int hash = 0;
+
+  if (use_java_hash()) {
+    // Get hash code from cache
+    hash = java_lang_String::hash(java_string);
+  }
+
+  if (hash == 0) {
+    // Compute hash
+    hash = hash_code(value, latin1);
+    stat->inc_hashed();
+
+    if (use_java_hash() && hash != 0) {
+      // Store hash code in cache
+      java_lang_String::set_hash(java_string, hash);
+    }
+  }
+
+  typeArrayOop existing_value = lookup_or_add(value, latin1, hash);
+  if (existing_value == value) {
+    // Same value, already known
+    stat->inc_known();
+    return;
+  }
+
+  // Get size of value array
+  uintx size_in_bytes = value->size() * HeapWordSize;
+  stat->inc_new(size_in_bytes);
+
+  if (existing_value != NULL) {
+    // Existing value found, deduplicate string
+    java_lang_String::set_value(java_string, existing_value);
+    stat->deduped(value, size_in_bytes);
+  }
+}
+
+bool StringDedupTable::is_resizing() {
+  return _resized_table != NULL;
+}
+
+bool StringDedupTable::is_rehashing() {
+  return _rehashed_table != NULL;
+}
+
+StringDedupTable* StringDedupTable::prepare_resize() {
+  size_t size = _table->_size;
+
+  // Check if the hashtable needs to be resized
+  if (_table->_entries > _table->_grow_threshold) {
+    // Grow table, double the size
+    size *= 2;
+    if (size > _max_size) {
+      // Too big, don't resize
+      return NULL;
+    }
+  } else if (_table->_entries < _table->_shrink_threshold) {
+    // Shrink table, half the size
+    size /= 2;
+    if (size < _min_size) {
+      // Too small, don't resize
+      return NULL;
+    }
+  } else if (StringDeduplicationResizeALot) {
+    // Force grow
+    size *= 2;
+    if (size > _max_size) {
+      // Too big, force shrink instead
+      size /= 4;
+    }
+  } else {
+    // Resize not needed
+    return NULL;
+  }
+
+  // Update statistics
+  _resize_count++;
+
+  // Update max cache size
+  _entry_cache->set_max_size(size * _max_cache_factor);
+
+  // Allocate the new table. The new table will be populated by workers
+  // calling unlink_or_oops_do() and finally installed by finish_resize().
+  return new StringDedupTable(size, _table->_hash_seed);
+}
+
+void StringDedupTable::finish_resize(StringDedupTable* resized_table) {
+  assert(resized_table != NULL, "Invalid table");
+
+  resized_table->_entries = _table->_entries;
+
+  // Free old table
+  delete _table;
+
+  // Install new table
+  _table = resized_table;
+}
+
+void StringDedupTable::unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id) {
+  // The table is divided into partitions to allow lock-less parallel processing by
+  // multiple worker threads. A worker thread first claims a partition, which ensures
+  // exclusive access to that part of the table, then continues to process it. To allow
+  // shrinking of the table in parallel we also need to make sure that the same worker
+  // thread processes all partitions where entries will hash to the same destination
+  // partition. Since the table size is always a power of two and we always shrink by
+  // dividing the table in half, we know that for a given partition there is only one
+  // other partition whoes entries will hash to the same destination partition. That
+  // other partition is always the sibling partition in the second half of the table.
+  // For example, if the table is divided into 8 partitions, the sibling of partition 0
+  // is partition 4, the sibling of partition 1 is partition 5, etc.
+  size_t table_half = _table->_size / 2;
+
+  // Let each partition be one page worth of buckets
+  size_t partition_size = MIN2(table_half, os::vm_page_size() / sizeof(StringDedupEntry*));
+  assert(table_half % partition_size == 0, "Invalid partition size");
+
+  // Number of entries removed during the scan
+  uintx removed = 0;
+
+  for (;;) {
+    // Grab next partition to scan
+    size_t partition_begin = claim_table_partition(partition_size);
+    size_t partition_end = partition_begin + partition_size;
+    if (partition_begin >= table_half) {
+      // End of table
+      break;
+    }
+
+    // Scan the partition followed by the sibling partition in the second half of the table
+    removed += unlink_or_oops_do(cl, partition_begin, partition_end, worker_id);
+    removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id);
+  }
+
+  // Delayed update to avoid contention on the table lock
+  if (removed > 0) {
+    MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
+    _table->_entries -= removed;
+    _entries_removed += removed;
+  }
+}
+
+uintx StringDedupTable::unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl,
+                                          size_t partition_begin,
+                                          size_t partition_end,
+                                          uint worker_id) {
+  uintx removed = 0;
+  for (size_t bucket = partition_begin; bucket < partition_end; bucket++) {
+    StringDedupEntry** entry = _table->bucket(bucket);
+    while (*entry != NULL) {
+      oop* p = (oop*)(*entry)->obj_addr();
+      if (cl->is_alive(*p)) {
+        cl->keep_alive(p);
+        if (is_resizing()) {
+          // We are resizing the table, transfer entry to the new table
+          _table->transfer(entry, _resized_table);
+        } else {
+          if (is_rehashing()) {
+            // We are rehashing the table, rehash the entry but keep it
+            // in the table. We can't transfer entries into the new table
+            // at this point since we don't have exclusive access to all
+            // destination partitions. finish_rehash() will do a single
+            // threaded transfer of all entries.
+            typeArrayOop value = (typeArrayOop)*p;
+            bool latin1 = (*entry)->latin1();
+            unsigned int hash = hash_code(value, latin1);
+            (*entry)->set_hash(hash);
+          }
+
+          // Move to next entry
+          entry = (*entry)->next_addr();
+        }
+      } else {
+        // Not alive, remove entry from table
+        _table->remove(entry, worker_id);
+        removed++;
+      }
+    }
+  }
+
+  return removed;
+}
+
+void StringDedupTable::gc_prologue(bool resize_and_rehash_table) {
+  assert(!is_resizing() && !is_rehashing(), "Already in progress?");
+
+  _claimed_index = 0;
+  if (resize_and_rehash_table) {
+    // If both resize and rehash is needed, only do resize. Rehash of
+    // the table will eventually happen if the situation persists.
+    _resized_table = StringDedupTable::prepare_resize();
+    if (!is_resizing()) {
+      _rehashed_table = StringDedupTable::prepare_rehash();
+    }
+  }
+}
+
+void StringDedupTable::gc_epilogue() {
+  assert(!is_resizing() || !is_rehashing(), "Can not both resize and rehash");
+  assert(_claimed_index >= _table->_size / 2 || _claimed_index == 0, "All or nothing");
+
+  if (is_resizing()) {
+    StringDedupTable::finish_resize(_resized_table);
+    _resized_table = NULL;
+  } else if (is_rehashing()) {
+    StringDedupTable::finish_rehash(_rehashed_table);
+    _rehashed_table = NULL;
+  }
+}
+
+StringDedupTable* StringDedupTable::prepare_rehash() {
+  if (!_table->_rehash_needed && !StringDeduplicationRehashALot) {
+    // Rehash not needed
+    return NULL;
+  }
+
+  // Update statistics
+  _rehash_count++;
+
+  // Compute new hash seed
+  _table->_hash_seed = AltHashing::compute_seed();
+
+  // Allocate the new table, same size and hash seed
+  return new StringDedupTable(_table->_size, _table->_hash_seed);
+}
+
+void StringDedupTable::finish_rehash(StringDedupTable* rehashed_table) {
+  assert(rehashed_table != NULL, "Invalid table");
+
+  // Move all newly rehashed entries into the correct buckets in the new table
+  for (size_t bucket = 0; bucket < _table->_size; bucket++) {
+    StringDedupEntry** entry = _table->bucket(bucket);
+    while (*entry != NULL) {
+      _table->transfer(entry, rehashed_table);
+    }
+  }
+
+  rehashed_table->_entries = _table->_entries;
+
+  // Free old table
+  delete _table;
+
+  // Install new table
+  _table = rehashed_table;
+}
+
+size_t StringDedupTable::claim_table_partition(size_t partition_size) {
+  return Atomic::add(partition_size, &_claimed_index) - partition_size;
+}
+
+void StringDedupTable::verify() {
+  for (size_t bucket = 0; bucket < _table->_size; bucket++) {
+    // Verify entries
+    StringDedupEntry** entry = _table->bucket(bucket);
+    while (*entry != NULL) {
+      typeArrayOop value = (*entry)->obj();
+      guarantee(value != NULL, "Object must not be NULL");
+      guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap");
+      guarantee(!value->is_forwarded(), "Object must not be forwarded");
+      guarantee(value->is_typeArray(), "Object must be a typeArrayOop");
+      bool latin1 = (*entry)->latin1();
+      unsigned int hash = hash_code(value, latin1);
+      guarantee((*entry)->hash() == hash, "Table entry has inorrect hash");
+      guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index");
+      entry = (*entry)->next_addr();
+    }
+
+    // Verify that we do not have entries with identical oops or identical arrays.
+    // We only need to compare entries in the same bucket. If the same oop or an
+    // identical array has been inserted more than once into different/incorrect
+    // buckets the verification step above will catch that.
+    StringDedupEntry** entry1 = _table->bucket(bucket);
+    while (*entry1 != NULL) {
+      typeArrayOop value1 = (*entry1)->obj();
+      bool latin1_1 = (*entry1)->latin1();
+      StringDedupEntry** entry2 = (*entry1)->next_addr();
+      while (*entry2 != NULL) {
+        typeArrayOop value2 = (*entry2)->obj();
+        bool latin1_2 = (*entry2)->latin1();
+        guarantee(latin1_1 != latin1_2 || !equals(value1, value2), "Table entries must not have identical arrays");
+        entry2 = (*entry2)->next_addr();
+      }
+      entry1 = (*entry1)->next_addr();
+    }
+  }
+}
+
+void StringDedupTable::clean_entry_cache() {
+  _entry_cache->delete_overflowed();
+}
+
+void StringDedupTable::print_statistics() {
+  Log(gc, stringdedup) log;
+  log.debug("  Table");
+  log.debug("    Memory Usage: " STRDEDUP_BYTES_FORMAT_NS,
+            STRDEDUP_BYTES_PARAM(_table->_size * sizeof(StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(StringDedupEntry)));
+  log.debug("    Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT, _table->_size, _min_size, _max_size);
+  log.debug("    Entries: " UINTX_FORMAT ", Load: " STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT,
+            _table->_entries, percent_of(_table->_entries, _table->_size), _entry_cache->size(), _entries_added, _entries_removed);
+  log.debug("    Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" STRDEDUP_PERCENT_FORMAT_NS ")",
+            _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0);
+  log.debug("    Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x", _rehash_count, _rehash_threshold, _table->_hash_seed);
+  log.debug("    Age Threshold: " UINTX_FORMAT, StringDeduplicationAgeThreshold);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP
+
+#include "gc/shared/stringdedup/stringDedupStat.hpp"
+#include "runtime/mutexLocker.hpp"
+
+class StringDedupEntryCache;
+class StringDedupUnlinkOrOopsDoClosure;
+
+//
+// Table entry in the deduplication hashtable. Points weakly to the
+// character array. Can be chained in a linked list in case of hash
+// collisions or when placed in a freelist in the entry cache.
+//
+class StringDedupEntry : public CHeapObj<mtGC> {
+private:
+  StringDedupEntry* _next;
+  unsigned int      _hash;
+  bool              _latin1;
+  typeArrayOop      _obj;
+
+public:
+  StringDedupEntry() :
+    _next(NULL),
+    _hash(0),
+    _latin1(false),
+    _obj(NULL) {
+  }
+
+  StringDedupEntry* next() {
+    return _next;
+  }
+
+  StringDedupEntry** next_addr() {
+    return &_next;
+  }
+
+  void set_next(StringDedupEntry* next) {
+    _next = next;
+  }
+
+  unsigned int hash() {
+    return _hash;
+  }
+
+  void set_hash(unsigned int hash) {
+    _hash = hash;
+  }
+
+  bool latin1() {
+    return _latin1;
+  }
+
+  void set_latin1(bool latin1) {
+    _latin1 = latin1;
+  }
+
+  typeArrayOop obj() {
+    return _obj;
+  }
+
+  typeArrayOop* obj_addr() {
+    return &_obj;
+  }
+
+  void set_obj(typeArrayOop obj) {
+    _obj = obj;
+  }
+};
+
+//
+// The deduplication hashtable keeps track of all unique character arrays used
+// by String objects. Each table entry weakly points to an character array, allowing
+// otherwise unreachable character arrays to be declared dead and pruned from the
+// table.
+//
+// The table is dynamically resized to accommodate the current number of table entries.
+// The table has hash buckets with chains for hash collision. If the average chain
+// length goes above or below given thresholds the table grows or shrinks accordingly.
+//
+// The table is also dynamically rehashed (using a new hash seed) if it becomes severely
+// unbalanced, i.e., a hash chain is significantly longer than average.
+//
+// All access to the table is protected by the StringDedupTable_lock, except under
+// safepoints in which case GC workers are allowed to access a table partitions they
+// have claimed without first acquiring the lock. Note however, that this applies only
+// the table partition (i.e. a range of elements in _buckets), not other parts of the
+// table such as the _entries field, statistics counters, etc.
+//
+class StringDedupTable : public CHeapObj<mtGC> {
+private:
+  // The currently active hashtable instance. Only modified when
+  // the table is resizes or rehashed.
+  static StringDedupTable*        _table;
+
+  // Cache for reuse and fast alloc/free of table entries.
+  static StringDedupEntryCache*   _entry_cache;
+
+  StringDedupEntry**              _buckets;
+  size_t                          _size;
+  uintx                           _entries;
+  uintx                           _shrink_threshold;
+  uintx                           _grow_threshold;
+  bool                            _rehash_needed;
+
+  // The hash seed also dictates which hash function to use. A
+  // zero hash seed means we will use the Java compatible hash
+  // function (which doesn't use a seed), and a non-zero hash
+  // seed means we use the murmur3 hash function.
+  jint                            _hash_seed;
+
+  // Constants governing table resize/rehash/cache.
+  static const size_t             _min_size;
+  static const size_t             _max_size;
+  static const double             _grow_load_factor;
+  static const double             _shrink_load_factor;
+  static const uintx              _rehash_multiple;
+  static const uintx              _rehash_threshold;
+  static const double             _max_cache_factor;
+
+  // Table statistics, only used for logging.
+  static uintx                    _entries_added;
+  static uintx                    _entries_removed;
+  static uintx                    _resize_count;
+  static uintx                    _rehash_count;
+
+  static volatile size_t          _claimed_index;
+
+  static StringDedupTable*        _resized_table;
+  static StringDedupTable*        _rehashed_table;
+
+  StringDedupTable(size_t size, jint hash_seed = 0);
+  ~StringDedupTable();
+
+  // Returns the hash bucket at the given index.
+  StringDedupEntry** bucket(size_t index) {
+    return _buckets + index;
+  }
+
+  // Returns the hash bucket index for the given hash code.
+  size_t hash_to_index(unsigned int hash) {
+    return (size_t)hash & (_size - 1);
+  }
+
+  // Adds a new table entry to the given hash bucket.
+  void add(typeArrayOop value, bool latin1, unsigned int hash, StringDedupEntry** list);
+
+  // Removes the given table entry from the table.
+  void remove(StringDedupEntry** pentry, uint worker_id);
+
+  // Transfers a table entry from the current table to the destination table.
+  void transfer(StringDedupEntry** pentry, StringDedupTable* dest);
+
+  // Returns an existing character array in the given hash bucket, or NULL
+  // if no matching character array exists.
+  typeArrayOop lookup(typeArrayOop value, bool latin1, unsigned int hash,
+                      StringDedupEntry** list, uintx &count);
+
+  // Returns an existing character array in the table, or inserts a new
+  // table entry if no matching character array exists.
+  typeArrayOop lookup_or_add_inner(typeArrayOop value, bool latin1, unsigned int hash);
+
+  // Thread safe lookup or add of table entry
+  static typeArrayOop lookup_or_add(typeArrayOop value, bool latin1, unsigned int hash) {
+    // Protect the table from concurrent access. Also note that this lock
+    // acts as a fence for _table, which could have been replaced by a new
+    // instance if the table was resized or rehashed.
+    MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
+    return _table->lookup_or_add_inner(value, latin1, hash);
+  }
+
+  // Returns true if the hashtable is currently using a Java compatible
+  // hash function.
+  static bool use_java_hash() {
+    return _table->_hash_seed == 0;
+  }
+
+  static bool equals(typeArrayOop value1, typeArrayOop value2);
+
+  // Computes the hash code for the given character array, using the
+  // currently active hash function and hash seed.
+  static unsigned int hash_code(typeArrayOop value, bool latin1);
+
+  static uintx unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl,
+                                 size_t partition_begin,
+                                 size_t partition_end,
+                                 uint worker_id);
+
+  static size_t claim_table_partition(size_t partition_size);
+
+  static bool is_resizing();
+  static bool is_rehashing();
+
+  // If a table resize is needed, returns a newly allocated empty
+  // hashtable of the proper size.
+  static StringDedupTable* prepare_resize();
+
+  // Installs a newly resized table as the currently active table
+  // and deletes the previously active table.
+  static void finish_resize(StringDedupTable* resized_table);
+
+  // If a table rehash is needed, returns a newly allocated empty
+  // hashtable and updates the hash seed.
+  static StringDedupTable* prepare_rehash();
+
+  // Transfers rehashed entries from the currently active table into
+  // the new table. Installs the new table as the currently active table
+  // and deletes the previously active table.
+  static void finish_rehash(StringDedupTable* rehashed_table);
+
+public:
+  static void create();
+
+  // Deduplicates the given String object, or adds its backing
+  // character array to the deduplication hashtable.
+  static void deduplicate(oop java_string, StringDedupStat* stat);
+
+  static void unlink_or_oops_do(StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id);
+
+  static void print_statistics();
+  static void verify();
+
+  // If the table entry cache has grown too large, delete overflowed entries.
+  static void clean_entry_cache();
+
+  // GC support
+  static void gc_prologue(bool resize_and_rehash_table);
+  static void gc_epilogue();
+};
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/stringTable.hpp"
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.inline.hpp"
+#include "gc/shared/stringdedup/stringDedupTable.hpp"
+#include "gc/shared/stringdedup/stringDedupThread.hpp"
+#include "gc/shared/suspendibleThreadSet.hpp"
+#include "logging/log.hpp"
+#include "oops/access.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
+
+StringDedupThread* StringDedupThread::_thread = NULL;
+
+StringDedupThread::StringDedupThread() :
+  ConcurrentGCThread() {
+  set_name("StrDedup");
+  create_and_start();
+}
+
+StringDedupThread::~StringDedupThread() {
+  ShouldNotReachHere();
+}
+
+StringDedupThread* StringDedupThread::thread() {
+  assert(_thread != NULL, "String deduplication thread not created");
+  return _thread;
+}
+
+class StringDedupSharedClosure: public OopClosure {
+ private:
+  StringDedupStat* _stat;
+
+ public:
+  StringDedupSharedClosure(StringDedupStat* stat) : _stat(stat) {}
+
+  virtual void do_oop(oop* p) { ShouldNotReachHere(); }
+  virtual void do_oop(narrowOop* p) {
+    oop java_string = RawAccess<>::oop_load(p);
+    StringDedupTable::deduplicate(java_string, _stat);
+  }
+};
+
+// The CDS archive does not include the string dedupication table. Only the string
+// table is saved in the archive. The shared strings from CDS archive need to be
+// added to the string dedupication table before deduplication occurs. That is
+// done in the begining of the StringDedupThread (see StringDedupThread::do_deduplication()).
+void StringDedupThread::deduplicate_shared_strings(StringDedupStat* stat) {
+  StringDedupSharedClosure sharedStringDedup(stat);
+  StringTable::shared_oops_do(&sharedStringDedup);
+}
+
+void StringDedupThread::stop_service() {
+  StringDedupQueue::cancel_wait();
+}
+
+void StringDedupThread::print_start(const StringDedupStat* last_stat) {
+  StringDedupStat::print_start(last_stat);
+}
+
+void StringDedupThread::print_end(const StringDedupStat* last_stat, const StringDedupStat* total_stat) {
+  StringDedupStat::print_end(last_stat, total_stat);
+  if (log_is_enabled(Debug, gc, stringdedup)) {
+    last_stat->print_statistics(false);
+    total_stat->print_statistics(true);
+
+    StringDedupTable::print_statistics();
+    StringDedupQueue::print_statistics();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTHREAD_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTHREAD_HPP
+
+#include "gc/shared/concurrentGCThread.hpp"
+#include "gc/shared/stringdedup/stringDedupStat.hpp"
+
+//
+// The deduplication thread is where the actual deduplication occurs. It waits for
+// deduplication candidates to appear on the deduplication queue, removes them from
+// the queue and tries to deduplicate them. It uses the deduplication hashtable to
+// find identical, already existing, character arrays on the heap. The thread runs
+// concurrently with the Java application but participates in safepoints to allow
+// the GC to adjust and unlink oops from the deduplication queue and table.
+//
+class StringDedupThread: public ConcurrentGCThread {
+protected:
+  static StringDedupThread* _thread;
+
+  StringDedupThread();
+  ~StringDedupThread();
+
+  void print_start(const StringDedupStat* last_stat);
+  void print_end(const StringDedupStat* last_stat, const StringDedupStat* total_stat);
+
+  void run_service() { this->do_deduplication(); }
+  void stop_service();
+
+  void deduplicate_shared_strings(StringDedupStat* stat);
+protected:
+  virtual void do_deduplication() = 0;
+
+public:
+  static StringDedupThread* thread();
+};
+
+template <typename S>
+class StringDedupThreadImpl : public StringDedupThread {
+private:
+  StringDedupThreadImpl() { }
+
+protected:
+  void do_deduplication();
+
+public:
+  static void create();
+};
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTHREAD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.inline.hpp	Thu Jun 14 09:59:21 2018 -0400
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTHREAD_INLINE_HPP
+#define SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTHREAD_INLINE_HPP
+
+#include "gc/shared/suspendibleThreadSet.hpp"
+#include "gc/shared/stringdedup/stringDedupQueue.inline.hpp"
+#include "gc/shared/stringdedup/stringDedupThread.hpp"
+
+template <typename S>
+void StringDedupThreadImpl<S>::do_deduplication() {
+  S total_stat;
+
+  deduplicate_shared_strings(&total_stat);
+
+  // Main loop
+  for (;;) {
+    S stat;
+
+    stat.mark_idle();
+
+    // Wait for the queue to become non-empty
+    StringDedupQueue::wait();
+    if (this->should_terminate()) {
+      break;
+    }
+
+    {
+      // Include thread in safepoints
+      SuspendibleThreadSetJoiner sts_join;
+
+      stat.mark_exec();
+      StringDedupStat::print_start(&stat);
+
+      // Process the queue
+      for (;;) {
+        oop java_string = StringDedupQueue::pop();
+        if (java_string == NULL) {
+          break;
+        }
+
+        StringDedupTable::deduplicate(java_string, &stat);
+
+        // Safepoint this thread if needed
+        if (sts_join.should_yield()) {
+          stat.mark_block();
+          sts_join.yield();
+          stat.mark_unblock();
+        }
+      }
+
+      stat.mark_done();
+
+      total_stat.add(&stat);
+      print_end(&stat, &total_stat);
+      stat.reset();
+    }
+
+    StringDedupTable::clean_entry_cache();
+  }
+}
+
+template <typename S>
+void StringDedupThreadImpl<S>::create() {
+  assert(_thread == NULL, "One string deduplication thread allowed");
+  _thread = new StringDedupThreadImpl<S>();
+}
+
+#endif // SHARE_VM_GC_SHARED_STRINGDEDUP_STRINGDEDUPTHREAD_INLINE_HPP