src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
changeset 54924 ba1eccda5450
parent 54882 b99e97bc5040
child 54940 2d90a0988c95
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp	Fri May 17 12:33:37 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp	Fri May 17 09:52:35 2019 -0400
@@ -28,8 +28,9 @@
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
-#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
 #include "gc/shenandoah/shenandoahHeap.hpp"
+#include "gc/shenandoah/shenandoahHeuristics.hpp"
 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
 #include "gc/shenandoah/shenandoahStringDedup.hpp"
 #include "gc/shenandoah/shenandoahTimingTracker.hpp"
@@ -43,67 +44,95 @@
 #include "runtime/thread.hpp"
 #include "services/management.hpp"
 
-ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahHeap* heap, uint n_workers,
-                                                 ShenandoahPhaseTimings::Phase phase) :
-  _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)),
-  _srs(n_workers),
-  _phase(phase),
-  _coderoots_all_iterator(ShenandoahCodeRoots::iterator()),
-  _weak_processor_timings(n_workers),
-  _weak_processor_task(&_weak_processor_timings, n_workers),
-  _processed_weak_roots(false) {
-  heap->phase_timings()->record_workers_start(_phase);
+ShenandoahSerialRoot::ShenandoahSerialRoot(ShenandoahSerialRoot::OopsDo oops_do, ShenandoahPhaseTimings::GCParPhases phase) :
+  _claimed(false), _oops_do(oops_do), _phase(phase) {
+}
+
+void ShenandoahSerialRoot::oops_do(OopClosure* cl, uint worker_id) {
+  if (!_claimed && Atomic::cmpxchg(true, &_claimed, false) == false) {
+    ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+    ShenandoahWorkerTimingsTracker timer(worker_times, _phase, worker_id);
+    _oops_do(cl);
+  }
+}
+
+ShenandoahSerialRoots::ShenandoahSerialRoots() :
+  _universe_root(&Universe::oops_do, ShenandoahPhaseTimings::UniverseRoots),
+  _object_synchronizer_root(&ObjectSynchronizer::oops_do, ShenandoahPhaseTimings::ObjectSynchronizerRoots),
+  _management_root(&Management::oops_do, ShenandoahPhaseTimings::ManagementRoots),
+  _system_dictionary_root(&SystemDictionary::oops_do, ShenandoahPhaseTimings::SystemDictionaryRoots),
+  _jvmti_root(&JvmtiExport::oops_do, ShenandoahPhaseTimings::JVMTIRoots),
+  _jni_handle_root(&JNIHandles::oops_do, ShenandoahPhaseTimings::JNIRoots) {
+}
+
+void ShenandoahSerialRoots::oops_do(OopClosure* cl, uint worker_id) {
+  _universe_root.oops_do(cl, worker_id);
+  _object_synchronizer_root.oops_do(cl, worker_id);
+  _management_root.oops_do(cl, worker_id);
+  _system_dictionary_root.oops_do(cl, worker_id);
+  _jvmti_root.oops_do(cl, worker_id);
+  _jni_handle_root.oops_do(cl, worker_id);
+}
 
+ShenandoahThreadRoots::ShenandoahThreadRoots(bool is_par) : _is_par(is_par) {
+  Threads::change_thread_claim_token();
+}
+
+void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, CodeBlobClosure* code_cl, uint worker_id) {
+  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+  ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+  ResourceMark rm;
+  Threads::possibly_parallel_oops_do(_is_par, oops_cl, code_cl);
+}
+
+void ShenandoahThreadRoots::threads_do(ThreadClosure* tc, uint worker_id) {
+  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+  ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+  ResourceMark rm;
+  Threads::possibly_parallel_threads_do(_is_par, tc);
+}
+
+ShenandoahThreadRoots::~ShenandoahThreadRoots() {
+  Threads::assert_all_threads_claimed();
+}
+
+ShenandoahWeakRoots::ShenandoahWeakRoots(uint n_workers) :
+  _process_timings(n_workers),
+  _task(&_process_timings, n_workers) {
+}
+
+ShenandoahWeakRoots::~ShenandoahWeakRoots() {
+  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+  ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(&_process_timings,
+                                                                         worker_times);
+}
+
+ShenandoahStringDedupRoots::ShenandoahStringDedupRoots() {
   if (ShenandoahStringDedup::is_enabled()) {
     StringDedup::gc_prologue(false);
   }
 }
 
-ShenandoahRootProcessor::~ShenandoahRootProcessor() {
-  delete _process_strong_tasks;
+ShenandoahStringDedupRoots::~ShenandoahStringDedupRoots() {
   if (ShenandoahStringDedup::is_enabled()) {
     StringDedup::gc_epilogue();
   }
+}
 
-  if (_processed_weak_roots) {
-    assert(_weak_processor_timings.max_threads() == n_workers(), "Must match");
-    ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
-    ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(&_weak_processor_timings,
-                                                                           worker_times);
+void ShenandoahStringDedupRoots::oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
+  if (ShenandoahStringDedup::is_enabled()) {
+    ShenandoahStringDedup::parallel_oops_do(is_alive, keep_alive, worker_id);
   }
-
-  ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase);
 }
 
-void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops,
-                                                   CLDClosure* clds,
-                                                   CodeBlobClosure* blobs,
-                                                   ThreadClosure* thread_cl,
-                                                   uint worker_id) {
-
-  process_java_roots(oops, clds, NULL, blobs, thread_cl, worker_id);
-  process_vm_roots(oops, worker_id);
-
-  _process_strong_tasks->all_tasks_completed(n_workers());
+ShenandoahClassLoaderDataRoots::ShenandoahClassLoaderDataRoots() {
+  ClassLoaderDataGraph::clear_claimed_marks();
 }
 
-void ShenandoahRootProcessor::process_all_roots(OopClosure* oops,
-                                                CLDClosure* clds,
-                                                CodeBlobClosure* blobs,
-                                                ThreadClosure* thread_cl,
-                                                uint worker_id) {
-
+void ShenandoahClassLoaderDataRoots::clds_do(CLDClosure* strong_clds, CLDClosure* weak_clds, uint worker_id) {
   ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
-  process_java_roots(oops, clds, clds, blobs, thread_cl, worker_id);
-  process_vm_roots(oops, worker_id);
-
-  if (blobs != NULL) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
-    _coderoots_all_iterator.possibly_parallel_blobs_do(blobs);
-  }
-
-  _process_strong_tasks->all_tasks_completed(n_workers());
-
+  ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
+  ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds);
 }
 
 class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
@@ -123,168 +152,110 @@
   }
 };
 
-void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots,
-                                                 CLDClosure* strong_clds,
-                                                 CLDClosure* weak_clds,
-                                                 CodeBlobClosure* strong_code,
-                                                 ThreadClosure* thread_cl,
-                                                 uint worker_id)
-{
-  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
-  // Iterating over the CLDG and the Threads are done early to allow us to
-  // first process the strong CLDs and nmethods and then, after a barrier,
-  // let the thread process the weak CLDs and nmethods.
-  {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
-    _cld_iterator.root_cld_do(strong_clds, weak_clds);
-  }
+ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase) :
+  _heap(ShenandoahHeap::heap()),
+  _phase(phase) {
+  assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
+  _heap->phase_timings()->record_workers_start(_phase);
+}
 
-  {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
-    bool is_par = n_workers() > 1;
-    ResourceMark rm;
-    ShenandoahParallelOopsDoThreadClosure cl(strong_roots, strong_code, thread_cl);
-    Threads::possibly_parallel_threads_do(is_par, &cl);
-  }
+ShenandoahRootProcessor::~ShenandoahRootProcessor() {
+  assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
+  _heap->phase_timings()->record_workers_end(_phase);
+}
+
+ShenandoahRootScanner::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
+  ShenandoahRootProcessor(phase),
+  _thread_roots(n_workers > 1) {
 }
 
-void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots,
-                                               uint worker_id) {
-  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
-  if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Universe_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id);
-    Universe::oops_do(strong_roots);
-  }
+void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops) {
+  CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
+  MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
+  roots_do(worker_id, oops, &clds_cl, &blobs_cl);
+}
 
-  if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_JNIHandles_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIRoots, worker_id);
-    JNIHandles::oops_do(strong_roots);
-  }
-  if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Management_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ManagementRoots, worker_id);
-    Management::oops_do(strong_roots);
-  }
-  if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_jvmti_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id);
-    JvmtiExport::oops_do(strong_roots);
-  }
-  if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id);
-    SystemDictionary::oops_do(strong_roots);
-  }
-
-  {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id);
-    if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_ObjectSynchronizer_oops_do)) {
-      ObjectSynchronizer::oops_do(strong_roots);
-    }
-  }
+void ShenandoahRootScanner::strong_roots_do(uint worker_id, OopClosure* oops) {
+  CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
+  MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
+  strong_roots_do(worker_id, oops, &clds_cl, &blobs_cl);
 }
 
-uint ShenandoahRootProcessor::n_workers() const {
-  return _srs.n_threads();
-}
+void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) {
+  assert(!ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
+  ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
+  ResourceMark rm;
 
-ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, ShenandoahPhaseTimings::Phase phase) :
-  _evacuation_tasks(new SubTasksDone(SHENANDOAH_EVAC_NumElements)),
-  _srs(n_workers),
-  _phase(phase),
-  _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()),
-  _weak_processor_timings(n_workers),
-  _weak_processor_task(&_weak_processor_timings, n_workers) {
-  heap->phase_timings()->record_workers_start(_phase);
-  if (ShenandoahStringDedup::is_enabled()) {
-    StringDedup::gc_prologue(false);
+  _serial_roots.oops_do(oops, worker_id);
+  _cld_roots.clds_do(clds, clds, worker_id);
+  _thread_roots.threads_do(&tc_cl, worker_id);
+
+  // With ShenandoahConcurrentScanCodeRoots, we avoid scanning the entire code cache here,
+  // and instead do that in concurrent phase under the relevant lock. This saves init mark
+  // pause time.
+  if (code != NULL && !ShenandoahConcurrentScanCodeRoots) {
+    _code_roots.code_blobs_do(code, worker_id);
   }
 }
 
-ShenandoahRootEvacuator::~ShenandoahRootEvacuator() {
-  delete _evacuation_tasks;
-  if (ShenandoahStringDedup::is_enabled()) {
-    StringDedup::gc_epilogue();
-  }
+void ShenandoahRootScanner::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
+  assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
+  ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
+  ResourceMark rm;
 
-  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
-  assert(_weak_processor_timings.max_threads() == n_workers(), "Must match");
-  ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(&_weak_processor_timings,
-                                                                         worker_times);
-
-  ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase);
+  _serial_roots.oops_do(oops, worker_id);
+  _cld_roots.clds_do(clds, NULL, worker_id);
+  _thread_roots.threads_do(&tc_cl, worker_id);
 }
 
-void ShenandoahRootEvacuator::process_evacuate_roots(OopClosure* oops,
-                                                     CodeBlobClosure* blobs,
-                                                     uint worker_id) {
+ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
+  ShenandoahRootProcessor(phase),
+  _thread_roots(n_workers > 1),
+  _weak_roots(n_workers) {
+}
+
+void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) {
+  MarkingCodeBlobClosure blobsCl(oops, CodeBlobToOopClosure::FixRelocations);
+  CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
+  CLDToOopClosure* weak_clds = ShenandoahHeap::heap()->unload_classes() ? NULL : &clds;
 
   AlwaysTrueClosure always_true;
-  ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
-  {
-    bool is_par = n_workers() > 1;
-    ResourceMark rm;
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
-    Threads::possibly_parallel_oops_do(is_par, oops, NULL);
-  }
 
-  {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
-    CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
-    _cld_iterator.root_cld_do(&clds, &clds);
-  }
+  _serial_roots.oops_do(oops, worker_id);
 
-  if (blobs != NULL) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
-    _coderoots_cset_iterator.possibly_parallel_blobs_do(blobs);
-  }
-
-  if (ShenandoahStringDedup::is_enabled()) {
-    ShenandoahStringDedup::parallel_oops_do(&always_true, oops, worker_id);
-  }
-
-  if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_Universe_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id);
-    Universe::oops_do(oops);
-  }
+  _thread_roots.oops_do(oops, NULL, worker_id);
+  _cld_roots.clds_do(&clds, &clds, worker_id);
+  _code_roots.code_blobs_do(&blobsCl, worker_id);
 
-  if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_Management_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ManagementRoots, worker_id);
-    Management::oops_do(oops);
-  }
-
-  if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_jvmti_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id);
-    JvmtiExport::oops_do(oops);
-    ShenandoahForwardedIsAliveClosure is_alive;
-    JvmtiExport::weak_oops_do(&is_alive, oops);
-  }
+  _weak_roots.oops_do<AlwaysTrueClosure, OopClosure>(&always_true, oops, worker_id);
+  _dedup_roots.oops_do(&always_true, oops, worker_id);
+}
 
-  if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_JNIHandles_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIRoots, worker_id);
-    JNIHandles::oops_do(oops);
-  }
-
-  if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_SystemDictionary_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id);
-    SystemDictionary::oops_do(oops);
-  }
-
-  if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_ObjectSynchronizer_oops_do)) {
-    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id);
-    ObjectSynchronizer::oops_do(oops);
-  }
-
-  _weak_processor_task.work<AlwaysTrueClosure, OopClosure>(worker_id, &always_true, oops);
+ShenandoahRootUpdater::ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool update_code_cache) :
+  ShenandoahRootProcessor(phase),
+  _thread_roots(n_workers > 1),
+  _weak_roots(n_workers),
+  _update_code_cache(update_code_cache) {
 }
 
-uint ShenandoahRootEvacuator::n_workers() const {
-  return _srs.n_threads();
+ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
+  ShenandoahRootProcessor(phase),
+  _thread_roots(n_workers > 1),
+  _weak_roots(n_workers) {
+  assert(ShenandoahHeap::heap()->is_full_gc_in_progress(), "Full GC only");
 }
 
-// Implemenation of ParallelCLDRootIterator
-ParallelCLDRootIterator::ParallelCLDRootIterator() {
-  assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
-  ClassLoaderDataGraph::clear_claimed_marks();
+void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) {
+  CodeBlobToOopClosure adjust_code_closure(oops, CodeBlobToOopClosure::FixRelocations);
+  CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong);
+  AlwaysTrueClosure always_true;
+
+  _serial_roots.oops_do(oops, worker_id);
+
+  _thread_roots.oops_do(oops, NULL, worker_id);
+  _cld_roots.clds_do(&adjust_cld_closure, NULL, worker_id);
+  _code_roots.code_blobs_do(&adjust_code_closure, worker_id);
+
+  _weak_roots.oops_do<AlwaysTrueClosure, OopClosure>(&always_true, oops, worker_id);
+  _dedup_roots.oops_do(&always_true, oops, worker_id);
 }
-
-void ParallelCLDRootIterator::root_cld_do(CLDClosure* strong, CLDClosure* weak) {
-    ClassLoaderDataGraph::roots_cld_do(strong, weak);
-}