1 /*
   2  * Copyright (c) 2015, Red Hat, Inc. and/or its affiliates.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "precompiled.hpp"
  25 
  26 #include "classfile/stringTable.hpp"
  27 #include "classfile/systemDictionary.hpp"
  28 #include "code/codeCache.hpp"
  29 #include "gc/shenandoah/shenandoahRootProcessor.hpp"
  30 #include "gc/shenandoah/shenandoahHeap.hpp"
  31 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  32 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
  33 #include "gc/shenandoah/shenandoahPhaseTimes.hpp"
  34 #include "memory/allocation.inline.hpp"
  35 #include "runtime/fprofiler.hpp"
  36 #include "runtime/mutex.hpp"
  37 #include "services/management.hpp"
  38 
  39 ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahHeap* heap, uint n_workers,
  40                                                  ShenandoahCollectorPolicy::TimingPhase phase) :
  41   _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)),
  42   _srs(n_workers),
  43   _phase(phase),
  44   _codecache_iterator(CodeCache::parallel_iterator()),
  45   _om_iterator(ObjectSynchronizer::parallel_iterator())
  46 {
  47   heap->shenandoahPolicy()->record_workers_start(_phase);
  48 }
  49 
  50 ShenandoahRootProcessor::~ShenandoahRootProcessor() {
  51   delete _process_strong_tasks;
  52   ShenandoahHeap::heap()->shenandoahPolicy()->record_workers_end(_phase);
  53 }
  54 
  55 void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops,
  56                                                    OopClosure* weak_oops,
  57                                                    CLDClosure* clds,
  58                                                    CodeBlobClosure* blobs,
  59                                                    uint worker_id) {
  60 
  61   process_java_roots(oops, clds, NULL, blobs, worker_id);
  62   process_vm_roots(oops, NULL, weak_oops, worker_id);
  63 
  64   _process_strong_tasks->all_tasks_completed(n_workers());
  65 }
  66 
  67 void ShenandoahRootProcessor::process_all_roots(OopClosure* oops,
  68                                                 OopClosure* weak_oops,
  69                                                 CLDClosure* clds,
  70                                                 CodeBlobClosure* blobs,
  71                                                 uint worker_id) {
  72 
  73   ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times();
  74   process_java_roots(oops, clds, clds, NULL, worker_id);
  75   process_vm_roots(oops, oops, weak_oops, worker_id);
  76 
  77   if (blobs != NULL) {
  78     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::CodeCacheRoots, worker_id);
  79     _codecache_iterator.parallel_blobs_do(blobs);
  80   }
  81 
  82   _process_strong_tasks->all_tasks_completed(n_workers());
  83 }
  84 
  85 void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots,
  86                                                  CLDClosure* strong_clds,
  87                                                  CLDClosure* weak_clds,
  88                                                  CodeBlobClosure* strong_code,
  89                                                  uint worker_id)
  90 {
  91   ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times();
  92   // Iterating over the CLDG and the Threads are done early to allow us to
  93   // first process the strong CLDs and nmethods and then, after a barrier,
  94   // let the thread process the weak CLDs and nmethods.
  95   {
  96     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::CLDGRoots, worker_id);
  97     _cld_iterator.root_cld_do(strong_clds, weak_clds);
  98   }
  99 
 100   {
 101     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ThreadRoots, worker_id);
 102     bool is_par = n_workers() > 1;
 103     ResourceMark rm;
 104     Threads::possibly_parallel_oops_do(is_par, strong_roots, strong_code);
 105   }
 106 }
 107 
 108 void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots,
 109                                                OopClosure* weak_roots,
 110                                                OopClosure* jni_weak_roots,
 111                                                uint worker_id)
 112 {
 113   ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times();
 114   if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_Universe_oops_do)) {
 115     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::UniverseRoots, worker_id);
 116     Universe::oops_do(strong_roots);
 117   }
 118 
 119   if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_JNIHandles_oops_do)) {
 120     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::JNIRoots, worker_id);
 121     JNIHandles::oops_do(strong_roots);
 122   }
 123 
 124   if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_FlatProfiler_oops_do)) {
 125     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::FlatProfilerRoots, worker_id);
 126     FlatProfiler::oops_do(strong_roots);
 127   }
 128   if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_Management_oops_do)) {
 129     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ManagementRoots, worker_id);
 130     Management::oops_do(strong_roots);
 131   }
 132   if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_jvmti_oops_do)) {
 133     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::JVMTIRoots, worker_id);
 134     JvmtiExport::oops_do(strong_roots);
 135   }
 136   if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) {
 137     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::SystemDictionaryRoots, worker_id);
 138     SystemDictionary::roots_oops_do(strong_roots, weak_roots);
 139   }
 140   if (jni_weak_roots != NULL) {
 141     if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_JNIHandles_weak_oops_do)) {
 142       ShenandoahAlwaysTrueClosure always_true;
 143       ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::JNIWeakRoots, worker_id);
 144       JNIHandles::weak_oops_do(&always_true, jni_weak_roots);
 145     }
 146   }
 147 
 148   {
 149     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ObjectSynchronizerRoots, worker_id);
 150     while(_om_iterator.parallel_oops_do(strong_roots));
 151   }
 152 
 153   // All threads execute the following. A specific chunk of buckets
 154   // from the StringTable are the individual tasks.
 155   if (weak_roots != NULL) {
 156     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::StringTableRoots, worker_id);
 157     StringTable::possibly_parallel_oops_do(weak_roots);
 158   }
 159 }
 160 
 161 uint ShenandoahRootProcessor::n_workers() const {
 162   return _srs.n_threads();
 163 }
 164 
 165 ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, ShenandoahCollectorPolicy::TimingPhase phase) :
 166   _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)),
 167   _srs(n_workers),
 168   _phase(phase),
 169   _codecache_iterator(CodeCache::parallel_iterator())
 170 {
 171   heap->shenandoahPolicy()->record_workers_start(_phase);
 172 }
 173 
 174 ShenandoahRootEvacuator::~ShenandoahRootEvacuator() {
 175   delete _process_strong_tasks;
 176   ShenandoahHeap::heap()->shenandoahPolicy()->record_workers_end(_phase);
 177 }
 178 
 179 void ShenandoahRootEvacuator::process_evacuate_roots(OopClosure* oops,
 180                                                      CodeBlobClosure* blobs,
 181                                                      uint worker_id) {
 182 
 183   ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times();
 184   {
 185     bool is_par = n_workers() > 1;
 186     ResourceMark rm;
 187     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ThreadRoots, worker_id);
 188     Threads::possibly_parallel_oops_do(is_par, oops, NULL);
 189   }
 190 
 191   {
 192     ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::CodeCacheRoots, worker_id);
 193     _codecache_iterator.parallel_blobs_do(blobs);
 194   }
 195 
 196   _process_strong_tasks->all_tasks_completed(n_workers());
 197 }
 198 
 199 uint ShenandoahRootEvacuator::n_workers() const {
 200   return _srs.n_threads();
 201 }
 202 
 203 // Implemenation of ParallelCLDRootIterator
 204 ParallelCLDRootIterator::ParallelCLDRootIterator() {
 205   assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
 206   ClassLoaderDataGraph::clear_claimed_marks();
 207 }
 208 
 209 void ParallelCLDRootIterator::root_cld_do(CLDClosure* strong, CLDClosure* weak) {
 210     ClassLoaderDataGraph::roots_cld_do(strong, weak);
 211 }
 212