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