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