1 /* 2 * Copyright (c) 2015, 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 #include "precompiled.hpp" 25 26 #include "classfile/classLoaderDataGraph.hpp" 27 #include "classfile/stringTable.hpp" 28 #include "classfile/systemDictionary.hpp" 29 #include "code/codeCache.hpp" 30 #include "gc/shenandoah/shenandoahRootProcessor.hpp" 31 #include "gc/shenandoah/shenandoahHeap.hpp" 32 #include "gc/shenandoah/shenandoahPhaseTimings.hpp" 33 #include "gc/shenandoah/shenandoahStringDedup.hpp" 34 #include "gc/shenandoah/shenandoahTimingTracker.hpp" 35 #include "gc/shenandoah/shenandoahUtils.hpp" 36 #include "gc/shenandoah/shenandoahVMOperations.hpp" 37 #include "gc/shared/weakProcessor.inline.hpp" 38 #include "memory/allocation.inline.hpp" 39 #include "memory/iterator.hpp" 40 #include "memory/resourceArea.hpp" 41 #include "runtime/thread.hpp" 42 #include "services/management.hpp" 43 44 struct PhaseMap { 45 WeakProcessorPhases::Phase _weak_processor_phase; 46 ShenandoahPhaseTimings::GCParPhases _shenandoah_phase; 47 }; 48 49 static const struct PhaseMap phase_mapping[] = { 50 #if INCLUDE_JVMTI 51 {WeakProcessorPhases::jvmti, ShenandoahPhaseTimings::JVMTIWeakRoots}, 52 #endif 53 #if INCLUDE_JFR 54 {WeakProcessorPhases::jfr, ShenandoahPhaseTimings::JFRWeakRoots}, 55 #endif 56 {WeakProcessorPhases::jni, ShenandoahPhaseTimings::JNIWeakRoots}, 57 {WeakProcessorPhases::stringtable, ShenandoahPhaseTimings::StringTableRoots}, 58 {WeakProcessorPhases::vm, ShenandoahPhaseTimings::VMWeakRoots} 59 }; 60 61 STATIC_ASSERT(sizeof(phase_mapping) / sizeof(PhaseMap) == WeakProcessorPhases::phase_count); 62 63 ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahHeap* heap, uint n_workers, 64 ShenandoahPhaseTimings::Phase phase) : 65 _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)), 66 _srs(n_workers), 67 _par_state_string(StringTable::weak_storage()), 68 _phase(phase), 69 _coderoots_all_iterator(ShenandoahCodeRoots::iterator()), 70 _weak_processor_timings(n_workers), 71 _weak_processor_task(&_weak_processor_timings, n_workers), 72 _processed_weak_roots(false) { 73 heap->phase_timings()->record_workers_start(_phase); 74 75 if (ShenandoahStringDedup::is_enabled()) { 76 StringDedup::gc_prologue(false); 77 } 78 } 79 80 ShenandoahRootProcessor::~ShenandoahRootProcessor() { 81 delete _process_strong_tasks; 82 if (ShenandoahStringDedup::is_enabled()) { 83 StringDedup::gc_epilogue(); 84 } 85 86 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); 87 88 if (_processed_weak_roots) { 89 assert(_weak_processor_timings.max_threads() == n_workers(), "Must match"); 90 for (uint index = 0; index < WeakProcessorPhases::phase_count; index ++) { 91 weak_processor_timing_to_shenandoah_timing(phase_mapping[index]._weak_processor_phase, 92 phase_mapping[index]._shenandoah_phase, 93 worker_times); 94 } 95 } 96 97 ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase); 98 } 99 100 void ShenandoahRootProcessor::weak_processor_timing_to_shenandoah_timing(const WeakProcessorPhases::Phase wpp, 101 const ShenandoahPhaseTimings::GCParPhases spp, 102 ShenandoahWorkerTimings* worker_times) const { 103 if (WeakProcessorPhases::is_serial(wpp)) { 104 worker_times->record_time_secs(spp, 0, _weak_processor_timings.phase_time_sec(wpp)); 105 } else { 106 for (uint index = 0; index < _weak_processor_timings.max_threads(); index ++) { 107 worker_times->record_time_secs(spp, index, _weak_processor_timings.worker_time_sec(index, wpp)); 108 } 109 } 110 } 111 112 void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) { 113 CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong); 114 CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); 115 116 CodeCache::blobs_do(&blobs); 117 ClassLoaderDataGraph::cld_do(&clds); 118 Universe::oops_do(oops); 119 Management::oops_do(oops); 120 JvmtiExport::oops_do(oops); 121 JNIHandles::oops_do(oops); 122 ObjectSynchronizer::oops_do(oops); 123 SystemDictionary::oops_do(oops); 124 125 // Do thread roots the last. This allows verification code to find 126 // any broken objects from those special roots first, not the accidental 127 // dangling reference from the thread root. 128 Threads::possibly_parallel_oops_do(false, oops, &blobs); 129 } 130 131 void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops, 132 CLDClosure* clds, 133 CodeBlobClosure* blobs, 134 ThreadClosure* thread_cl, 135 uint worker_id) { 136 137 process_java_roots(oops, clds, NULL, blobs, thread_cl, worker_id); 138 process_vm_roots(oops, worker_id); 139 140 _process_strong_tasks->all_tasks_completed(n_workers()); 141 } 142 143 void ShenandoahRootProcessor::process_all_roots(OopClosure* oops, 144 CLDClosure* clds, 145 CodeBlobClosure* blobs, 146 ThreadClosure* thread_cl, 147 uint worker_id) { 148 149 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); 150 process_java_roots(oops, clds, clds, blobs, thread_cl, worker_id); 151 process_vm_roots(oops, worker_id); 152 153 if (blobs != NULL) { 154 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); 155 _coderoots_all_iterator.possibly_parallel_blobs_do(blobs); 156 } 157 158 _process_strong_tasks->all_tasks_completed(n_workers()); 159 160 } 161 162 class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure { 163 private: 164 OopClosure* _f; 165 CodeBlobClosure* _cf; 166 ThreadClosure* _thread_cl; 167 public: 168 ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) : 169 _f(f), _cf(cf), _thread_cl(thread_cl) {} 170 171 void do_thread(Thread* t) { 172 if (_thread_cl != NULL) { 173 _thread_cl->do_thread(t); 174 } 175 t->oops_do(_f, _cf); 176 } 177 }; 178 179 void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots, 180 CLDClosure* strong_clds, 181 CLDClosure* weak_clds, 182 CodeBlobClosure* strong_code, 183 ThreadClosure* thread_cl, 184 uint worker_id) 185 { 186 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); 187 // Iterating over the CLDG and the Threads are done early to allow us to 188 // first process the strong CLDs and nmethods and then, after a barrier, 189 // let the thread process the weak CLDs and nmethods. 190 { 191 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id); 192 _cld_iterator.root_cld_do(strong_clds, weak_clds); 193 } 194 195 { 196 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id); 197 bool is_par = n_workers() > 1; 198 ResourceMark rm; 199 ShenandoahParallelOopsDoThreadClosure cl(strong_roots, strong_code, thread_cl); 200 Threads::possibly_parallel_threads_do(is_par, &cl); 201 } 202 } 203 204 void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots, 205 uint worker_id) { 206 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); 207 if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Universe_oops_do)) { 208 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id); 209 Universe::oops_do(strong_roots); 210 } 211 212 if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_JNIHandles_oops_do)) { 213 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIRoots, worker_id); 214 JNIHandles::oops_do(strong_roots); 215 } 216 if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Management_oops_do)) { 217 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ManagementRoots, worker_id); 218 Management::oops_do(strong_roots); 219 } 220 if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_jvmti_oops_do)) { 221 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id); 222 JvmtiExport::oops_do(strong_roots); 223 } 224 if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) { 225 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id); 226 SystemDictionary::oops_do(strong_roots); 227 } 228 229 { 230 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id); 231 if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_ObjectSynchronizer_oops_do)) { 232 ObjectSynchronizer::oops_do(strong_roots); 233 } 234 } 235 } 236 237 uint ShenandoahRootProcessor::n_workers() const { 238 return _srs.n_threads(); 239 } 240 241 ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, ShenandoahPhaseTimings::Phase phase) : 242 _evacuation_tasks(new SubTasksDone(SHENANDOAH_EVAC_NumElements)), 243 _srs(n_workers), 244 _phase(phase), 245 _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()), 246 _par_state_string(StringTable::weak_storage()) 247 248 { 249 heap->phase_timings()->record_workers_start(_phase); 250 if (ShenandoahStringDedup::is_enabled()) { 251 StringDedup::gc_prologue(false); 252 } 253 } 254 255 ShenandoahRootEvacuator::~ShenandoahRootEvacuator() { 256 delete _evacuation_tasks; 257 if (ShenandoahStringDedup::is_enabled()) { 258 StringDedup::gc_epilogue(); 259 } 260 ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase); 261 } 262 263 void ShenandoahRootEvacuator::process_evacuate_roots(OopClosure* oops, 264 CodeBlobClosure* blobs, 265 uint worker_id) { 266 267 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); 268 { 269 bool is_par = n_workers() > 1; 270 ResourceMark rm; 271 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id); 272 273 Threads::possibly_parallel_oops_do(is_par, oops, NULL); 274 } 275 276 if (blobs != NULL) { 277 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); 278 _coderoots_cset_iterator.possibly_parallel_blobs_do(blobs); 279 } 280 281 if (ShenandoahStringDedup::is_enabled()) { 282 ShenandoahForwardedIsAliveClosure is_alive; 283 ShenandoahStringDedup::parallel_oops_do(&is_alive, oops, worker_id); 284 } 285 286 if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_Universe_oops_do)) { 287 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id); 288 Universe::oops_do(oops); 289 } 290 291 if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_Management_oops_do)) { 292 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ManagementRoots, worker_id); 293 Management::oops_do(oops); 294 } 295 296 if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_jvmti_oops_do)) { 297 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id); 298 JvmtiExport::oops_do(oops); 299 ShenandoahForwardedIsAliveClosure is_alive; 300 JvmtiExport::weak_oops_do(&is_alive, oops); 301 } 302 303 if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_SystemDictionary_oops_do)) { 304 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id); 305 SystemDictionary::oops_do(oops); 306 } 307 308 if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_ObjectSynchronizer_oops_do)) { 309 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id); 310 ObjectSynchronizer::oops_do(oops); 311 } 312 313 } 314 315 uint ShenandoahRootEvacuator::n_workers() const { 316 return _srs.n_threads(); 317 } 318 319 // Implemenation of ParallelCLDRootIterator 320 ParallelCLDRootIterator::ParallelCLDRootIterator() { 321 assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint"); 322 ClassLoaderDataGraph::clear_claimed_marks(); 323 } 324 325 void ParallelCLDRootIterator::root_cld_do(CLDClosure* strong, CLDClosure* weak) { 326 ClassLoaderDataGraph::roots_cld_do(strong, weak); 327 }