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/shenandoahOopClosures.inline.hpp" 37 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" 38 #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" 39 #include "gc/shenandoah/shenandoahSTWMark.hpp" 40 #include "gc/shenandoah/shenandoahVerifier.hpp" 41 42 template<ShenandoahGenerationType GENERATION> 43 class ShenandoahInitMarkRootsClosure : public OopClosure { 44 private: 45 ShenandoahObjToScanQueue* const _queue; 46 ShenandoahMarkingContext* const _mark_context; 47 48 template <class T> 49 inline void do_oop_work(T* p); 50 51 public: 52 ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q); 53 54 void do_oop(narrowOop* p) { do_oop_work(p); } 55 void do_oop(oop* p) { do_oop_work(p); } 56 }; 57 58 template <ShenandoahGenerationType GENERATION> 59 ShenandoahInitMarkRootsClosure<GENERATION>::ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q) : 60 _queue(q), 61 _mark_context(ShenandoahHeap::heap()->marking_context()) { 62 } 63 64 template <ShenandoahGenerationType GENERATION> 65 template <class T> 66 void ShenandoahInitMarkRootsClosure<GENERATION>::do_oop_work(T* p) { 67 // Only called from STW mark, should not be used to bootstrap old generation marking. 68 ShenandoahMark::mark_through_ref<T, GENERATION>(p, _queue, nullptr, _mark_context, false); 69 } 70 71 class ShenandoahSTWMarkTask : public WorkerTask { 72 private: 73 ShenandoahSTWMark* const _mark; 74 75 public: 76 ShenandoahSTWMarkTask(ShenandoahSTWMark* mark); 77 void work(uint worker_id); 78 }; 79 80 ShenandoahSTWMarkTask::ShenandoahSTWMarkTask(ShenandoahSTWMark* mark) : 81 WorkerTask("Shenandoah STW mark"), 82 _mark(mark) { 83 } 84 85 void ShenandoahSTWMarkTask::work(uint worker_id) { 86 ShenandoahParallelWorkerSession worker_session(worker_id); 87 _mark->mark_roots(worker_id); 88 _mark->finish_mark(worker_id); 89 } 90 91 ShenandoahSTWMark::ShenandoahSTWMark(ShenandoahGeneration* generation, bool full_gc) : 92 ShenandoahMark(generation), 93 _root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark), 94 _terminator(ShenandoahHeap::heap()->workers()->active_workers(), task_queues()), 95 _full_gc(full_gc) { 96 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a Shenandoah safepoint"); 97 } 98 99 void ShenandoahSTWMark::mark() { 100 ShenandoahHeap* const heap = ShenandoahHeap::heap(); 101 102 // Arm all nmethods. Even though this is STW mark, some marking code 103 // piggybacks on nmethod barriers for special instances. 104 ShenandoahCodeRoots::arm_nmethods_for_mark(); 105 106 // Weak reference processing 107 ShenandoahReferenceProcessor* rp = heap->gc_generation()->ref_processor(); 108 shenandoah_assert_generations_reconciled(); 109 rp->reset_thread_locals(); 110 rp->set_soft_reference_policy(heap->soft_ref_policy()->should_clear_all_soft_refs()); 111 112 // Init mark, do not expect forwarded pointers in roots 113 if (ShenandoahVerify) { 114 assert(Thread::current()->is_VM_thread(), "Must be"); 115 heap->verifier()->verify_roots_no_forwarded(); 116 } 117 118 start_mark(); 119 120 uint nworkers = heap->workers()->active_workers(); 121 task_queues()->reserve(nworkers); 122 123 TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); 124 125 { 126 // Mark 127 if (_generation->is_young()) { 128 // But only scan the remembered set for young generation. 129 _generation->scan_remembered_set(false /* is_concurrent */); 130 } 131 132 StrongRootsScope scope(nworkers); 133 ShenandoahSTWMarkTask task(this); 134 heap->workers()->run_task(&task); 135 136 assert(task_queues()->is_empty(), "Should be empty"); 137 } 138 139 _generation->set_mark_complete(); 140 end_mark(); 141 142 // Mark is finished, can disarm the nmethods now. 143 ShenandoahCodeRoots::disarm_nmethods(); 144 145 assert(task_queues()->is_empty(), "Should be empty"); 146 TASKQUEUE_STATS_ONLY(task_queues()->print_and_reset_taskqueue_stats("")); 147 } 148 149 void ShenandoahSTWMark::mark_roots(uint worker_id) { 150 switch (_generation->type()) { 151 case NON_GEN: { 152 ShenandoahInitMarkRootsClosure<NON_GEN> init_mark(task_queues()->queue(worker_id)); 153 _root_scanner.roots_do(&init_mark, worker_id); 154 break; 155 } 156 case GLOBAL: { 157 ShenandoahInitMarkRootsClosure<GLOBAL> init_mark(task_queues()->queue(worker_id)); 158 _root_scanner.roots_do(&init_mark, worker_id); 159 break; 160 } 161 case YOUNG: { 162 ShenandoahInitMarkRootsClosure<YOUNG> init_mark(task_queues()->queue(worker_id)); 163 _root_scanner.roots_do(&init_mark, worker_id); 164 break; 165 } 166 case OLD: 167 default: 168 ShouldNotReachHere(); 169 } 170 } 171 172 void ShenandoahSTWMark::finish_mark(uint worker_id) { 173 ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark; 174 ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id); 175 ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->gc_generation()->ref_processor(); 176 shenandoah_assert_generations_reconciled(); 177 StringDedup::Requests requests; 178 179 mark_loop(worker_id, &_terminator, rp, 180 _generation->type(), false /* not cancellable */, 181 ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests); 182 }