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