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