< prev index next >

src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp

Print this page

  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 }
< prev index next >