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