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 "gc/shenandoah/vm_operations_shenandoah.hpp" 35 #include "memory/allocation.inline.hpp" 36 #include "runtime/fprofiler.hpp" 37 #include "runtime/mutex.hpp" 38 #include "runtime/sweeper.hpp" 39 #include "services/management.hpp" 40 41 ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahHeap* heap, uint n_workers, 42 ShenandoahCollectorPolicy::TimingPhase phase) : 43 _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)), 44 _srs(n_workers), 45 _phase(phase), 46 _codecache_iterator(CodeCache::parallel_iterator()), 47 _om_iterator(ObjectSynchronizer::parallel_iterator()), 48 _threads_nmethods_cl(NULL) 49 { 50 heap->shenandoahPolicy()->record_workers_start(_phase); 51 VM_ShenandoahOperation* op = (VM_ShenandoahOperation*) VMThread::vm_operation(); 52 if (! op->_safepoint_cleanup_done) { 53 _threads_nmethods_cl = NMethodSweeper::prepare_mark_active_nmethods(); 54 } 55 } 56 57 ShenandoahRootProcessor::~ShenandoahRootProcessor() { 58 delete _process_strong_tasks; 59 ShenandoahHeap::heap()->shenandoahPolicy()->record_workers_end(_phase); 60 VM_ShenandoahOperation* op = (VM_ShenandoahOperation*) VMThread::vm_operation(); 61 op->_safepoint_cleanup_done = true; 62 } 63 64 void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops, 65 OopClosure* weak_oops, 66 CLDClosure* clds, 67 CodeBlobClosure* blobs, 68 uint worker_id) { 69 70 process_java_roots(oops, clds, NULL, NULL, _threads_nmethods_cl, worker_id); 71 process_vm_roots(oops, NULL, weak_oops, worker_id); 72 73 _process_strong_tasks->all_tasks_completed(n_workers()); 74 } 75 76 void ShenandoahRootProcessor::process_all_roots(OopClosure* oops, 77 OopClosure* weak_oops, 78 CLDClosure* clds, 79 CodeBlobClosure* blobs, 80 uint worker_id) { 81 82 ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times(); 83 process_java_roots(oops, clds, clds, blobs, _threads_nmethods_cl, worker_id); 84 process_vm_roots(oops, oops, weak_oops, worker_id); 85 86 if (blobs != NULL) { 87 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::CodeCacheRoots, worker_id); 88 _codecache_iterator.parallel_blobs_do(blobs); 89 } 90 91 _process_strong_tasks->all_tasks_completed(n_workers()); 92 } 93 94 void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots, 95 CLDClosure* strong_clds, 96 CLDClosure* weak_clds, 97 CodeBlobClosure* strong_code, 98 CodeBlobClosure* nmethods_cl, 99 uint worker_id) 100 { 101 ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times(); 102 // Iterating over the CLDG and the Threads are done early to allow us to 103 // first process the strong CLDs and nmethods and then, after a barrier, 104 // let the thread process the weak CLDs and nmethods. 105 { 106 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::CLDGRoots, worker_id); 107 _cld_iterator.root_cld_do(strong_clds, weak_clds); 108 } 109 110 { 111 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ThreadRoots, worker_id); 112 bool is_par = n_workers() > 1; 113 ResourceMark rm; 114 Threads::possibly_parallel_oops_do(is_par, strong_roots, strong_code, nmethods_cl); 115 } 116 } 117 118 void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots, 119 OopClosure* weak_roots, 120 OopClosure* jni_weak_roots, 121 uint worker_id) 122 { 123 ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times(); 124 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_Universe_oops_do)) { 125 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::UniverseRoots, worker_id); 126 Universe::oops_do(strong_roots); 127 } 128 129 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_JNIHandles_oops_do)) { 130 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::JNIRoots, worker_id); 131 JNIHandles::oops_do(strong_roots); 132 } 133 134 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_FlatProfiler_oops_do)) { 135 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::FlatProfilerRoots, worker_id); 136 FlatProfiler::oops_do(strong_roots); 137 } 138 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_Management_oops_do)) { 139 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ManagementRoots, worker_id); 140 Management::oops_do(strong_roots); 141 } 142 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_jvmti_oops_do)) { 143 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::JVMTIRoots, worker_id); 144 JvmtiExport::oops_do(strong_roots); 145 } 146 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) { 147 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::SystemDictionaryRoots, worker_id); 148 SystemDictionary::roots_oops_do(strong_roots, weak_roots); 149 } 150 if (jni_weak_roots != NULL) { 151 if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_JNIHandles_weak_oops_do)) { 152 ShenandoahAlwaysTrueClosure always_true; 153 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::JNIWeakRoots, worker_id); 154 JNIHandles::weak_oops_do(&always_true, jni_weak_roots); 155 } 156 } 157 158 { 159 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ObjectSynchronizerRoots, worker_id); 160 if (ShenandoahFastSyncRoots && MonitorInUseLists) { 161 ObjectSynchronizer::oops_do(strong_roots); 162 } else { 163 while(_om_iterator.parallel_oops_do(strong_roots)); 164 } 165 } 166 167 // All threads execute the following. A specific chunk of buckets 168 // from the StringTable are the individual tasks. 169 if (weak_roots != NULL) { 170 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::StringTableRoots, worker_id); 171 StringTable::possibly_parallel_oops_do(weak_roots); 172 } 173 } 174 175 uint ShenandoahRootProcessor::n_workers() const { 176 return _srs.n_threads(); 177 } 178 179 ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, ShenandoahCollectorPolicy::TimingPhase phase) : 180 _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)), 181 _srs(n_workers), 182 _phase(phase), 183 _codecache_iterator(CodeCache::parallel_iterator()), 184 _threads_nmethods_cl(NULL) 185 { 186 heap->shenandoahPolicy()->record_workers_start(_phase); 187 VM_ShenandoahOperation* op = (VM_ShenandoahOperation*) VMThread::vm_operation(); 188 if (! op->_safepoint_cleanup_done) { 189 _threads_nmethods_cl = NMethodSweeper::prepare_mark_active_nmethods(); 190 } 191 } 192 193 ShenandoahRootEvacuator::~ShenandoahRootEvacuator() { 194 delete _process_strong_tasks; 195 ShenandoahHeap::heap()->shenandoahPolicy()->record_workers_end(_phase); 196 VM_ShenandoahOperation* op = (VM_ShenandoahOperation*) VMThread::vm_operation(); 197 op->_safepoint_cleanup_done = true; 198 } 199 200 void ShenandoahRootEvacuator::process_evacuate_roots(OopClosure* oops, 201 CodeBlobClosure* blobs, 202 uint worker_id) { 203 204 ShenandoahPhaseTimes* phase_times = ShenandoahHeap::heap()->shenandoahPolicy()->phase_times(); 205 { 206 bool is_par = n_workers() > 1; 207 ResourceMark rm; 208 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::ThreadRoots, worker_id); 209 210 Threads::possibly_parallel_oops_do(is_par, oops, NULL, _threads_nmethods_cl); 211 } 212 213 { 214 ShenandoahParPhaseTimesTracker timer(phase_times, ShenandoahPhaseTimes::CodeCacheRoots, worker_id); 215 _codecache_iterator.parallel_blobs_do(blobs); 216 } 217 218 _process_strong_tasks->all_tasks_completed(n_workers()); 219 } 220 221 uint ShenandoahRootEvacuator::n_workers() const { 222 return _srs.n_threads(); 223 } 224 225 // Implemenation of ParallelCLDRootIterator 226 ParallelCLDRootIterator::ParallelCLDRootIterator() { 227 assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint"); 228 ClassLoaderDataGraph::clear_claimed_marks(); 229 } 230 231 void ParallelCLDRootIterator::root_cld_do(CLDClosure* strong, CLDClosure* weak) { 232 ClassLoaderDataGraph::roots_cld_do(strong, weak); 233 } 234