1 /*
2 * Copyright (c) 2021, 2022, 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
26 #include "precompiled.hpp"
27
28 #include "gc/shared/strongRootsScope.hpp"
29 #include "gc/shared/taskTerminator.hpp"
30 #include "gc/shared/workerThread.hpp"
31 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
32 #include "gc/shenandoah/shenandoahMark.inline.hpp"
33 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
34 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
35 #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
36 #include "gc/shenandoah/shenandoahSTWMark.hpp"
37 #include "gc/shenandoah/shenandoahVerifier.hpp"
38
39 class ShenandoahInitMarkRootsClosure : public OopClosure {
40 private:
41 ShenandoahObjToScanQueue* const _queue;
42 ShenandoahMarkingContext* const _mark_context;
43
44 template <class T>
45 inline void do_oop_work(T* p);
46 public:
47 ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q);
48
49 void do_oop(narrowOop* p) { do_oop_work(p); }
50 void do_oop(oop* p) { do_oop_work(p); }
51 };
52
53 ShenandoahInitMarkRootsClosure::ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q) :
54 _queue(q),
55 _mark_context(ShenandoahHeap::heap()->marking_context()) {
56 }
57
58 template <class T>
59 void ShenandoahInitMarkRootsClosure::do_oop_work(T* p) {
60 ShenandoahMark::mark_through_ref<T>(p, _queue, _mark_context, false);
61 }
62
63 class ShenandoahSTWMarkTask : public WorkerTask {
64 private:
65 ShenandoahSTWMark* const _mark;
66
67 public:
68 ShenandoahSTWMarkTask(ShenandoahSTWMark* mark);
69 void work(uint worker_id);
70 };
71
72 ShenandoahSTWMarkTask::ShenandoahSTWMarkTask(ShenandoahSTWMark* mark) :
73 WorkerTask("Shenandoah STW mark"),
74 _mark(mark) {
75 }
76
77 void ShenandoahSTWMarkTask::work(uint worker_id) {
78 ShenandoahParallelWorkerSession worker_session(worker_id);
79 _mark->mark_roots(worker_id);
80 _mark->finish_mark(worker_id);
81 }
82
83 ShenandoahSTWMark::ShenandoahSTWMark(bool full_gc) :
84 ShenandoahMark(),
85 _root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark),
86 _terminator(ShenandoahHeap::heap()->workers()->active_workers(), ShenandoahHeap::heap()->marking_context()->task_queues()),
87 _full_gc(full_gc) {
88 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a Shenandoah safepoint");
89 }
90
91 void ShenandoahSTWMark::mark() {
92 ShenandoahHeap* const heap = ShenandoahHeap::heap();
93
94 // Arm all nmethods. Even though this is STW mark, some marking code
95 // piggybacks on nmethod barriers for special instances.
96 ShenandoahCodeRoots::arm_nmethods_for_mark();
97
98 // Weak reference processing
99 ShenandoahReferenceProcessor* rp = heap->ref_processor();
100 rp->reset_thread_locals();
101 rp->set_soft_reference_policy(heap->soft_ref_policy()->should_clear_all_soft_refs());
102
103 // Init mark, do not expect forwarded pointers in roots
104 if (ShenandoahVerify) {
105 assert(Thread::current()->is_VM_thread(), "Must be");
106 heap->verifier()->verify_roots_no_forwarded();
107 }
108
109 start_mark();
110
111 uint nworkers = heap->workers()->active_workers();
112 task_queues()->reserve(nworkers);
113
114 TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
115
116 {
117 // Mark
118 StrongRootsScope scope(nworkers);
119 ShenandoahSTWMarkTask task(this);
120 heap->workers()->run_task(&task);
121
122 assert(task_queues()->is_empty(), "Should be empty");
123 }
124
125 heap->mark_complete_marking_context();
126 end_mark();
127
128 // Mark is finished, can disarm the nmethods now.
129 ShenandoahCodeRoots::disarm_nmethods();
130
131 assert(task_queues()->is_empty(), "Should be empty");
132 TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats());
133 TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
134 }
135
136 void ShenandoahSTWMark::mark_roots(uint worker_id) {
137 ShenandoahInitMarkRootsClosure init_mark(task_queues()->queue(worker_id));
138 _root_scanner.roots_do(&init_mark, worker_id);
139 }
140
141 void ShenandoahSTWMark::finish_mark(uint worker_id) {
142 ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark;
143 ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id);
144 ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor();
145 StringDedup::Requests requests;
146
147 mark_loop(worker_id, &_terminator, rp,
148 false /* not cancellable */,
149 ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests);
150 }
151