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