1 /* 2 * Copyright (c) 2019, 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 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP 26 #define SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP 27 28 #include "classfile/classLoaderDataGraph.hpp" 29 #include "classfile/stringTable.hpp" 30 #include "classfile/systemDictionary.hpp" 31 #include "gc/shared/oopStorageParState.inline.hpp" 32 #include "gc/shenandoah/shenandoahClosures.inline.hpp" 33 #include "gc/shenandoah/shenandoahConcurrentRoots.hpp" 34 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 35 #include "gc/shenandoah/shenandoahPhaseTimings.hpp" 36 #include "gc/shenandoah/shenandoahRootProcessor.hpp" 37 #include "gc/shenandoah/shenandoahUtils.hpp" 38 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" 39 #include "memory/resourceArea.hpp" 40 #include "prims/resolvedMethodTable.hpp" 41 #include "runtime/safepoint.hpp" 42 43 template <bool CONCURRENT> 44 inline ShenandoahVMRoot<CONCURRENT>::ShenandoahVMRoot(OopStorage* storage, 45 ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) : 46 _itr(storage), _phase(phase), _par_phase(par_phase) { 47 } 48 49 template <bool CONCURRENT> 50 template <typename Closure> 51 inline void ShenandoahVMRoot<CONCURRENT>::oops_do(Closure* cl, uint worker_id) { 52 ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id); 53 _itr.oops_do(cl); 54 } 55 56 template <bool CONCURRENT> 57 inline ShenandoahWeakRoot<CONCURRENT>::ShenandoahWeakRoot(OopStorage* storage, 58 ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) : 59 ShenandoahVMRoot<CONCURRENT>(storage, phase, par_phase) { 60 } 61 62 inline ShenandoahWeakRoot<false>::ShenandoahWeakRoot(OopStorage* storage, 63 ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) : 64 _itr(storage), _phase(phase), _par_phase(par_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 ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id); 70 _itr.weak_oops_do(is_alive, keep_alive); 71 } 72 73 template <bool CONCURRENT> 74 ShenandoahWeakRoots<CONCURRENT>::ShenandoahWeakRoots() : 75 _jni_roots(OopStorageSet::jni_weak(), ShenandoahPhaseTimings::JNIWeakRoots), 76 _string_table_roots(OopStorageSet::string_table_weak(), ShenandoahPhaseTimings::StringTableRoots), 77 _resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), ShenandoahPhaseTimings::ResolvedMethodTableRoots), 78 _vm_roots(OopStorageSet::vm_weak(), ShenandoahPhaseTimings::VMWeakRoots) { 79 StringTable::reset_dead_counter(); 80 ResolvedMethodTable::reset_dead_counter(); 81 } 82 83 template <bool CONCURRENT> 84 ShenandoahWeakRoots<CONCURRENT>::~ShenandoahWeakRoots() { 85 StringTable::finish_dead_counter(); 86 ResolvedMethodTable::finish_dead_counter(); 87 } 88 89 template <bool CONCURRENT> 90 template <typename Closure> 91 void ShenandoahWeakRoots<CONCURRENT>::oops_do(Closure* cl, uint worker_id) { 92 _jni_roots.oops_do(cl, worker_id); 93 _string_table_roots.oops_do(cl, worker_id); 94 _resolved_method_table_roots.oops_do(cl, worker_id); 95 _vm_roots.oops_do(cl, worker_id); 96 } 97 98 inline ShenandoahWeakRoots<false /* concurrent */>::ShenandoahWeakRoots(ShenandoahPhaseTimings::Phase phase) : 99 _jni_roots(OopStorageSet::jni_weak(), phase, ShenandoahPhaseTimings::JNIWeakRoots), 100 _string_table_roots(OopStorageSet::string_table_weak(), phase, ShenandoahPhaseTimings::StringTableRoots), 101 _resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), phase, ShenandoahPhaseTimings::ResolvedMethodTableRoots), 102 _vm_roots(OopStorageSet::vm_weak(), phase, ShenandoahPhaseTimings::VMWeakRoots) { 103 } 104 105 template <typename IsAliveClosure, typename KeepAliveClosure> 106 void ShenandoahWeakRoots<false /* concurrent*/>::weak_oops_do(IsAliveClosure* is_alive, KeepAliveClosure* keep_alive, uint worker_id) { 107 _jni_roots.weak_oops_do(is_alive, keep_alive, worker_id); 108 _string_table_roots.weak_oops_do(is_alive, keep_alive, worker_id); 109 _resolved_method_table_roots.weak_oops_do(is_alive, keep_alive, worker_id); 110 _vm_roots.weak_oops_do(is_alive, keep_alive, worker_id); 111 } 112 113 template <typename Closure> 114 void ShenandoahWeakRoots<false /* concurrent */>::oops_do(Closure* cl, uint worker_id) { 115 AlwaysTrueClosure always_true; 116 weak_oops_do<AlwaysTrueClosure, Closure>(&always_true, cl, worker_id); 117 } 118 119 template <bool CONCURRENT> 120 ShenandoahVMRoots<CONCURRENT>::ShenandoahVMRoots(ShenandoahPhaseTimings::Phase phase) : 121 _jni_handle_roots(OopStorageSet::jni_global(), phase, ShenandoahPhaseTimings::JNIRoots), 122 _vm_global_roots(OopStorageSet::vm_global(), phase, ShenandoahPhaseTimings::VMGlobalRoots) { 123 } 124 125 template <bool CONCURRENT> 126 template <typename T> 127 void ShenandoahVMRoots<CONCURRENT>::oops_do(T* cl, uint worker_id) { 128 _jni_handle_roots.oops_do(cl, worker_id); 129 _vm_global_roots.oops_do(cl, worker_id); 130 } 131 132 template <bool CONCURRENT, bool SINGLE_THREADED> 133 ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::ShenandoahClassLoaderDataRoots(ShenandoahPhaseTimings::Phase phase, uint n_workers) : 134 _semaphore(worker_count(n_workers)), 135 _phase(phase) { 136 if (!SINGLE_THREADED) { 137 ClassLoaderDataGraph::clear_claimed_marks(); 138 } 139 if (CONCURRENT) { 140 ClassLoaderDataGraph_lock->lock(); 141 } 142 } 143 144 template <bool CONCURRENT, bool SINGLE_THREADED> 145 ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::~ShenandoahClassLoaderDataRoots() { 146 if (CONCURRENT) { 147 ClassLoaderDataGraph_lock->unlock(); 148 } 149 } 150 151 152 template <bool CONCURRENT, bool SINGLE_THREADED> 153 void ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::always_strong_cld_do(CLDClosure* clds, uint worker_id) { 154 if (SINGLE_THREADED) { 155 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 156 assert(Thread::current()->is_VM_thread(), "Single threaded CLDG iteration can only be done by VM thread"); 157 ClassLoaderDataGraph::always_strong_cld_do(clds); 158 } else if (_semaphore.try_acquire()) { 159 ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id); 160 ClassLoaderDataGraph::always_strong_cld_do(clds); 161 _semaphore.claim_all(); 162 } 163 } 164 165 template <bool CONCURRENT, bool SINGLE_THREADED> 166 void ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::cld_do(CLDClosure* clds, uint worker_id) { 167 if (SINGLE_THREADED) { 168 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 169 assert(Thread::current()->is_VM_thread(), "Single threaded CLDG iteration can only be done by VM thread"); 170 ClassLoaderDataGraph::cld_do(clds); 171 } else if (_semaphore.try_acquire()) { 172 ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id); 173 ClassLoaderDataGraph::cld_do(clds); 174 _semaphore.claim_all(); 175 } 176 } 177 178 class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure { 179 private: 180 OopClosure* _f; 181 CodeBlobClosure* _cf; 182 ThreadClosure* _thread_cl; 183 public: 184 ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) : 185 _f(f), _cf(cf), _thread_cl(thread_cl) {} 186 187 void do_thread(Thread* t) { 188 if (_thread_cl != NULL) { 189 _thread_cl->do_thread(t); 190 } 191 t->oops_do(_f, _cf); 192 } 193 }; 194 195 template <bool CONCURRENT> 196 ShenandoahConcurrentRootScanner<CONCURRENT>::ShenandoahConcurrentRootScanner(uint n_workers, 197 ShenandoahPhaseTimings::Phase phase) : 198 _vm_roots(phase), 199 _cld_roots(phase, n_workers), 200 _dedup_roots(phase), 201 _codecache_snapshot(NULL), 202 _phase(phase) { 203 if (!ShenandoahHeap::heap()->unload_classes()) { 204 if (CONCURRENT) { 205 CodeCache_lock->lock_without_safepoint_check(); 206 } else { 207 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 208 } 209 _codecache_snapshot = ShenandoahCodeRoots::table()->snapshot_for_iteration(); 210 } 211 assert(!CONCURRENT || !ShenandoahHeap::heap()->has_forwarded_objects(), "Not expecting forwarded pointers during concurrent marking"); 212 } 213 214 template <bool CONCURRENT> 215 ShenandoahConcurrentRootScanner<CONCURRENT>::~ShenandoahConcurrentRootScanner() { 216 if (!ShenandoahHeap::heap()->unload_classes()) { 217 ShenandoahCodeRoots::table()->finish_iteration(_codecache_snapshot); 218 if (CONCURRENT) { 219 CodeCache_lock->unlock(); 220 } 221 } 222 } 223 224 template <bool CONCURRENT> 225 void ShenandoahConcurrentRootScanner<CONCURRENT>::oops_do(OopClosure* oops, uint worker_id) { 226 ShenandoahHeap* const heap = ShenandoahHeap::heap(); 227 CLDToOopClosure clds_cl(oops, CONCURRENT ? ClassLoaderData::_claim_strong : ClassLoaderData::_claim_none); 228 _vm_roots.oops_do(oops, worker_id); 229 230 if (!heap->unload_classes()) { 231 AlwaysTrueClosure always_true; 232 _cld_roots.cld_do(&clds_cl, worker_id); 233 _dedup_roots.oops_do(&always_true, oops, worker_id); 234 ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); 235 CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); 236 _codecache_snapshot->parallel_blobs_do(&blobs); 237 } else { 238 _cld_roots.always_strong_cld_do(&clds_cl, worker_id); 239 } 240 } 241 242 template <typename IsAlive, typename KeepAlive> 243 void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { 244 CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations); 245 ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(keep_alive); 246 CodeBlobToOopClosure* codes_cl = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ? 247 static_cast<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) : 248 static_cast<CodeBlobToOopClosure*>(&update_blobs); 249 250 CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong); 251 252 // Process serial-claiming roots first 253 _serial_roots.oops_do(keep_alive, worker_id); 254 _serial_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id); 255 256 // Process light-weight/limited parallel roots then 257 _vm_roots.oops_do(keep_alive, worker_id); 258 _weak_roots.weak_oops_do(is_alive, keep_alive, worker_id); 259 _dedup_roots.oops_do(is_alive, keep_alive, worker_id); 260 _cld_roots.cld_do(&clds, worker_id); 261 262 // Process heavy-weight/fully parallel roots the last 263 _code_roots.code_blobs_do(codes_cl, worker_id); 264 _thread_roots.oops_do(keep_alive, NULL, worker_id); 265 } 266 267 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP