< prev index next >

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

Print this page

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