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