1 /* 2 * Copyright (c) 2013, 2021, 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 #include "precompiled.hpp" 26 27 #include "gc/shared/satbMarkQueue.hpp" 28 #include "gc/shared/strongRootsScope.hpp" 29 #include "gc/shared/taskTerminator.hpp" 30 #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" 31 #include "gc/shenandoah/shenandoahClosures.inline.hpp" 32 #include "gc/shenandoah/shenandoahConcurrentMark.hpp" 33 #include "gc/shenandoah/shenandoahGeneration.hpp" 34 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 35 #include "gc/shenandoah/shenandoahMark.inline.hpp" 36 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" 37 #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" 38 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" 39 #include "gc/shenandoah/shenandoahPhaseTimings.hpp" 40 #include "gc/shenandoah/shenandoahStringDedup.hpp" 41 #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" 42 #include "gc/shenandoah/shenandoahUtils.hpp" 43 #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" 44 #include "memory/iterator.inline.hpp" 45 #include "memory/resourceArea.hpp" 46 #include "runtime/continuation.hpp" 47 #include "runtime/threads.hpp" 48 49 template <GenerationMode GENERATION> 50 class ShenandoahConcurrentMarkingTask : public WorkerTask { 51 private: 52 ShenandoahConcurrentMark* const _cm; 53 TaskTerminator* const _terminator; 54 55 public: 56 ShenandoahConcurrentMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) : 57 WorkerTask("Shenandoah Concurrent Mark"), _cm(cm), _terminator(terminator) { 58 } 59 60 void work(uint worker_id) { 61 ShenandoahHeap* heap = ShenandoahHeap::heap(); 62 ShenandoahParallelWorkerSession worker_session(worker_id); 63 ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::ParallelMark, worker_id, true); 64 ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers); 65 ShenandoahReferenceProcessor* rp = heap->active_generation()->ref_processor(); 66 assert(rp != nullptr, "need reference processor"); 67 StringDedup::Requests requests; 68 _cm->mark_loop(GENERATION, worker_id, _terminator, rp, 69 true /*cancellable*/, 70 ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP, 71 &requests); 72 } 73 }; 74 75 class ShenandoahSATBAndRemarkThreadsClosure : public ThreadClosure { 76 private: 77 SATBMarkQueueSet& _satb_qset; 78 OopClosure* const _cl; 79 uintx _claim_token; 80 81 public: 82 ShenandoahSATBAndRemarkThreadsClosure(SATBMarkQueueSet& satb_qset, OopClosure* cl) : 83 _satb_qset(satb_qset), 84 _cl(cl) {} 85 86 void do_thread(Thread* thread) { 87 // Transfer any partial buffer to the qset for completed buffer processing. 88 _satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread)); 89 if (thread->is_Java_thread()) { 90 if (_cl != nullptr) { 91 ResourceMark rm; 92 thread->oops_do(_cl, nullptr); 93 } 94 } 95 } 96 }; 97 98 template<GenerationMode GENERATION> 99 class ShenandoahFinalMarkingTask : public WorkerTask { 100 private: 101 ShenandoahConcurrentMark* _cm; 102 TaskTerminator* _terminator; 103 bool _dedup_string; 104 105 public: 106 ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) : 107 WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) { 108 } 109 110 void work(uint worker_id) { 111 ShenandoahHeap* heap = ShenandoahHeap::heap(); 112 113 ShenandoahParallelWorkerSession worker_session(worker_id); 114 StringDedup::Requests requests; 115 ShenandoahReferenceProcessor* rp = heap->active_generation()->ref_processor(); 116 117 // First drain remaining SATB buffers. 118 { 119 ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); 120 ShenandoahObjToScanQueue* old = _cm->get_old_queue(worker_id); 121 122 ShenandoahSATBBufferClosure<GENERATION> cl(q, old); 123 SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); 124 while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {} 125 assert(!heap->has_forwarded_objects(), "Not expected"); 126 127 ShenandoahMarkRefsClosure<GENERATION> mark_cl(q, rp, old); 128 ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set, 129 ShenandoahIUBarrier ? &mark_cl : nullptr); 130 Threads::possibly_parallel_threads_do(true /* is_par */, &tc); 131 } 132 _cm->mark_loop(GENERATION, worker_id, _terminator, rp, 133 false /*not cancellable*/, 134 _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP, 135 &requests); 136 assert(_cm->task_queues()->is_empty(), "Should be empty"); 137 } 138 }; 139 140 ShenandoahConcurrentMark::ShenandoahConcurrentMark(ShenandoahGeneration* generation) : 141 ShenandoahMark(generation) {} 142 143 // Mark concurrent roots during concurrent phases 144 template<GenerationMode GENERATION> 145 class ShenandoahMarkConcurrentRootsTask : public WorkerTask { 146 private: 147 SuspendibleThreadSetJoiner _sts_joiner; 148 ShenandoahConcurrentRootScanner _root_scanner; 149 ShenandoahObjToScanQueueSet* const _queue_set; 150 ShenandoahObjToScanQueueSet* const _old_queue_set; 151 ShenandoahReferenceProcessor* const _rp; 152 153 public: 154 ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs, 155 ShenandoahObjToScanQueueSet* old, 156 ShenandoahReferenceProcessor* rp, 157 ShenandoahPhaseTimings::Phase phase, 158 uint nworkers); 159 void work(uint worker_id); 160 }; 161 162 template<GenerationMode GENERATION> 163 ShenandoahMarkConcurrentRootsTask<GENERATION>::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs, 164 ShenandoahObjToScanQueueSet* old, 165 ShenandoahReferenceProcessor* rp, 166 ShenandoahPhaseTimings::Phase phase, 167 uint nworkers) : 168 WorkerTask("Shenandoah Concurrent Mark Roots"), 169 _root_scanner(nworkers, phase), 170 _queue_set(qs), 171 _old_queue_set(old), 172 _rp(rp) { 173 assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected"); 174 } 175 176 template<GenerationMode GENERATION> 177 void ShenandoahMarkConcurrentRootsTask<GENERATION>::work(uint worker_id) { 178 ShenandoahConcurrentWorkerSession worker_session(worker_id); 179 ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id); 180 ShenandoahObjToScanQueue* old = _old_queue_set == nullptr ? nullptr : _old_queue_set->queue(worker_id); 181 ShenandoahMarkRefsClosure<GENERATION> cl(q, _rp, old); 182 _root_scanner.roots_do(&cl, worker_id); 183 } 184 185 void ShenandoahConcurrentMark::mark_concurrent_roots() { 186 ShenandoahHeap* const heap = ShenandoahHeap::heap(); 187 assert(!heap->has_forwarded_objects(), "Not expected"); 188 189 WorkerThreads* workers = heap->workers(); 190 ShenandoahReferenceProcessor* rp = _generation->ref_processor(); 191 _generation->reserve_task_queues(workers->active_workers()); 192 switch (_generation->generation_mode()) { 193 case YOUNG: { 194 ShenandoahMarkConcurrentRootsTask<YOUNG> task(task_queues(), old_task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers()); 195 workers->run_task(&task); 196 break; 197 } 198 case GLOBAL: { 199 assert(old_task_queues() == nullptr, "Global mark should not have old gen mark queues."); 200 ShenandoahMarkConcurrentRootsTask<GLOBAL> task(task_queues(), old_task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers()); 201 workers->run_task(&task); 202 break; 203 } 204 default: 205 // Intentionally haven't added OLD here. We use a YOUNG generation 206 // cycle to bootstrap concurrent old marking. 207 ShouldNotReachHere(); 208 } 209 } 210 211 class ShenandoahFlushSATBHandshakeClosure : public HandshakeClosure { 212 private: 213 SATBMarkQueueSet& _qset; 214 public: 215 ShenandoahFlushSATBHandshakeClosure(SATBMarkQueueSet& qset) : 216 HandshakeClosure("Shenandoah Flush SATB Handshake"), 217 _qset(qset) {} 218 219 void do_thread(Thread* thread) { 220 _qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread)); 221 } 222 }; 223 224 void ShenandoahConcurrentMark::concurrent_mark() { 225 ShenandoahHeap* const heap = ShenandoahHeap::heap(); 226 WorkerThreads* workers = heap->workers(); 227 uint nworkers = workers->active_workers(); 228 task_queues()->reserve(nworkers); 229 230 ShenandoahSATBMarkQueueSet& qset = ShenandoahBarrierSet::satb_mark_queue_set(); 231 ShenandoahFlushSATBHandshakeClosure flush_satb(qset); 232 for (uint flushes = 0; flushes < ShenandoahMaxSATBBufferFlushes; flushes++) { 233 switch (_generation->generation_mode()) { 234 case YOUNG: { 235 TaskTerminator terminator(nworkers, task_queues()); 236 ShenandoahConcurrentMarkingTask<YOUNG> task(this, &terminator); 237 workers->run_task(&task); 238 break; 239 } 240 case OLD: { 241 TaskTerminator terminator(nworkers, task_queues()); 242 ShenandoahConcurrentMarkingTask<OLD> task(this, &terminator); 243 workers->run_task(&task); 244 break; 245 } 246 case GLOBAL: { 247 TaskTerminator terminator(nworkers, task_queues()); 248 ShenandoahConcurrentMarkingTask<GLOBAL> task(this, &terminator); 249 workers->run_task(&task); 250 break; 251 } 252 default: 253 ShouldNotReachHere(); 254 } 255 256 if (heap->cancelled_gc()) { 257 // GC is cancelled, break out. 258 break; 259 } 260 261 size_t before = qset.completed_buffers_num(); 262 Handshake::execute(&flush_satb); 263 size_t after = qset.completed_buffers_num(); 264 265 if (before == after) { 266 // No more retries needed, break out. 267 break; 268 } 269 } 270 assert(task_queues()->is_empty() || heap->cancelled_gc(), "Should be empty when not cancelled"); 271 } 272 273 void ShenandoahConcurrentMark::finish_mark() { 274 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); 275 assert(Thread::current()->is_VM_thread(), "Must by VM Thread"); 276 finish_mark_work(); 277 assert(task_queues()->is_empty(), "Should be empty"); 278 TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats()); 279 TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); 280 281 _generation->set_concurrent_mark_in_progress(false); 282 _generation->set_mark_complete(); 283 284 end_mark(); 285 } 286 287 void ShenandoahConcurrentMark::finish_mark_work() { 288 // Finally mark everything else we've got in our queues during the previous steps. 289 // It does two different things for concurrent vs. mark-compact GC: 290 // - For concurrent GC, it starts with empty task queues, drains the remaining 291 // SATB buffers, and then completes the marking closure. 292 // - For mark-compact GC, it starts out with the task queues seeded by initial 293 // root scan, and completes the closure, thus marking through all live objects 294 // The implementation is the same, so it's shared here. 295 ShenandoahHeap* const heap = ShenandoahHeap::heap(); 296 ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark); 297 uint nworkers = heap->workers()->active_workers(); 298 task_queues()->reserve(nworkers); 299 300 StrongRootsScope scope(nworkers); 301 TaskTerminator terminator(nworkers, task_queues()); 302 303 switch (_generation->generation_mode()) { 304 case YOUNG:{ 305 ShenandoahFinalMarkingTask<YOUNG> task(this, &terminator, ShenandoahStringDedup::is_enabled()); 306 heap->workers()->run_task(&task); 307 break; 308 } 309 case OLD:{ 310 ShenandoahFinalMarkingTask<OLD> task(this, &terminator, ShenandoahStringDedup::is_enabled()); 311 heap->workers()->run_task(&task); 312 break; 313 } 314 case GLOBAL:{ 315 ShenandoahFinalMarkingTask<GLOBAL> task(this, &terminator, ShenandoahStringDedup::is_enabled()); 316 heap->workers()->run_task(&task); 317 break; 318 } 319 default: 320 ShouldNotReachHere(); 321 } 322 323 324 assert(task_queues()->is_empty(), "Should be empty"); 325 }