1 /*
   2  * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
   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 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
  25 #define SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
  26 
  27 #include "classfile/classLoaderDataGraph.hpp"
  28 #include "classfile/stringTable.hpp"
  29 #include "classfile/systemDictionary.hpp"
  30 #include "gc/shared/oopStorageParState.inline.hpp"
  31 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
  32 #include "gc/shenandoah/shenandoahConcurrentRoots.hpp"
  33 #include "gc/shenandoah/shenandoahHeuristics.hpp"
  34 #include "gc/shenandoah/shenandoahRootProcessor.hpp"
  35 #include "gc/shenandoah/shenandoahTimingTracker.hpp"
  36 #include "gc/shenandoah/shenandoahUtils.hpp"
  37 #include "memory/resourceArea.hpp"
  38 #include "prims/resolvedMethodTable.hpp"
  39 #include "runtime/safepoint.hpp"
  40 
  41 template <bool CONCURRENT>
  42 inline ShenandoahVMRoot<CONCURRENT>::ShenandoahVMRoot(OopStorage* storage, ShenandoahPhaseTimings::GCParPhases phase) :
  43   _itr(storage), _phase(phase) {
  44 }
  45 
  46 template <bool CONCURRENT>
  47 template <typename Closure>
  48 inline void ShenandoahVMRoot<CONCURRENT>::oops_do(Closure* cl, uint worker_id) {
  49   if (CONCURRENT) {
  50     _itr.oops_do(cl);
  51   } else {
  52     ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
  53     ShenandoahWorkerTimingsTracker timer(worker_times, _phase, worker_id);
  54     _itr.oops_do(cl);
  55   }
  56 }
  57 
  58 template <bool CONCURRENT>
  59 inline ShenandoahWeakRoot<CONCURRENT>::ShenandoahWeakRoot(OopStorage* storage, ShenandoahPhaseTimings::GCParPhases phase) :
  60   ShenandoahVMRoot<CONCURRENT>(storage, phase) {
  61 }
  62 
  63 inline ShenandoahWeakRoot<false>::ShenandoahWeakRoot(OopStorage* storage, ShenandoahPhaseTimings::GCParPhases phase) :
  64   _itr(storage), _phase(phase) {
  65 }
  66 
  67 template <typename IsAliveClosure, typename KeepAliveClosure>
  68 void ShenandoahWeakRoot<false /* concurrent */>::weak_oops_do(IsAliveClosure* is_alive, KeepAliveClosure* keep_alive, uint worker_id) {
  69   ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
  70   ShenandoahWorkerTimingsTracker timer(worker_times, _phase, worker_id);
  71   _itr.weak_oops_do(is_alive, keep_alive);
  72 }
  73 
  74 template <bool CONCURRENT>
  75 ShenandoahWeakRoots<CONCURRENT>::ShenandoahWeakRoots() :
  76   _jni_roots(JNIHandles::weak_global_handles(), ShenandoahPhaseTimings::JNIWeakRoots),
  77   _string_table_roots(StringTable::weak_storage(), ShenandoahPhaseTimings::StringTableRoots),
  78   _resolved_method_table_roots(ResolvedMethodTable::weak_storage(), ShenandoahPhaseTimings::ResolvedMethodTableRoots),
  79   _vm_roots(SystemDictionary::vm_weak_oop_storage(), ShenandoahPhaseTimings::VMWeakRoots) {
  80 }
  81 
  82 template <bool CONCURRENT>
  83 template <typename Closure>
  84 void ShenandoahWeakRoots<CONCURRENT>::oops_do(Closure* cl, uint worker_id) {
  85   _jni_roots.oops_do(cl, worker_id);
  86   _string_table_roots.oops_do(cl, worker_id);
  87   _resolved_method_table_roots.oops_do(cl, worker_id);
  88   _vm_roots.oops_do(cl, worker_id);
  89 }
  90 
  91 inline ShenandoahWeakRoots<false /* concurrent */>::ShenandoahWeakRoots() :
  92   _jni_roots(JNIHandles::weak_global_handles(), ShenandoahPhaseTimings::JNIWeakRoots),
  93   _string_table_roots(StringTable::weak_storage(), ShenandoahPhaseTimings::StringTableRoots),
  94   _resolved_method_table_roots(ResolvedMethodTable::weak_storage(), ShenandoahPhaseTimings::ResolvedMethodTableRoots),
  95   _vm_roots(SystemDictionary::vm_weak_oop_storage(), ShenandoahPhaseTimings::VMWeakRoots) {
  96 }
  97 
  98 template <typename IsAliveClosure, typename KeepAliveClosure>
  99 void ShenandoahWeakRoots<false /* concurrent*/>::weak_oops_do(IsAliveClosure* is_alive, KeepAliveClosure* keep_alive, uint worker_id) {
 100   _jni_roots.weak_oops_do(is_alive, keep_alive, worker_id);
 101   _string_table_roots.weak_oops_do(is_alive, keep_alive, worker_id);
 102   _resolved_method_table_roots.weak_oops_do(is_alive, keep_alive, worker_id);
 103   _vm_roots.weak_oops_do(is_alive, keep_alive, worker_id);
 104 }
 105 
 106 template <typename Closure>
 107 void ShenandoahWeakRoots<false /* concurrent */>::oops_do(Closure* cl, uint worker_id) {
 108   AlwaysTrueClosure always_true;
 109   weak_oops_do<AlwaysTrueClosure, Closure>(&always_true, cl, worker_id);
 110 }
 111 
 112 template <bool CONCURRENT>
 113 ShenandoahVMRoots<CONCURRENT>::ShenandoahVMRoots() :
 114   _jni_handle_roots(JNIHandles::global_handles(), ShenandoahPhaseTimings::JNIRoots),
 115   _vm_global_roots(SystemDictionary::vm_global_oop_storage(), ShenandoahPhaseTimings::VMGlobalRoots) {
 116 }
 117 
 118 template <bool CONCURRENT>
 119 template <typename T>
 120 void ShenandoahVMRoots<CONCURRENT>::oops_do(T* cl, uint worker_id) {
 121   _jni_handle_roots.oops_do(cl, worker_id);
 122   _vm_global_roots.oops_do(cl, worker_id);
 123 }
 124 
 125 template <bool CONCURRENT, bool SINGLE_THREADED>
 126 ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::ShenandoahClassLoaderDataRoots() {
 127   if (!SINGLE_THREADED) {
 128     ClassLoaderDataGraph::clear_claimed_marks();
 129   }
 130   if (CONCURRENT) {
 131     ClassLoaderDataGraph_lock->lock();
 132   }
 133 }
 134 
 135 template <bool CONCURRENT, bool SINGLE_THREADED>
 136 ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::~ShenandoahClassLoaderDataRoots() {
 137   if (CONCURRENT) {
 138     ClassLoaderDataGraph_lock->unlock();
 139   }
 140 }
 141 
 142 
 143 template <bool CONCURRENT, bool SINGLE_THREADED>
 144 void ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::always_strong_cld_do(CLDClosure* clds, uint worker_id) {
 145   if (SINGLE_THREADED) {
 146     assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 147     assert(Thread::current()->is_VM_thread(), "Single threaded CLDG iteration can only be done by VM thread");
 148     ClassLoaderDataGraph::always_strong_cld_do(clds);
 149   } else if (CONCURRENT) {
 150      ClassLoaderDataGraph::always_strong_cld_do(clds);
 151   } else {
 152    ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
 153    ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
 154    ClassLoaderDataGraph::always_strong_cld_do(clds);
 155   }
 156 }
 157 
 158 template <bool CONCURRENT, bool SINGLE_THREADED>
 159 void ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::cld_do(CLDClosure* clds, uint worker_id) {
 160   if (SINGLE_THREADED) {
 161     assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 162     assert(Thread::current()->is_VM_thread(), "Single threaded CLDG iteration can only be done by VM thread");
 163     ClassLoaderDataGraph::cld_do(clds);
 164   } else if (CONCURRENT) {
 165     ClassLoaderDataGraph::cld_do(clds);
 166   }  else {
 167     ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
 168     ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
 169     ClassLoaderDataGraph::cld_do(clds);
 170   }
 171 }
 172 
 173 template <typename ITR>
 174 ShenandoahCodeCacheRoots<ITR>::ShenandoahCodeCacheRoots() {
 175   nmethod::oops_do_marking_prologue();
 176 }
 177 
 178 template <typename ITR>
 179 void ShenandoahCodeCacheRoots<ITR>::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) {
 180   ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
 181   ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
 182   _coderoots_iterator.possibly_parallel_blobs_do(blob_cl);
 183 }
 184 
 185 template <typename ITR>
 186 ShenandoahCodeCacheRoots<ITR>::~ShenandoahCodeCacheRoots() {
 187   nmethod::oops_do_marking_epilogue();
 188 }
 189 
 190 class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
 191 private:
 192   OopClosure* _f;
 193   CodeBlobClosure* _cf;
 194   ThreadClosure* _thread_cl;
 195 public:
 196   ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) :
 197     _f(f), _cf(cf), _thread_cl(thread_cl) {}
 198 
 199   void do_thread(Thread* t) {
 200     if (_thread_cl != NULL) {
 201       _thread_cl->do_thread(t);
 202     }
 203     t->oops_do(_f, _cf);
 204   }
 205 };
 206 
 207 template <typename ITR>
 208 ShenandoahRootScanner<ITR>::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
 209   ShenandoahRootProcessor(phase),
 210   _thread_roots(n_workers > 1) {
 211 }
 212 
 213 template <typename ITR>
 214 void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops) {
 215   CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
 216   MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
 217   roots_do(worker_id, oops, &clds_cl, &blobs_cl);
 218 }
 219 
 220 template <typename ITR>
 221 void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops) {
 222   CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
 223   MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
 224   strong_roots_do(worker_id, oops, &clds_cl, &blobs_cl);
 225 }
 226 
 227 template <typename ITR>
 228 void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) {
 229   assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint() ||
 230          !ShenandoahHeap::heap()->unload_classes() ||
 231           ShenandoahHeap::heap()->is_traversal_mode(),
 232           "Expect class unloading or traversal when Shenandoah cycle is running");
 233   ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
 234   ResourceMark rm;
 235 
 236   _serial_roots.oops_do(oops, worker_id);
 237   _vm_roots.oops_do(oops, worker_id);
 238 
 239   if (clds != NULL) {
 240     _cld_roots.cld_do(clds, worker_id);
 241   } else {
 242     assert(ShenandoahHeap::heap()->is_concurrent_traversal_in_progress(), "Only possible with traversal GC");
 243   }
 244 
 245   _thread_roots.threads_do(&tc_cl, worker_id);
 246 
 247   // With ShenandoahConcurrentScanCodeRoots, we avoid scanning the entire code cache here,
 248   // and instead do that in concurrent phase under the relevant lock. This saves init mark
 249   // pause time.
 250   if (code != NULL && !ShenandoahConcurrentScanCodeRoots) {
 251     _code_roots.code_blobs_do(code, worker_id);
 252   }
 253 }
 254 
 255 template <typename ITR>
 256 void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
 257   assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
 258   ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
 259   ResourceMark rm;
 260 
 261   _serial_roots.oops_do(oops, worker_id);
 262   _vm_roots.oops_do(oops, worker_id);
 263   _cld_roots.always_strong_cld_do(clds, worker_id);
 264   _thread_roots.threads_do(&tc_cl, worker_id);
 265 }
 266 
 267 template <typename IsAlive, typename KeepAlive>
 268 void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) {
 269   CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations);
 270   ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(keep_alive);
 271   CodeBlobToOopClosure* codes_cl = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ?
 272                                   static_cast<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
 273                                   static_cast<CodeBlobToOopClosure*>(&update_blobs);
 274 
 275   CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong);
 276 
 277   _serial_roots.oops_do(keep_alive, worker_id);
 278   _vm_roots.oops_do(keep_alive, worker_id);
 279 
 280   _cld_roots.cld_do(&clds, worker_id);
 281   _code_roots.code_blobs_do(&update_blobs, worker_id);
 282   _thread_roots.oops_do(keep_alive, NULL, worker_id);
 283 
 284   _serial_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);
 285   _weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);
 286   _dedup_roots.oops_do(is_alive, keep_alive, worker_id);
 287 }
 288 
 289 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP