changeset 52289:b9f6a4427da9

8072498: Multi-thread JNI weak reference processing Summary: Add parallel processing support to WeakProcessor. Reviewed-by: tschatzl, sjohanss
author kbarrett
date Tue, 28 Aug 2018 12:57:40 -0400
parents 29517169ad2d
children 2b004d807187
files src/hotspot/share/gc/g1/g1CollectedHeap.cpp src/hotspot/share/gc/g1/g1ConcurrentMark.cpp src/hotspot/share/gc/g1/g1FullCollector.cpp src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp src/hotspot/share/gc/g1/g1RootProcessor.cpp src/hotspot/share/gc/g1/g1RootProcessor.hpp src/hotspot/share/gc/shared/weakProcessor.cpp src/hotspot/share/gc/shared/weakProcessor.hpp src/hotspot/share/gc/shared/weakProcessor.inline.hpp src/hotspot/share/gc/shared/weakProcessorPhaseTimes.cpp src/hotspot/share/gc/shared/weakProcessorPhaseTimes.hpp src/hotspot/share/gc/shared/weakProcessorPhases.cpp src/hotspot/share/gc/shared/weakProcessorPhases.hpp src/hotspot/share/gc/shared/workgroup.cpp
diffstat 17 files changed, 863 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -75,7 +75,7 @@
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "gc/shared/referenceProcessor.inline.hpp"
 #include "gc/shared/taskqueue.inline.hpp"
-#include "gc/shared/weakProcessor.hpp"
+#include "gc/shared/weakProcessor.inline.hpp"
 #include "logging/log.hpp"
 #include "memory/allocation.hpp"
 #include "memory/iterator.hpp"
@@ -3719,14 +3719,8 @@
   G1STWIsAliveClosure is_alive(this);
   G1KeepAliveClosure keep_alive(this);
 
-  {
-    double start = os::elapsedTime();
-
-    WeakProcessor::weak_oops_do(&is_alive, &keep_alive);
-
-    double time_ms = (os::elapsedTime() - start) * 1000.0;
-    g1_policy()->phase_times()->record_weak_ref_proc_time(time_ms);
-  }
+  WeakProcessor::weak_oops_do(workers(), &is_alive, &keep_alive,
+                              g1_policy()->phase_times()->weak_phase_times());
 
   if (G1StringDedup::is_enabled()) {
     double fixup_start = os::elapsedTime();
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -50,7 +50,7 @@
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "gc/shared/taskqueue.inline.hpp"
 #include "gc/shared/vmGCOperations.hpp"
-#include "gc/shared/weakProcessor.hpp"
+#include "gc/shared/weakProcessor.inline.hpp"
 #include "include/jvm.h"
 #include "logging/log.hpp"
 #include "memory/allocation.hpp"
@@ -1669,7 +1669,7 @@
 
   {
     GCTraceTime(Debug, gc, phases) debug("Weak Processing", _gc_timer_cm);
-    WeakProcessor::weak_oops_do(&g1_is_alive, &do_nothing_cl);
+    WeakProcessor::weak_oops_do(_g1h->workers(), &g1_is_alive, &do_nothing_cl, 1);
   }
 
   // Unload Klasses, String, Code Cache, etc.
--- a/src/hotspot/share/gc/g1/g1FullCollector.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -41,7 +41,7 @@
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/preservedMarks.hpp"
 #include "gc/shared/referenceProcessor.hpp"
-#include "gc/shared/weakProcessor.hpp"
+#include "gc/shared/weakProcessor.inline.hpp"
 #include "logging/log.hpp"
 #include "runtime/biasedLocking.hpp"
 #include "runtime/handles.inline.hpp"
@@ -214,8 +214,8 @@
 
   // Weak oops cleanup.
   {
-    GCTraceTime(Debug, gc, phases) trace("Phase 1: Weak Processing", scope()->timer());
-    WeakProcessor::weak_oops_do(&_is_alive, &do_nothing_cl);
+    GCTraceTime(Debug, gc, phases) debug("Phase 1: Weak Processing", scope()->timer());
+    WeakProcessor::weak_oops_do(_heap->workers(), &_is_alive, &do_nothing_cl, 1);
   }
 
   // Class unloading and cleanup.
--- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -33,8 +33,10 @@
 #include "gc/g1/heapRegion.inline.hpp"
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/referenceProcessor.hpp"
+#include "gc/shared/weakProcessor.inline.hpp"
 #include "logging/log.hpp"
 #include "memory/iterator.inline.hpp"
+#include "runtime/atomic.hpp"
 
 class G1AdjustLiveClosure : public StackObj {
   G1AdjustClosure* _adjust_closure;
@@ -79,6 +81,8 @@
 G1FullGCAdjustTask::G1FullGCAdjustTask(G1FullCollector* collector) :
     G1FullGCTask("G1 Adjust", collector),
     _root_processor(G1CollectedHeap::heap(), collector->workers()),
+    _references_done(0),
+    _weak_proc_task(collector->workers()),
     _hrclaimer(collector->workers()),
     _adjust(),
     _adjust_string_dedup(NULL, &_adjust, G1StringDedup::is_enabled()) {
@@ -94,12 +98,17 @@
   G1FullGCMarker* marker = collector()->marker(worker_id);
   marker->preserved_stack()->adjust_during_full_gc();
 
-  // Adjust the weak_roots.
+  // Adjust the weak roots.
+
+  if (Atomic::add(1u, &_references_done) == 1u) { // First incr claims task.
+    G1CollectedHeap::heap()->ref_processor_stw()->weak_oops_do(&_adjust);
+  }
+
+  AlwaysTrueClosure always_alive;
+  _weak_proc_task.work(worker_id, &always_alive, &_adjust);
+
   CLDToOopClosure adjust_cld(&_adjust);
   CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations);
-  _root_processor.process_full_gc_weak_roots(&_adjust);
-
-  // Needs to be last, process_all_roots calls all_tasks_completed(...).
   _root_processor.process_all_roots(
       &_adjust,
       &adjust_cld,
--- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -30,12 +30,16 @@
 #include "gc/g1/g1RootProcessor.hpp"
 #include "gc/g1/g1StringDedup.hpp"
 #include "gc/g1/heapRegionManager.hpp"
+#include "gc/shared/weakProcessorPhaseTimes.hpp"
+#include "gc/shared/weakProcessor.hpp"
 #include "utilities/ticks.hpp"
 
 class G1CollectedHeap;
 
 class G1FullGCAdjustTask : public G1FullGCTask {
   G1RootProcessor          _root_processor;
+  volatile uint            _references_done; // Atomic counter / bool
+  WeakProcessor::Task      _weak_proc_task;
   HeapRegionClaimer        _hrclaimer;
   G1AdjustClosure          _adjust;
   G1StringDedupUnlinkOrOopsDoClosure _adjust_string_dedup;
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -28,6 +28,7 @@
 #include "gc/g1/g1HotCardCache.hpp"
 #include "gc/g1/g1ParScanThreadState.inline.hpp"
 #include "gc/g1/g1StringDedup.hpp"
+#include "gc/shared/gcTimer.hpp"
 #include "gc/shared/workerDataArray.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "logging/log.hpp"
@@ -42,7 +43,8 @@
   _max_gc_threads(max_gc_threads),
   _gc_start_counter(0),
   _gc_pause_time_ms(0.0),
-  _ref_phase_times((GCTimer*)gc_timer, max_gc_threads)
+  _ref_phase_times(gc_timer, max_gc_threads),
+  _weak_phase_times(max_gc_threads)
 {
   assert(max_gc_threads > 0, "Must have some GC threads");
 
@@ -129,7 +131,6 @@
   _cur_clear_ct_time_ms = 0.0;
   _cur_expand_heap_time_ms = 0.0;
   _cur_ref_proc_time_ms = 0.0;
-  _cur_weak_ref_proc_time_ms = 0.0;
   _cur_collection_start_sec = 0.0;
   _root_region_scan_wait_time_ms = 0.0;
   _external_accounted_time_ms = 0.0;
@@ -157,6 +158,7 @@
   }
 
   _ref_phase_times.reset();
+  _weak_phase_times.reset();
 }
 
 void G1GCPhaseTimes::note_gc_start() {
@@ -381,7 +383,7 @@
                         _cur_collection_code_root_fixup_time_ms +
                         _recorded_preserve_cm_referents_time_ms +
                         _cur_ref_proc_time_ms +
-                        _cur_weak_ref_proc_time_ms +
+                        (_weak_phase_times.total_time_sec() * MILLIUNITS) +
                         _cur_clear_ct_time_ms +
                         _recorded_merge_pss_time_ms +
                         _cur_strong_code_root_purge_time_ms +
@@ -399,8 +401,7 @@
 
   debug_time_for_reference("Reference Processing", _cur_ref_proc_time_ms);
   _ref_phase_times.print_all_references(2, false);
-
-  debug_time("Weak Processing", _cur_weak_ref_proc_time_ms);
+  _weak_phase_times.log_print(2);
 
   if (G1StringDedup::is_enabled()) {
     debug_time("String Dedup Fixup", _cur_string_dedup_fixup_time_ms);
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_G1_G1GCPHASETIMES_HPP
 
 #include "gc/shared/referenceProcessorPhaseTimes.hpp"
+#include "gc/shared/weakProcessorPhaseTimes.hpp"
 #include "logging/logLevel.hpp"
 #include "memory/allocation.hpp"
 #include "utilities/macros.hpp"
@@ -127,9 +128,6 @@
   double _cur_clear_ct_time_ms;
   double _cur_expand_heap_time_ms;
   double _cur_ref_proc_time_ms;
-  double _cur_ref_enq_time_ms;
-
-  double _cur_weak_ref_proc_time_ms;
 
   double _cur_collection_start_sec;
   double _root_region_scan_wait_time_ms;
@@ -163,6 +161,7 @@
   double _cur_verify_after_time_ms;
 
   ReferenceProcessorPhaseTimes _ref_phase_times;
+  WeakProcessorPhaseTimes _weak_phase_times;
 
   double worker_time(GCParPhases phase, uint worker);
   void note_gc_end();
@@ -257,10 +256,6 @@
     _cur_ref_proc_time_ms = ms;
   }
 
-  void record_weak_ref_proc_time(double ms) {
-    _cur_weak_ref_proc_time_ms = ms;
-  }
-
   void record_root_region_scan_wait_time(double time_ms) {
     _root_region_scan_wait_time_ms = time_ms;
   }
@@ -365,6 +360,8 @@
   }
 
   ReferenceProcessorPhaseTimes* ref_phase_times() { return &_ref_phase_times; }
+
+  WeakProcessorPhaseTimes* weak_phase_times() { return &_weak_phase_times; }
 };
 
 class G1EvacPhaseWithTrimTimeTracker : public StackObj {
--- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -40,7 +40,6 @@
 #include "gc/g1/heapRegion.inline.hpp"
 #include "gc/shared/oopStorageParState.hpp"
 #include "gc/shared/referenceProcessor.hpp"
-#include "gc/shared/weakProcessor.hpp"
 #include "memory/allocation.inline.hpp"
 #include "runtime/mutex.hpp"
 #include "services/management.hpp"
@@ -314,16 +313,6 @@
   }
 }
 
-void G1RootProcessor::process_full_gc_weak_roots(OopClosure* oops) {
-  if (!_process_strong_tasks.is_task_claimed(G1RP_PS_refProcessor_oops_do)) {
-    _g1h->ref_processor_stw()->weak_oops_do(oops);
-  }
-
-  if (!_process_strong_tasks.is_task_claimed(G1RP_PS_weakProcessor_oops_do)) {
-    WeakProcessor::oops_do(oops);
-  }
-}
-
 uint G1RootProcessor::n_workers() const {
   return _srs.n_threads();
 }
--- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -68,7 +68,6 @@
     G1RP_PS_aot_oops_do,
     G1RP_PS_filter_satb_buffers,
     G1RP_PS_refProcessor_oops_do,
-    G1RP_PS_weakProcessor_oops_do,
     // Leave this one last.
     G1RP_PS_NumElements
   };
@@ -122,10 +121,6 @@
                                          CLDClosure* clds,
                                          CodeBlobClosure* blobs);
 
-  // Apply closure to weak roots in the system. Used during the adjust phase
-  // for the Full GC.
-  void process_full_gc_weak_roots(OopClosure* oops);
-
   // Number of worker threads used by the root processor.
   uint n_workers() const;
 };
--- a/src/hotspot/share/gc/shared/weakProcessor.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/shared/weakProcessor.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -23,24 +23,107 @@
  */
 
 #include "precompiled.hpp"
-#include "classfile/systemDictionary.hpp"
 #include "gc/shared/oopStorage.inline.hpp"
+#include "gc/shared/oopStorageParState.inline.hpp"
 #include "gc/shared/weakProcessor.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "runtime/jniHandles.hpp"
+#include "gc/shared/weakProcessor.inline.hpp"
+#include "gc/shared/weakProcessorPhases.hpp"
+#include "gc/shared/weakProcessorPhaseTimes.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/iterator.hpp"
+#include "runtime/globals.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_JFR
-#include "jfr/jfr.hpp"
-#endif
 
 void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
-  JNIHandles::weak_oops_do(is_alive, keep_alive);
-  JvmtiExport::weak_oops_do(is_alive, keep_alive);
-  SystemDictionary::vm_weak_oop_storage()->weak_oops_do(is_alive, keep_alive);
-  JFR_ONLY(Jfr::weak_oops_do(is_alive, keep_alive);)
+  FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
+    if (WeakProcessorPhases::is_serial(phase)) {
+      WeakProcessorPhases::processor(phase)(is_alive, keep_alive);
+    } else {
+      WeakProcessorPhases::oop_storage(phase)->weak_oops_do(is_alive, keep_alive);
+    }
+  }
 }
 
 void WeakProcessor::oops_do(OopClosure* closure) {
   AlwaysTrueClosure always_true;
   weak_oops_do(&always_true, closure);
 }
+
+uint WeakProcessor::ergo_workers(uint max_workers) {
+  // Ignore ParallelRefProcEnabled; that's for j.l.r.Reference processing.
+  if (ReferencesPerThread == 0) {
+    // Configuration says always use all the threads.
+    return max_workers;
+  }
+
+  // One thread per ReferencesPerThread references (or fraction thereof)
+  // in the various OopStorage objects, bounded by max_threads.
+  //
+  // Serial phases are ignored in this calculation, because of the
+  // cost of running unnecessary threads.  These phases are normally
+  // small or empty (assuming they are configured to exist at all),
+  // and development oriented, so not allocating any threads
+  // specifically for them is okay.
+  size_t ref_count = 0;
+  FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) {
+    ref_count += WeakProcessorPhases::oop_storage(phase)->allocation_count();
+  }
+
+  // +1 to (approx) round up the ref per thread division.
+  size_t nworkers = 1 + (ref_count / ReferencesPerThread);
+  nworkers = MIN2(nworkers, static_cast<size_t>(max_workers));
+  return static_cast<uint>(nworkers);
+}
+
+void WeakProcessor::Task::initialize() {
+  assert(_nworkers != 0, "must be");
+  assert(_phase_times == NULL || _nworkers <= _phase_times->max_threads(),
+         "nworkers (%u) exceeds max threads (%u)",
+         _nworkers, _phase_times->max_threads());
+
+  if (_phase_times) {
+    _phase_times->set_active_workers(_nworkers);
+  }
+
+  uint storage_count = WeakProcessorPhases::oop_storage_phase_count;
+  _storage_states = NEW_C_HEAP_ARRAY(StorageState, storage_count, mtGC);
+
+  StorageState* states = _storage_states;
+  FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) {
+    OopStorage* storage = WeakProcessorPhases::oop_storage(phase);
+    new (states++) StorageState(storage, _nworkers);
+  }
+}
+
+WeakProcessor::Task::Task(uint nworkers) :
+  _phase_times(NULL),
+  _nworkers(nworkers),
+  _serial_phases_done(WeakProcessorPhases::serial_phase_count),
+  _storage_states(NULL)
+{
+  initialize();
+}
+
+WeakProcessor::Task::Task(WeakProcessorPhaseTimes* phase_times, uint nworkers) :
+  _phase_times(phase_times),
+  _nworkers(nworkers),
+  _serial_phases_done(WeakProcessorPhases::serial_phase_count),
+  _storage_states(NULL)
+{
+  initialize();
+}
+
+WeakProcessor::Task::~Task() {
+  if (_storage_states != NULL) {
+    StorageState* states = _storage_states;
+    FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) {
+      states->StorageState::~StorageState();
+      ++states;
+    }
+    FREE_C_HEAP_ARRAY(StorageState, _storage_states);
+  }
+}
+
+void WeakProcessor::GangTask::work(uint worker_id) {
+  _erased_do_work(this, worker_id);
+}
--- a/src/hotspot/share/gc/shared/weakProcessor.hpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/shared/weakProcessor.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -25,8 +25,12 @@
 #ifndef SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP
 #define SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP
 
+#include "gc/shared/oopStorageParState.hpp"
+#include "gc/shared/workgroup.hpp"
 #include "memory/allocation.hpp"
-#include "memory/iterator.hpp"
+
+class WeakProcessorPhaseTimes;
+class WorkGang;
 
 // Helper class to aid in root scanning and cleaning of weak oops in the VM.
 //
@@ -41,6 +45,51 @@
 
   // Visit all oop*s and apply the given closure.
   static void oops_do(OopClosure* closure);
+
+  // Parallel version.  Uses ergo_workers(), active workers, and
+  // phase_time's max_threads to determine the number of threads to use.
+  // IsAlive must be derived from BoolObjectClosure.
+  // KeepAlive must be derived from OopClosure.
+  template<typename IsAlive, typename KeepAlive>
+  static void weak_oops_do(WorkGang* workers,
+                           IsAlive* is_alive,
+                           KeepAlive* keep_alive,
+                           WeakProcessorPhaseTimes* phase_times);
+
+  // Convenience parallel version.  Uses ergo_workers() and active workers
+  // to determine the number of threads to run.  Implicitly logs phase times.
+  // IsAlive must be derived from BoolObjectClosure.
+  // KeepAlive must be derived from OopClosure.
+  template<typename IsAlive, typename KeepAlive>
+  static void weak_oops_do(WorkGang* workers,
+                           IsAlive* is_alive,
+                           KeepAlive* keep_alive,
+                           uint indent_log);
+
+  static uint ergo_workers(uint max_workers);
+  class Task;
+
+private:
+  class GangTask;
+};
+
+class WeakProcessor::Task {
+  typedef OopStorage::ParState<false, false> StorageState;
+
+  WeakProcessorPhaseTimes* _phase_times;
+  uint _nworkers;
+  SubTasksDone _serial_phases_done;
+  StorageState* _storage_states;
+
+  void initialize();
+
+public:
+  Task(uint nworkers);          // No time tracking.
+  Task(WeakProcessorPhaseTimes* phase_times, uint nworkers);
+  ~Task();
+
+  template<typename IsAlive, typename KeepAlive>
+  void work(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive);
 };
 
 #endif // SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/weakProcessor.inline.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -0,0 +1,119 @@
+/*
+ * 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_WEAKPROCESSOR_INLINE_HPP
+#define SHARE_VM_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
+
+#include "gc/shared/oopStorage.inline.hpp"
+#include "gc/shared/oopStorageParState.inline.hpp"
+#include "gc/shared/weakProcessor.hpp"
+#include "gc/shared/weakProcessorPhases.hpp"
+#include "gc/shared/weakProcessorPhaseTimes.hpp"
+#include "gc/shared/workgroup.hpp"
+#include "utilities/debug.hpp"
+
+class BoolObjectClosure;
+class OopClosure;
+
+template<typename IsAlive, typename KeepAlive>
+void WeakProcessor::Task::work(uint worker_id,
+                               IsAlive* is_alive,
+                               KeepAlive* keep_alive) {
+  assert(worker_id < _nworkers,
+         "worker_id (%u) exceeds task's configured workers (%u)",
+         worker_id, _nworkers);
+
+  FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
+    if (WeakProcessorPhases::is_serial(phase)) {
+      uint serial_index = WeakProcessorPhases::serial_index(phase);
+      if (!_serial_phases_done.is_task_claimed(serial_index)) {
+        WeakProcessorPhaseTimeTracker pt(_phase_times, phase);
+        WeakProcessorPhases::processor(phase)(is_alive, keep_alive);
+      }
+    } else {
+      WeakProcessorPhaseTimeTracker pt(_phase_times, phase, worker_id);
+      uint storage_index = WeakProcessorPhases::oop_storage_index(phase);
+      _storage_states[storage_index].weak_oops_do(is_alive, keep_alive);
+    }
+  }
+
+  _serial_phases_done.all_tasks_completed(_nworkers);
+}
+
+class WeakProcessor::GangTask : public AbstractGangTask {
+  Task _task;
+  BoolObjectClosure* _is_alive;
+  OopClosure* _keep_alive;
+  void (*_erased_do_work)(GangTask* task, uint worker_id);
+
+  template<typename IsAlive, typename KeepAlive>
+  static void erased_do_work(GangTask* task, uint worker_id) {
+    task->_task.work(worker_id,
+                     static_cast<IsAlive*>(task->_is_alive),
+                     static_cast<KeepAlive*>(task->_keep_alive));
+  }
+
+public:
+  template<typename IsAlive, typename KeepAlive>
+  GangTask(const char* name,
+           IsAlive* is_alive,
+           KeepAlive* keep_alive,
+           WeakProcessorPhaseTimes* phase_times,
+           uint nworkers) :
+    AbstractGangTask(name),
+    _task(phase_times, nworkers),
+    _is_alive(is_alive),
+    _keep_alive(keep_alive),
+    _erased_do_work(&erased_do_work<IsAlive, KeepAlive>)
+  {}
+
+  virtual void work(uint worker_id);
+};
+
+template<typename IsAlive, typename KeepAlive>
+void WeakProcessor::weak_oops_do(WorkGang* workers,
+                                 IsAlive* is_alive,
+                                 KeepAlive* keep_alive,
+                                 WeakProcessorPhaseTimes* phase_times) {
+  WeakProcessorTimeTracker tt(phase_times);
+
+  uint nworkers = ergo_workers(MIN2(workers->active_workers(),
+                                    phase_times->max_threads()));
+
+  GangTask task("Weak Processor", is_alive, keep_alive, phase_times, nworkers);
+  workers->run_task(&task, nworkers);
+}
+
+template<typename IsAlive, typename KeepAlive>
+void WeakProcessor::weak_oops_do(WorkGang* workers,
+                                 IsAlive* is_alive,
+                                 KeepAlive* keep_alive,
+                                 uint indent_log) {
+  uint nworkers = ergo_workers(workers->active_workers());
+  WeakProcessorPhaseTimes pt(nworkers);
+  weak_oops_do(workers, is_alive, keep_alive, &pt);
+  pt.log_print_phases(indent_log);
+}
+
+#endif // SHARE_VM_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/weakProcessorPhaseTimes.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -0,0 +1,268 @@
+/*
+ * 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/weakProcessorPhases.hpp"
+#include "gc/shared/weakProcessorPhaseTimes.hpp"
+#include "gc/shared/workerDataArray.inline.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ticks.hpp"
+
+static uint phase_index(WeakProcessorPhase phase) {
+  return WeakProcessorPhases::index(phase);
+}
+
+static bool is_serial_phase(WeakProcessorPhase phase) {
+  return WeakProcessorPhases::is_serial(phase);
+}
+
+static void assert_oop_storage_phase(WeakProcessorPhase phase) {
+  assert(WeakProcessorPhases::is_oop_storage(phase),
+         "Not an oop_storage phase %u", phase_index(phase));
+}
+
+const double uninitialized_time = -1.0;
+
+#ifdef ASSERT
+static bool is_initialized_time(double t) { return t >= 0.0; }
+#endif // ASSERT
+
+static void reset_times(double* times, size_t ntimes) {
+  for (size_t i = 0; i < ntimes; ++i) {
+    times[i] = uninitialized_time;
+  }
+}
+
+WeakProcessorPhaseTimes::WeakProcessorPhaseTimes(uint max_threads) :
+  _max_threads(max_threads),
+  _active_workers(0),
+  _total_time_sec(uninitialized_time),
+  _worker_phase_times_sec()
+{
+  assert(_max_threads > 0, "max_threads must not be zero");
+
+  reset_times(_phase_times_sec, ARRAY_SIZE(_phase_times_sec));
+
+  if (_max_threads > 1) {
+    WorkerDataArray<double>** wpt = _worker_phase_times_sec;
+    FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) {
+      const char* description = WeakProcessorPhases::description(phase);
+      *wpt++ = new WorkerDataArray<double>(_max_threads, description);
+    }
+  }
+}
+
+WeakProcessorPhaseTimes::~WeakProcessorPhaseTimes() {
+  for (size_t i = 0; i < ARRAY_SIZE(_worker_phase_times_sec); ++i) {
+    delete _worker_phase_times_sec[i];
+  }
+}
+
+uint WeakProcessorPhaseTimes::max_threads() const { return _max_threads; }
+
+uint WeakProcessorPhaseTimes::active_workers() const {
+  assert(_active_workers != 0, "active workers not set");
+  return _active_workers;
+}
+
+void WeakProcessorPhaseTimes::set_active_workers(uint n) {
+  assert(_active_workers == 0, "active workers already set");
+  assert(n > 0, "active workers must be non-zero");
+  assert(n <= _max_threads, "active workers must not exceed max threads");
+  _active_workers = n;
+}
+
+void WeakProcessorPhaseTimes::reset() {
+  _active_workers = 0;
+  _total_time_sec = uninitialized_time;
+  reset_times(_phase_times_sec, ARRAY_SIZE(_phase_times_sec));
+  if (_max_threads > 1) {
+    for (size_t i = 0; i < ARRAY_SIZE(_worker_phase_times_sec); ++i) {
+      _worker_phase_times_sec[i]->reset();
+    }
+  }
+}
+
+double WeakProcessorPhaseTimes::total_time_sec() const {
+  assert(is_initialized_time(_total_time_sec), "Total time not set");
+  return _total_time_sec;
+}
+
+void WeakProcessorPhaseTimes::record_total_time_sec(double time_sec) {
+  assert(!is_initialized_time(_total_time_sec), "Already set total time");
+  _total_time_sec = time_sec;
+}
+
+double WeakProcessorPhaseTimes::phase_time_sec(WeakProcessorPhase phase) const {
+  assert(is_initialized_time(_phase_times_sec[phase_index(phase)]),
+         "phase time not set %u", phase_index(phase));
+  return _phase_times_sec[phase_index(phase)];
+}
+
+void WeakProcessorPhaseTimes::record_phase_time_sec(WeakProcessorPhase phase, double time_sec) {
+  assert(!is_initialized_time(_phase_times_sec[phase_index(phase)]),
+         "Already set time for phase %u", phase_index(phase));
+  _phase_times_sec[phase_index(phase)] = time_sec;
+}
+
+WorkerDataArray<double>* WeakProcessorPhaseTimes::worker_data(WeakProcessorPhase phase) const {
+  assert_oop_storage_phase(phase);
+  assert(active_workers() > 1, "No worker data when single-threaded");
+  return _worker_phase_times_sec[WeakProcessorPhases::oop_storage_index(phase)];
+}
+
+double WeakProcessorPhaseTimes::worker_time_sec(uint worker_id, WeakProcessorPhase phase) const {
+  assert(worker_id < active_workers(),
+         "invalid worker id %u for %u", worker_id, active_workers());
+  if (active_workers() == 1) {
+    return phase_time_sec(phase);
+  } else {
+    return worker_data(phase)->get(worker_id);
+  }
+}
+
+void WeakProcessorPhaseTimes::record_worker_time_sec(uint worker_id,
+                                                     WeakProcessorPhase phase,
+                                                     double time_sec) {
+  if (active_workers() == 1) {
+    record_phase_time_sec(phase, time_sec);
+  } else {
+    worker_data(phase)->set(worker_id, time_sec);
+  }
+}
+
+static double elapsed_time_sec(Ticks start_time, Ticks end_time) {
+  return (end_time - start_time).seconds();
+}
+
+WeakProcessorTimeTracker::WeakProcessorTimeTracker(WeakProcessorPhaseTimes* times) :
+  _times(times),
+  _start_time(Ticks::now())
+{}
+
+WeakProcessorTimeTracker::~WeakProcessorTimeTracker() {
+  if (_times != NULL) {
+    Ticks end_time = Ticks::now();
+    _times->record_total_time_sec(elapsed_time_sec(_start_time, end_time));
+  }
+}
+
+WeakProcessorPhaseTimeTracker::WeakProcessorPhaseTimeTracker(WeakProcessorPhaseTimes* times,
+                                                             WeakProcessorPhase phase,
+                                                             uint worker_id) :
+  _times(times),
+  _phase(phase),
+  _worker_id(worker_id),
+  _start_time(Ticks::now())
+{
+  assert_oop_storage_phase(_phase);
+  assert(_times == NULL || worker_id < _times->active_workers(),
+         "Invalid worker_id %u", worker_id);
+}
+
+WeakProcessorPhaseTimeTracker::WeakProcessorPhaseTimeTracker(WeakProcessorPhaseTimes* times,
+                                                             WeakProcessorPhase phase) :
+  _times(times),
+  _phase(phase),
+  _worker_id(0),
+  _start_time(Ticks::now())
+{
+  assert(is_serial_phase(phase), "Not a serial phase %u", phase_index(phase));
+}
+
+WeakProcessorPhaseTimeTracker::~WeakProcessorPhaseTimeTracker() {
+  if (_times != NULL) {
+    double time_sec = elapsed_time_sec(_start_time, Ticks::now());
+    if (is_serial_phase(_phase)) {
+      _times->record_phase_time_sec(_phase, time_sec);
+    } else {
+      _times->record_worker_time_sec(_worker_id, _phase, time_sec);
+    }
+  }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Printing times
+
+const char* const indents[] = {"", "  ", "    ", "      ", "        "};
+const size_t max_indents_index = ARRAY_SIZE(indents) - 1;
+
+static const char* indent_str(size_t i) {
+  return indents[MIN2(i, max_indents_index)];
+}
+
+#define TIME_FORMAT "%.1lfms"
+
+void WeakProcessorPhaseTimes::log_st_phase(WeakProcessorPhase phase,
+                                           uint indent) const {
+  log_debug(gc, phases)("%s%s: " TIME_FORMAT,
+                        indent_str(indent),
+                        WeakProcessorPhases::description(phase),
+                        phase_time_sec(phase) * MILLIUNITS);
+}
+
+void WeakProcessorPhaseTimes::log_mt_phase_summary(WeakProcessorPhase phase,
+                                                   uint indent) const {
+  LogTarget(Debug, gc, phases) lt;
+  LogStream ls(lt);
+  ls.print("%s", indents[indent]);
+  worker_data(phase)->print_summary_on(&ls, true);
+}
+
+void WeakProcessorPhaseTimes::log_mt_phase_details(WeakProcessorPhase phase,
+                                                   uint indent) const {
+  LogTarget(Trace, gc, phases) lt;
+  LogStream ls(lt);
+  ls.print("%s", indents[indent]);
+  worker_data(phase)->print_details_on(&ls);
+}
+
+void WeakProcessorPhaseTimes::log_print_phases(uint indent) const {
+  if (log_is_enabled(Debug, gc, phases)) {
+    bool details_enabled = log_is_enabled(Trace, gc, phases);
+    FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
+      if (is_serial_phase(phase) || (active_workers() == 1)) {
+        log_st_phase(phase, indent);
+      } else {
+        log_mt_phase_summary(phase, indent);
+        if (details_enabled) {
+          log_mt_phase_details(phase, indent + 1);
+        }
+      }
+    }
+  }
+}
+
+void WeakProcessorPhaseTimes::log_print(uint indent) const {
+  if (log_is_enabled(Debug, gc, phases)) {
+    log_debug(gc, phases)("%s%s: " TIME_FORMAT,
+                          indent_str(indent),
+                          "Weak Processing",
+                          total_time_sec() * MILLIUNITS);
+    log_print_phases(indent + 1);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/weakProcessorPhaseTimes.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -0,0 +1,115 @@
+/*
+ * 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_GC_SHARED_WEAKPROCESSORPHASETIMES_HPP
+#define SHARE_GC_SHARED_WEAKPROCESSORPHASETIMES_HPP
+
+#include "gc/shared/weakProcessorPhases.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ticks.hpp"
+
+template<typename T> class WorkerDataArray;
+
+class WeakProcessorPhaseTimes : public CHeapObj<mtGC> {
+  uint _max_threads;
+  uint _active_workers;
+
+  // Total time for weak processor.
+  double _total_time_sec;
+
+  // Total time for each serially processed phase.  Entries for phases
+  // processed by multiple threads are unused, as are entries for
+  // unexecuted phases.
+  double _phase_times_sec[WeakProcessorPhases::phase_count];
+
+  // Per-worker times, if multiple threads used and the phase was executed.
+  WorkerDataArray<double>* _worker_phase_times_sec[WeakProcessorPhases::oop_storage_phase_count];
+
+  WorkerDataArray<double>* worker_data(WeakProcessorPhase phase) const;
+
+  void log_st_phase(WeakProcessorPhase phase, uint indent) const;
+  void log_mt_phase_summary(WeakProcessorPhase phase, uint indent) const;
+  void log_mt_phase_details(WeakProcessorPhase phase, uint indent) const;
+
+public:
+  WeakProcessorPhaseTimes(uint max_threads);
+  ~WeakProcessorPhaseTimes();
+
+  uint max_threads() const;
+  uint active_workers() const;
+  void set_active_workers(uint n);
+
+  double total_time_sec() const;
+  double phase_time_sec(WeakProcessorPhase phase) const;
+  double worker_time_sec(uint worker_id, WeakProcessorPhase phase) const;
+
+  void record_total_time_sec(double time_sec);
+  void record_phase_time_sec(WeakProcessorPhase phase, double time_sec);
+  void record_worker_time_sec(uint worker_id, WeakProcessorPhase phase, double time_sec);
+
+  void reset();
+
+  void log_print(uint indent = 0) const;
+  void log_print_phases(uint indent = 0) const;
+};
+
+// Record total weak processor time and worker count in times.
+// Does nothing if times is NULL.
+class WeakProcessorTimeTracker : StackObj {
+  WeakProcessorPhaseTimes* _times;
+  Ticks _start_time;
+
+public:
+  WeakProcessorTimeTracker(WeakProcessorPhaseTimes* times);
+  ~WeakProcessorTimeTracker();
+};
+
+// Record phase time contribution for the current thread in phase times.
+// Does nothing if phase times is NULL.
+class WeakProcessorPhaseTimeTracker : StackObj {
+private:
+  WeakProcessorPhaseTimes* _times;
+  WeakProcessorPhase _phase;
+  uint _worker_id;
+  Ticks _start_time;
+
+public:
+  // For tracking serial phase times.
+  // Precondition: WeakProcessorPhases::is_serial(phase)
+  WeakProcessorPhaseTimeTracker(WeakProcessorPhaseTimes* times,
+                                WeakProcessorPhase phase);
+
+  // For tracking possibly parallel phase times (even if processed by
+  // only one thread).
+  // Precondition: WeakProcessorPhases::is_oop_storage(phase)
+  // Precondition: worker_id < times->max_threads().
+  WeakProcessorPhaseTimeTracker(WeakProcessorPhaseTimes* times,
+                                WeakProcessorPhase phase,
+                                uint worker_id);
+
+  ~WeakProcessorPhaseTimeTracker();
+};
+
+#endif // SHARE_GC_SHARED_WEAKPROCESSORPHASETIMES_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/weakProcessorPhases.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -0,0 +1,99 @@
+/*
+ * 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 "classfile/systemDictionary.hpp"
+#include "gc/shared/weakProcessorPhases.hpp"
+#include "runtime/jniHandles.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#endif // INCLUDE_JFR
+
+#if INCLUDE_JVMTI
+#include "prims/jvmtiExport.hpp"
+#endif // INCLUDE_JVMTI
+
+WeakProcessorPhases::Phase WeakProcessorPhases::phase(uint value) {
+  assert(value < phase_count, "Invalid phase value %u", value);
+  return static_cast<Phase>(value);
+}
+
+uint WeakProcessorPhases::index(Phase phase) {
+  uint value = static_cast<uint>(phase);
+  assert(value < phase_count, "Invalid phase %u", value);
+  return value;
+}
+
+uint WeakProcessorPhases::serial_index(Phase phase) {
+  assert(is_serial(phase), "not serial phase %u", index(phase));
+  return index(phase) - serial_phase_start;
+}
+
+uint WeakProcessorPhases::oop_storage_index(Phase phase) {
+  assert(is_oop_storage(phase), "not oop storage phase %u", index(phase));
+  return index(phase) - oop_storage_phase_start;
+}
+
+bool WeakProcessorPhases::is_serial(Phase phase) {
+  return (index(phase) - serial_phase_start) < serial_phase_count;
+}
+
+bool WeakProcessorPhases::is_oop_storage(Phase phase) {
+  return (index(phase) - oop_storage_phase_start) < oop_storage_phase_count;
+}
+
+const char* WeakProcessorPhases::description(Phase phase) {
+  switch (phase) {
+  JVMTI_ONLY(case jvmti: return "JVMTI weak processing";)
+  JFR_ONLY(case jfr: return "JFR weak processing";)
+  case jni: return "JNI weak processing";
+  case vm: return "VM weak processing";
+  default:
+    ShouldNotReachHere();
+    return "Invalid weak processing phase";
+  }
+}
+
+WeakProcessorPhases::Processor WeakProcessorPhases::processor(Phase phase) {
+  switch (phase) {
+  JVMTI_ONLY(case jvmti: return &JvmtiExport::weak_oops_do;)
+  JFR_ONLY(case jfr: return &Jfr::weak_oops_do;)
+  default:
+    ShouldNotReachHere();
+    return NULL;
+  }
+}
+
+OopStorage* WeakProcessorPhases::oop_storage(Phase phase) {
+  switch (phase) {
+  case jni: return JNIHandles::weak_global_handles();
+  case vm: return SystemDictionary::vm_weak_oop_storage();
+  default:
+    ShouldNotReachHere();
+    return NULL;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/weakProcessorPhases.hpp	Tue Aug 28 12:57:40 2018 -0400
@@ -0,0 +1,83 @@
+/*
+ * 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_GC_SHARED_WEAKPROCESSORPHASES_HPP
+#define SHARE_GC_SHARED_WEAKPROCESSORPHASES_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+class BoolObjectClosure;
+class OopClosure;
+class OopStorage;
+
+class WeakProcessorPhases : AllStatic {
+public:
+  typedef void (*Processor)(BoolObjectClosure*, OopClosure*);
+
+  enum Phase {
+    // Serial phases.
+    JVMTI_ONLY(jvmti COMMA)
+    JFR_ONLY(jfr COMMA)
+
+    // OopStorage phases.
+    jni,
+    vm
+  };
+
+  static const uint serial_phase_start = 0;
+  static const uint serial_phase_count = jni;
+  static const uint oop_storage_phase_start = serial_phase_count;
+  static const uint oop_storage_phase_count = (vm + 1) - oop_storage_phase_start;
+  static const uint phase_count = serial_phase_count + oop_storage_phase_count;
+
+  static Phase phase(uint value);
+  static uint index(Phase phase);
+  // Indexes relative to the corresponding phase_start constant.
+  static uint serial_index(Phase phase);
+  static uint oop_storage_index(Phase phase);
+
+  static bool is_serial(Phase phase);
+  static bool is_oop_storage(Phase phase);
+
+  static const char* description(Phase phase);
+  static Processor processor(Phase phase); // Precondition: is_serial(phase)
+  static OopStorage* oop_storage(Phase phase); // Precondition: is_oop_storage(phase)
+};
+
+typedef WeakProcessorPhases::Phase WeakProcessorPhase;
+
+#define FOR_EACH_WEAK_PROCESSOR_PHASE(P)                                \
+  for (WeakProcessorPhase P = static_cast<WeakProcessorPhase>(0);       \
+       static_cast<uint>(P) <  WeakProcessorPhases::phase_count;        \
+       P = static_cast<WeakProcessorPhase>(static_cast<uint>(P) + 1))
+
+#define FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(P)                    \
+  for (WeakProcessorPhase P = static_cast<WeakProcessorPhase>(WeakProcessorPhases::oop_storage_phase_start); \
+       static_cast<uint>(P) < (WeakProcessorPhases::oop_storage_phase_start + \
+                               WeakProcessorPhases::oop_storage_phase_count); \
+       P = static_cast<WeakProcessorPhase>(static_cast<uint>(P) + 1))
+
+#endif // SHARE_GC_SHARED_WEAKPROCESSORPHASES_HPP
--- a/src/hotspot/share/gc/shared/workgroup.cpp	Wed Aug 22 09:33:18 2018 -0700
+++ b/src/hotspot/share/gc/shared/workgroup.cpp	Tue Aug 28 12:57:40 2018 -0400
@@ -462,7 +462,7 @@
 
 
 SubTasksDone::~SubTasksDone() {
-  if (_tasks != NULL) FREE_C_HEAP_ARRAY(jint, _tasks);
+  if (_tasks != NULL) FREE_C_HEAP_ARRAY(uint, _tasks);
 }
 
 // *** SequentialSubTasksDone