1 /* 2 * Copyright (c) 2021, 2022, Red Hat, Inc. All rights reserved. 3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 27 #include "precompiled.hpp" 28 29 #include "gc/shared/strongRootsScope.hpp" 30 #include "gc/shared/taskTerminator.hpp" 31 #include "gc/shared/workerThread.hpp" 32 #include "gc/shenandoah/shenandoahClosures.inline.hpp" 33 #include "gc/shenandoah/shenandoahGeneration.hpp" 34 #include "gc/shenandoah/shenandoahGenerationType.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/shenandoahSTWMark.hpp" 39 #include "gc/shenandoah/shenandoahVerifier.hpp" 40 41 class ShenandoahSTWMarkTask : public WorkerTask { 42 private: 43 ShenandoahSTWMark* const _mark; 44 45 public: 46 ShenandoahSTWMarkTask(ShenandoahSTWMark* mark); 47 void work(uint worker_id); 48 }; 49 50 ShenandoahSTWMarkTask::ShenandoahSTWMarkTask(ShenandoahSTWMark* mark) : 51 WorkerTask("Shenandoah STW mark"), 52 _mark(mark) { 53 } 54 55 void ShenandoahSTWMarkTask::work(uint worker_id) { 56 ShenandoahParallelWorkerSession worker_session(worker_id); 57 _mark->mark_roots(worker_id); 58 _mark->finish_mark(worker_id); 59 } 60 61 ShenandoahSTWMark::ShenandoahSTWMark(ShenandoahGeneration* generation, bool full_gc) : 62 ShenandoahMark(generation), 63 _root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark), 64 _terminator(ShenandoahHeap::heap()->workers()->active_workers(), task_queues()), 65 _full_gc(full_gc) { 66 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a Shenandoah safepoint"); 67 } 68 69 void ShenandoahSTWMark::mark() { 70 ShenandoahHeap* const heap = ShenandoahHeap::heap(); 71 72 // Arm all nmethods. Even though this is STW mark, some marking code 73 // piggybacks on nmethod barriers for special instances. 74 ShenandoahCodeRoots::arm_nmethods_for_mark(); 75 76 // Weak reference processing 77 assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); 78 ShenandoahReferenceProcessor* rp = _generation->ref_processor(); 79 shenandoah_assert_generations_reconciled(); 80 rp->reset_thread_locals(); 81 rp->set_soft_reference_policy(heap->soft_ref_policy()->should_clear_all_soft_refs()); 82 83 // Init mark, do not expect forwarded pointers in roots 84 if (ShenandoahVerify) { 85 assert(Thread::current()->is_VM_thread(), "Must be"); 86 heap->verifier()->verify_roots_no_forwarded(); 87 } 88 89 start_mark(); 90 91 uint nworkers = heap->workers()->active_workers(); 92 task_queues()->reserve(nworkers); 93 94 TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); 95 96 { 97 // Mark 98 if (_generation->is_young()) { 99 // But only scan the remembered set for young generation. 100 _generation->scan_remembered_set(false /* is_concurrent */); 101 } 102 103 StrongRootsScope scope(nworkers); 104 ShenandoahSTWMarkTask task(this); 105 heap->workers()->run_task(&task); 106 107 assert(task_queues()->is_empty(), "Should be empty"); 108 } 109 110 _generation->set_mark_complete(); 111 end_mark(); 112 113 // Mark is finished, can disarm the nmethods now. 114 ShenandoahCodeRoots::disarm_nmethods(); 115 116 assert(task_queues()->is_empty(), "Should be empty"); 117 TASKQUEUE_STATS_ONLY(task_queues()->print_and_reset_taskqueue_stats("")); 118 } 119 120 void ShenandoahSTWMark::mark_roots(uint worker_id) { 121 assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); 122 ShenandoahReferenceProcessor* rp = _generation->ref_processor(); 123 auto queue = task_queues()->queue(worker_id); 124 switch (_generation->type()) { 125 case NON_GEN: { 126 ShenandoahMarkRefsClosure<NON_GEN> init_mark(queue, rp, nullptr); 127 _root_scanner.roots_do(&init_mark, worker_id); 128 break; 129 } 130 case GLOBAL: { 131 ShenandoahMarkRefsClosure<GLOBAL> init_mark(queue, rp, nullptr); 132 _root_scanner.roots_do(&init_mark, worker_id); 133 break; 134 } 135 case YOUNG: { 136 ShenandoahMarkRefsClosure<YOUNG> init_mark(queue, rp, nullptr); 137 _root_scanner.roots_do(&init_mark, worker_id); 138 break; 139 } 140 case OLD: 141 // We never exclusively mark the old generation on a safepoint. This would be encompassed 142 // by a 'global' collection. Note that both GLOBAL and NON_GEN mark the entire heap, but 143 // the GLOBAL closure is specialized for the generational mode. 144 default: 145 ShouldNotReachHere(); 146 } 147 } 148 149 void ShenandoahSTWMark::finish_mark(uint worker_id) { 150 assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); 151 ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark; 152 ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id); 153 ShenandoahReferenceProcessor* rp = _generation->ref_processor(); 154 shenandoah_assert_generations_reconciled(); 155 StringDedup::Requests requests; 156 157 mark_loop(worker_id, &_terminator, rp, 158 _generation->type(), false /* not cancellable */, 159 ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests); 160 }