rev 59532 : 8246100: Shenandoah: walk roots in more efficient order
Reviewed-by: XXX
rev 59533 : 8246097: Shenandoah: limit parallelism in CLDG root handling
Reviewed-by: XXX

   1 /*
   2  * Copyright (c) 2015, 2020, Red Hat, Inc. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 
  27 #include "classfile/classLoaderDataGraph.hpp"
  28 #include "classfile/stringTable.hpp"
  29 #include "classfile/systemDictionary.hpp"
  30 #include "code/codeCache.hpp"
  31 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
  32 #include "gc/shenandoah/shenandoahConcurrentRoots.hpp"
  33 #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
  34 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  35 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
  36 #include "gc/shenandoah/shenandoahStringDedup.hpp"
  37 #include "gc/shenandoah/shenandoahVMOperations.hpp"
  38 #include "jfr/jfr.hpp"
  39 #include "memory/iterator.hpp"
  40 #include "memory/resourceArea.hpp"
  41 #include "memory/universe.hpp"
  42 #include "runtime/thread.hpp"
  43 #include "services/management.hpp"
  44 
  45 ShenandoahSerialRoot::ShenandoahSerialRoot(ShenandoahSerialRoot::OopsDo oops_do,
  46   ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
  47   _oops_do(oops_do), _phase(phase), _par_phase(par_phase) {
  48 }
  49 
  50 void ShenandoahSerialRoot::oops_do(OopClosure* cl, uint worker_id) {
  51   if (_claimed.try_set()) {
  52     ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id);
  53     _oops_do(cl);
  54   }
  55 }
  56 
  57 // Overwrite the second argument for SD::oops_do, don't include vm global oop storage.
  58 static void system_dictionary_oops_do(OopClosure* cl) {
  59   SystemDictionary::oops_do(cl, false);
  60 }
  61 
  62 ShenandoahSerialRoots::ShenandoahSerialRoots(ShenandoahPhaseTimings::Phase phase) :
  63   _universe_root(&Universe::oops_do, phase, ShenandoahPhaseTimings::UniverseRoots),
  64   _object_synchronizer_root(&ObjectSynchronizer::oops_do, phase, ShenandoahPhaseTimings::ObjectSynchronizerRoots),
  65   _management_root(&Management::oops_do, phase, ShenandoahPhaseTimings::ManagementRoots),
  66   _system_dictionary_root(&system_dictionary_oops_do, phase, ShenandoahPhaseTimings::SystemDictionaryRoots),
  67   _jvmti_root(&JvmtiExport::oops_do, phase, ShenandoahPhaseTimings::JVMTIRoots) {
  68 }
  69 
  70 void ShenandoahSerialRoots::oops_do(OopClosure* cl, uint worker_id) {
  71   _universe_root.oops_do(cl, worker_id);
  72   _object_synchronizer_root.oops_do(cl, worker_id);
  73   _management_root.oops_do(cl, worker_id);
  74   _system_dictionary_root.oops_do(cl, worker_id);
  75   _jvmti_root.oops_do(cl, worker_id);
  76 }
  77 
  78 ShenandoahWeakSerialRoot::ShenandoahWeakSerialRoot(ShenandoahWeakSerialRoot::WeakOopsDo weak_oops_do,
  79   ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
  80   _weak_oops_do(weak_oops_do), _phase(phase), _par_phase(par_phase) {
  81 }
  82 
  83 void ShenandoahWeakSerialRoot::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
  84   if (_claimed.try_set()) {
  85     ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id);
  86     _weak_oops_do(is_alive, keep_alive);
  87   }
  88 }
  89 
  90 #if INCLUDE_JVMTI
  91 ShenandoahJVMTIWeakRoot::ShenandoahJVMTIWeakRoot(ShenandoahPhaseTimings::Phase phase) :
  92   ShenandoahWeakSerialRoot(&JvmtiExport::weak_oops_do, phase, ShenandoahPhaseTimings::JVMTIWeakRoots) {
  93 }
  94 #endif // INCLUDE_JVMTI
  95 
  96 #if INCLUDE_JFR
  97 ShenandoahJFRWeakRoot::ShenandoahJFRWeakRoot(ShenandoahPhaseTimings::Phase phase) :
  98   ShenandoahWeakSerialRoot(&Jfr::weak_oops_do, phase, ShenandoahPhaseTimings::JFRWeakRoots) {
  99 }
 100 #endif // INCLUDE_JFR
 101 
 102 void ShenandoahSerialWeakRoots::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
 103   JVMTI_ONLY(_jvmti_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);)
 104   JFR_ONLY(_jfr_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);)
 105 }
 106 
 107 void ShenandoahSerialWeakRoots::weak_oops_do(OopClosure* cl, uint worker_id) {
 108   AlwaysTrueClosure always_true;
 109   weak_oops_do(&always_true, cl, worker_id);
 110 }
 111 
 112 ShenandoahThreadRoots::ShenandoahThreadRoots(ShenandoahPhaseTimings::Phase phase, bool is_par) :
 113   _phase(phase), _is_par(is_par) {
 114   Threads::change_thread_claim_token();
 115 }
 116 
 117 void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, CodeBlobClosure* code_cl, uint worker_id) {
 118   ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
 119   ResourceMark rm;
 120   Threads::possibly_parallel_oops_do(_is_par, oops_cl, code_cl);
 121 }
 122 
 123 void ShenandoahThreadRoots::threads_do(ThreadClosure* tc, uint worker_id) {
 124   ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
 125   ResourceMark rm;
 126   Threads::possibly_parallel_threads_do(_is_par, tc);
 127 }
 128 
 129 ShenandoahThreadRoots::~ShenandoahThreadRoots() {
 130   Threads::assert_all_threads_claimed();
 131 }
 132 
 133 ShenandoahStringDedupRoots::ShenandoahStringDedupRoots(ShenandoahPhaseTimings::Phase phase) : _phase(phase) {
 134   if (ShenandoahStringDedup::is_enabled()) {
 135     StringDedup::gc_prologue(false);
 136   }
 137 }
 138 
 139 ShenandoahStringDedupRoots::~ShenandoahStringDedupRoots() {
 140   if (ShenandoahStringDedup::is_enabled()) {
 141     StringDedup::gc_epilogue();
 142   }
 143 }
 144 
 145 void ShenandoahStringDedupRoots::oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
 146   if (ShenandoahStringDedup::is_enabled()) {
 147     ShenandoahStringDedup::parallel_oops_do(_phase, is_alive, keep_alive, worker_id);
 148   }
 149 }
 150 
 151 ShenandoahConcurrentStringDedupRoots::ShenandoahConcurrentStringDedupRoots() {
 152   if (ShenandoahStringDedup::is_enabled()) {
 153     StringDedupTable_lock->lock_without_safepoint_check();
 154     StringDedupQueue_lock->lock_without_safepoint_check();
 155     StringDedup::gc_prologue(true);
 156   }
 157 }
 158 
 159 ShenandoahConcurrentStringDedupRoots::~ShenandoahConcurrentStringDedupRoots() {
 160   if (ShenandoahStringDedup::is_enabled()) {
 161     StringDedup::gc_epilogue();
 162     StringDedupQueue_lock->unlock();
 163     StringDedupTable_lock->unlock();
 164   }
 165 }
 166 
 167 void ShenandoahConcurrentStringDedupRoots::oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
 168   if (ShenandoahStringDedup::is_enabled()) {
 169     assert_locked_or_safepoint_weak(StringDedupQueue_lock);
 170     assert_locked_or_safepoint_weak(StringDedupTable_lock);
 171 
 172     StringDedupUnlinkOrOopsDoClosure sd_cl(is_alive, keep_alive);
 173     StringDedupQueue::unlink_or_oops_do(&sd_cl);
 174     StringDedupTable::unlink_or_oops_do(&sd_cl, worker_id);
 175   }
 176 }
 177 
 178 ShenandoahCodeCacheRoots::ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase) : _phase(phase) {
 179   nmethod::oops_do_marking_prologue();
 180 }
 181 
 182 void ShenandoahCodeCacheRoots::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) {
 183   ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
 184   _coderoots_iterator.possibly_parallel_blobs_do(blob_cl);
 185 }
 186 
 187 ShenandoahCodeCacheRoots::~ShenandoahCodeCacheRoots() {
 188   nmethod::oops_do_marking_epilogue();
 189 }
 190 
 191 ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase) :
 192   _heap(ShenandoahHeap::heap()),
 193   _phase(phase),
 194   _worker_phase(phase) {
 195   assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
 196 }
 197 
 198 ShenandoahRootScanner::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
 199   ShenandoahRootProcessor(phase),
 200   _serial_roots(phase),
 201   _thread_roots(phase, n_workers > 1),
 202   _code_roots(phase),
 203   _vm_roots(phase),
 204   _dedup_roots(phase),
 205   _cld_roots(phase, n_workers) {
 206 }
 207 
 208 void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops) {
 209   CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
 210   MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
 211   roots_do(worker_id, oops, &clds_cl, &blobs_cl);
 212 }
 213 
 214 void ShenandoahRootScanner::strong_roots_do(uint worker_id, OopClosure* oops) {
 215   CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
 216   MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
 217   strong_roots_do(worker_id, oops, &clds_cl, &blobs_cl);
 218 }
 219 
 220 void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) {
 221   assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint() ||
 222          !ShenandoahHeap::heap()->unload_classes(),
 223           "Expect class unloading when Shenandoah cycle is running");
 224   assert(clds != NULL, "Only possible with CLD closure");
 225 
 226   AlwaysTrueClosure always_true;
 227   ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
 228 
 229   ResourceMark rm;
 230 
 231   // Process serial-claiming roots first
 232   _serial_roots.oops_do(oops, worker_id);
 233 
 234    // Process light-weight/limited parallel roots then
 235   _vm_roots.oops_do(oops, worker_id);
 236   _dedup_roots.oops_do(&always_true, oops, worker_id);
 237   _cld_roots.cld_do(clds, worker_id);
 238 
 239   // Process heavy-weight/fully parallel roots the last

 240   _thread_roots.threads_do(&tc_cl, worker_id);
 241 }
 242 
 243 void ShenandoahRootScanner::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
 244   assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
 245   ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
 246 
 247   ResourceMark rm;
 248 
 249   // Process serial-claiming roots first
 250   _serial_roots.oops_do(oops, worker_id);
 251 
 252   // Process light-weight/limited parallel roots then
 253   _vm_roots.oops_do(oops, worker_id);
 254   _cld_roots.always_strong_cld_do(clds, worker_id);
 255 
 256   // Process heavy-weight/fully parallel roots the last

 257   _thread_roots.threads_do(&tc_cl, worker_id);
 258 }
 259 
 260 ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers,
 261                                                  ShenandoahPhaseTimings::Phase phase,
 262                                                  bool stw_roots_processing,
 263                                                  bool stw_class_unloading) :
 264   ShenandoahRootProcessor(phase),
 265   _serial_roots(phase),
 266   _vm_roots(phase),
 267   _cld_roots(phase, n_workers),
 268   _thread_roots(phase, n_workers > 1),
 269   _serial_weak_roots(phase),
 270   _weak_roots(phase),
 271   _dedup_roots(phase),
 272   _code_roots(phase),
 273   _stw_roots_processing(stw_roots_processing),
 274   _stw_class_unloading(stw_class_unloading) {
 275 }
 276 
 277 void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) {
 278   MarkingCodeBlobClosure blobsCl(oops, CodeBlobToOopClosure::FixRelocations);
 279   ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(oops);
 280   CodeBlobToOopClosure* codes_cl = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ?
 281                                    static_cast<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
 282                                    static_cast<CodeBlobToOopClosure*>(&blobsCl);
 283   AlwaysTrueClosure always_true;
 284 
 285   // Process serial-claiming roots first
 286   _serial_roots.oops_do(oops, worker_id);
 287   _serial_weak_roots.weak_oops_do(oops, worker_id);
 288 
 289   // Process light-weight/limited parallel roots then
 290   if (_stw_roots_processing) {
 291     _vm_roots.oops_do<OopClosure>(oops, worker_id);
 292     _weak_roots.oops_do<OopClosure>(oops, worker_id);
 293     _dedup_roots.oops_do(&always_true, oops, worker_id);
 294   }


 295   if (_stw_class_unloading) {
 296     CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
 297     _cld_roots.cld_do(&clds, worker_id);
 298   }
 299 
 300   // Process heavy-weight/fully parallel roots the last
 301   if (_stw_class_unloading) {
 302     _code_roots.code_blobs_do(codes_cl, worker_id);
 303     _thread_roots.oops_do(oops, NULL, worker_id);
 304   } else {
 305     _thread_roots.oops_do(oops, codes_cl, worker_id);
 306   }
 307 }
 308 
 309 ShenandoahRootUpdater::ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
 310   ShenandoahRootProcessor(phase),
 311   _serial_roots(phase),
 312   _vm_roots(phase),
 313   _cld_roots(phase, n_workers),
 314   _thread_roots(phase, n_workers > 1),
 315   _serial_weak_roots(phase),
 316   _weak_roots(phase),
 317   _dedup_roots(phase),
 318   _code_roots(phase) {
 319 }
 320 
 321 ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
 322   ShenandoahRootProcessor(phase),
 323   _serial_roots(phase),
 324   _vm_roots(phase),
 325   _cld_roots(phase, n_workers),
 326   _thread_roots(phase, n_workers > 1),
 327   _serial_weak_roots(phase),
 328   _weak_roots(phase),
 329   _dedup_roots(phase),
 330   _code_roots(phase) {
 331   assert(ShenandoahHeap::heap()->is_full_gc_in_progress(), "Full GC only");
 332 }
 333 
 334 void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) {
 335   CodeBlobToOopClosure code_blob_cl(oops, CodeBlobToOopClosure::FixRelocations);
 336   ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(oops);
 337   CodeBlobToOopClosure* adjust_code_closure = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ?
 338                                               static_cast<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
 339                                               static_cast<CodeBlobToOopClosure*>(&code_blob_cl);
 340   CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong);
 341   AlwaysTrueClosure always_true;
 342 
 343   // Process serial-claiming roots first
 344   _serial_roots.oops_do(oops, worker_id);
 345   _serial_weak_roots.weak_oops_do(oops, worker_id);
 346 
 347   // Process light-weight/limited parallel roots then
 348   _vm_roots.oops_do(oops, worker_id);
 349   _weak_roots.oops_do<OopClosure>(oops, worker_id);
 350   _dedup_roots.oops_do(&always_true, oops, worker_id);
 351   _cld_roots.cld_do(&adjust_cld_closure, worker_id);
 352 
 353   // Process heavy-weight/fully parallel roots the last

 354   _code_roots.code_blobs_do(adjust_code_closure, worker_id);
 355   _thread_roots.oops_do(oops, NULL, worker_id);
 356 }
 357 
 358 ShenandoahHeapIterationRootScanner::ShenandoahHeapIterationRootScanner() :
 359    ShenandoahRootProcessor(ShenandoahPhaseTimings::heap_iteration_roots),
 360    _serial_roots(ShenandoahPhaseTimings::heap_iteration_roots),
 361    _thread_roots(ShenandoahPhaseTimings::heap_iteration_roots, false /*is par*/),
 362    _vm_roots(ShenandoahPhaseTimings::heap_iteration_roots),
 363    _cld_roots(ShenandoahPhaseTimings::heap_iteration_roots, 1),
 364    _serial_weak_roots(ShenandoahPhaseTimings::heap_iteration_roots),
 365    _weak_roots(ShenandoahPhaseTimings::heap_iteration_roots),
 366    _code_roots(ShenandoahPhaseTimings::heap_iteration_roots) {
 367  }
 368 
 369  void ShenandoahHeapIterationRootScanner::roots_do(OopClosure* oops) {
 370    assert(Thread::current()->is_VM_thread(), "Only by VM thread");
 371    // Must use _claim_none to avoid interfering with concurrent CLDG iteration
 372    CLDToOopClosure clds(oops, ClassLoaderData::_claim_none);
 373    MarkingCodeBlobClosure code(oops, !CodeBlobToOopClosure::FixRelocations);
 374    ShenandoahParallelOopsDoThreadClosure tc_cl(oops, &code, NULL);
 375    AlwaysTrueClosure always_true;
 376 
 377    ResourceMark rm;
 378 
 379    // Process serial-claiming roots first
 380    _serial_roots.oops_do(oops, 0);
 381    _serial_weak_roots.weak_oops_do(oops, 0);
 382 
 383    // Process light-weight/limited parallel roots then
 384    _vm_roots.oops_do(oops, 0);
 385    _weak_roots.oops_do<OopClosure>(oops, 0);
 386    _dedup_roots.oops_do(&always_true, oops, 0);
 387    _cld_roots.cld_do(&clds, 0);
 388 
 389    // Process heavy-weight/fully parallel roots the last

 390    _code_roots.code_blobs_do(&code, 0);
 391    _thread_roots.threads_do(&tc_cl, 0);
 392  }
--- EOF ---