< 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 != NULL, "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     _claim_token(Threads::thread_claim_token()) {}
 83 
 84   void do_thread(Thread* thread) {
 85     if (thread->claim_threads_do(true, _claim_token)) {
 86       // Transfer any partial buffer to the qset for completed buffer processing.
 87       _satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
 88       if (thread->is_Java_thread()) {
 89         if (_cl != NULL) {
 90           ResourceMark rm;
 91           thread->oops_do(_cl, NULL);
 92         }
 93       }
 94     }
 95   }
 96 };
 97 

 98 class ShenandoahFinalMarkingTask : public WorkerTask {
 99 private:
100   ShenandoahConcurrentMark* _cm;
101   TaskTerminator*           _terminator;
102   bool                      _dedup_string;
103 
104 public:
105   ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
106     WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) {
107   }
108 
109   void work(uint worker_id) {
110     ShenandoahHeap* heap = ShenandoahHeap::heap();
111 
112     ShenandoahParallelWorkerSession worker_session(worker_id);
113     ShenandoahReferenceProcessor* rp = heap->ref_processor();
114     StringDedup::Requests requests;

115 
116     // First drain remaining SATB buffers.
117     {
118       ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);

119 
120       ShenandoahSATBBufferClosure cl(q);
121       SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();
122       while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {}
123       assert(!heap->has_forwarded_objects(), "Not expected");
124 
125       ShenandoahMarkRefsClosure             mark_cl(q, rp);
126       ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set,
127                                                ShenandoahIUBarrier ? &mark_cl : NULL);
128       Threads::threads_do(&tc);
129     }
130     _cm->mark_loop(worker_id, _terminator, rp,
131                    false /*not cancellable*/,
132                    _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
133                    &requests);
134     assert(_cm->task_queues()->is_empty(), "Should be empty");
135   }
136 };
137 
138 ShenandoahConcurrentMark::ShenandoahConcurrentMark() :
139   ShenandoahMark() {}
140 
141 // Mark concurrent roots during concurrent phases

142 class ShenandoahMarkConcurrentRootsTask : public WorkerTask {
143 private:
144   SuspendibleThreadSetJoiner          _sts_joiner;
145   ShenandoahConcurrentRootScanner     _root_scanner;
146   ShenandoahObjToScanQueueSet* const  _queue_set;

147   ShenandoahReferenceProcessor* const _rp;
148 
149 public:
150   ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,

151                                     ShenandoahReferenceProcessor* rp,
152                                     ShenandoahPhaseTimings::Phase phase,
153                                     uint nworkers);
154   void work(uint worker_id);
155 };
156 
157 ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
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   _rp(rp) {
165   assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected");
166 }
167 
168 void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) {

169   ShenandoahConcurrentWorkerSession worker_session(worker_id);
170   ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
171   ShenandoahMarkRefsClosure cl(q, _rp);

172   _root_scanner.roots_do(&cl, worker_id);
173 }
174 
175 void ShenandoahConcurrentMark::mark_concurrent_roots() {
176   ShenandoahHeap* const heap = ShenandoahHeap::heap();
177   assert(!heap->has_forwarded_objects(), "Not expected");
178 
179   TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
180 
181   WorkerThreads* workers = heap->workers();
182   ShenandoahReferenceProcessor* rp = heap->ref_processor();
183   task_queues()->reserve(workers->active_workers());
184   ShenandoahMarkConcurrentRootsTask task(task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());
185 
186   workers->run_task(&task);














187 }
188 
189 class ShenandoahFlushSATBHandshakeClosure : public HandshakeClosure {
190 private:
191   SATBMarkQueueSet& _qset;
192 public:
193   ShenandoahFlushSATBHandshakeClosure(SATBMarkQueueSet& qset) :
194     HandshakeClosure("Shenandoah Flush SATB Handshake"),
195     _qset(qset) {}
196 
197   void do_thread(Thread* thread) {
198     _qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
199   }
200 };
201 
202 void ShenandoahConcurrentMark::concurrent_mark() {
203   ShenandoahHeap* const heap = ShenandoahHeap::heap();
204   WorkerThreads* workers = heap->workers();
205   uint nworkers = workers->active_workers();
206   task_queues()->reserve(nworkers);
207 
208   ShenandoahSATBMarkQueueSet& qset = ShenandoahBarrierSet::satb_mark_queue_set();
209   ShenandoahFlushSATBHandshakeClosure flush_satb(qset);
210   for (uint flushes = 0; flushes < ShenandoahMaxSATBBufferFlushes; flushes++) {
211     TaskTerminator terminator(nworkers, task_queues());
212     ShenandoahConcurrentMarkingTask task(this, &terminator);
213     workers->run_task(&task);



















214 
215     if (heap->cancelled_gc()) {
216       // GC is cancelled, break out.
217       break;
218     }
219 
220     size_t before = qset.completed_buffers_num();
221     Handshake::execute(&flush_satb);
222     size_t after = qset.completed_buffers_num();
223 
224     if (before == after) {
225       // No more retries needed, break out.
226       break;
227     }
228   }
229   assert(task_queues()->is_empty() || heap->cancelled_gc(), "Should be empty when not cancelled");
230 }
231 
232 void ShenandoahConcurrentMark::finish_mark() {
233   assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
234   assert(Thread::current()->is_VM_thread(), "Must by VM Thread");
235   finish_mark_work();
236   assert(task_queues()->is_empty(), "Should be empty");
237   TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats());
238   TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
239 
240   ShenandoahHeap* const heap = ShenandoahHeap::heap();
241   heap->set_concurrent_mark_in_progress(false);
242   heap->mark_complete_marking_context();
243 
244   end_mark();
245 }
246 
247 void ShenandoahConcurrentMark::finish_mark_work() {
248   // Finally mark everything else we've got in our queues during the previous steps.
249   // It does two different things for concurrent vs. mark-compact GC:
250   // - For concurrent GC, it starts with empty task queues, drains the remaining
251   //   SATB buffers, and then completes the marking closure.
252   // - For mark-compact GC, it starts out with the task queues seeded by initial
253   //   root scan, and completes the closure, thus marking through all live objects
254   // The implementation is the same, so it's shared here.
255   ShenandoahHeap* const heap = ShenandoahHeap::heap();
256   ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark);
257   uint nworkers = heap->workers()->active_workers();
258   task_queues()->reserve(nworkers);
259 
260   StrongRootsScope scope(nworkers);
261   TaskTerminator terminator(nworkers, task_queues());
262   ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
263   heap->workers()->run_task(&task);
264 
265   assert(task_queues()->is_empty(), "Should be empty");
266 }

















267 
268 
269 void ShenandoahConcurrentMark::cancel() {
270   clear();
271   ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor();
272   rp->abandon_partial_discovery();
273 }

 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 != NULL, "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     _claim_token(Threads::thread_claim_token()) {}
 86 
 87   void do_thread(Thread* thread) {
 88     if (thread->claim_threads_do(true, _claim_token)) {
 89       // Transfer any partial buffer to the qset for completed buffer processing.
 90       _satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
 91       if (thread->is_Java_thread()) {
 92         if (_cl != NULL) {
 93           ResourceMark rm;
 94           thread->oops_do(_cl, NULL);
 95         }
 96       }
 97     }
 98   }
 99 };
100 
101 template<GenerationMode GENERATION>
102 class ShenandoahFinalMarkingTask : public WorkerTask {
103 private:
104   ShenandoahConcurrentMark* _cm;
105   TaskTerminator*           _terminator;
106   bool                      _dedup_string;
107 
108 public:
109   ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
110     WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) {
111   }
112 
113   void work(uint worker_id) {
114     ShenandoahHeap* heap = ShenandoahHeap::heap();
115 
116     ShenandoahParallelWorkerSession worker_session(worker_id);

117     StringDedup::Requests requests;
118     ShenandoahReferenceProcessor* rp = heap->active_generation()->ref_processor();
119 
120     // First drain remaining SATB buffers.
121     {
122       ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);
123       ShenandoahObjToScanQueue* old = _cm->get_old_queue(worker_id);
124 
125       ShenandoahSATBBufferClosure<GENERATION> cl(q, old);
126       SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();
127       while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {}
128       assert(!heap->has_forwarded_objects(), "Not expected");
129 
130       ShenandoahMarkRefsClosure<GENERATION> mark_cl(q, rp, old);
131       ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set,
132                                                ShenandoahIUBarrier ? &mark_cl : NULL);
133       Threads::threads_do(&tc);
134     }
135     _cm->mark_loop(GENERATION, worker_id, _terminator, rp,
136                    false /*not cancellable*/,
137                    _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
138                    &requests);
139     assert(_cm->task_queues()->is_empty(), "Should be empty");
140   }
141 };
142 
143 ShenandoahConcurrentMark::ShenandoahConcurrentMark(ShenandoahGeneration* generation) :
144   ShenandoahMark(generation) {}
145 
146 // Mark concurrent roots during concurrent phases
147 template<GenerationMode GENERATION>
148 class ShenandoahMarkConcurrentRootsTask : public WorkerTask {
149 private:
150   SuspendibleThreadSetJoiner          _sts_joiner;
151   ShenandoahConcurrentRootScanner     _root_scanner;
152   ShenandoahObjToScanQueueSet* const  _queue_set;
153   ShenandoahObjToScanQueueSet* const  _old_queue_set;
154   ShenandoahReferenceProcessor* const _rp;
155 
156 public:
157   ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
158                                     ShenandoahObjToScanQueueSet* old,
159                                     ShenandoahReferenceProcessor* rp,
160                                     ShenandoahPhaseTimings::Phase phase,
161                                     uint nworkers);
162   void work(uint worker_id);
163 };
164 
165 template<GenerationMode GENERATION>
166 ShenandoahMarkConcurrentRootsTask<GENERATION>::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
167                                                                                  ShenandoahObjToScanQueueSet* old,
168                                                                                  ShenandoahReferenceProcessor* rp,
169                                                                                  ShenandoahPhaseTimings::Phase phase,
170                                                                                  uint nworkers) :
171   WorkerTask("Shenandoah Concurrent Mark Roots"),
172   _root_scanner(nworkers, phase),
173   _queue_set(qs),
174   _old_queue_set(old),
175   _rp(rp) {
176   assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected");
177 }
178 
179 template<GenerationMode GENERATION>
180 void ShenandoahMarkConcurrentRootsTask<GENERATION>::work(uint worker_id) {
181   ShenandoahConcurrentWorkerSession worker_session(worker_id);
182   ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
183   ShenandoahObjToScanQueue* old = _old_queue_set == NULL ? NULL : _old_queue_set->queue(worker_id);
184   ShenandoahMarkRefsClosure<GENERATION> cl(q, _rp, old);
185   _root_scanner.roots_do(&cl, worker_id);
186 }
187 
188 void ShenandoahConcurrentMark::mark_concurrent_roots() {
189   ShenandoahHeap* const heap = ShenandoahHeap::heap();
190   assert(!heap->has_forwarded_objects(), "Not expected");
191 


192   WorkerThreads* workers = heap->workers();
193   ShenandoahReferenceProcessor* rp = _generation->ref_processor();
194   _generation->reserve_task_queues(workers->active_workers());
195   switch (_generation->generation_mode()) {
196     case YOUNG: {
197       ShenandoahMarkConcurrentRootsTask<YOUNG> task(task_queues(), old_task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());
198       workers->run_task(&task);
199       break;
200     }
201     case GLOBAL: {
202       assert(old_task_queues() == NULL, "Global mark should not have old gen mark queues.");
203       ShenandoahMarkConcurrentRootsTask<GLOBAL> task(task_queues(), old_task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());
204       workers->run_task(&task);
205       break;
206     }
207     default:
208       // Intentionally haven't added OLD here. We use a YOUNG generation
209       // cycle to bootstrap concurrent old marking.
210       ShouldNotReachHere();
211   }
212 }
213 
214 class ShenandoahFlushSATBHandshakeClosure : public HandshakeClosure {
215 private:
216   SATBMarkQueueSet& _qset;
217 public:
218   ShenandoahFlushSATBHandshakeClosure(SATBMarkQueueSet& qset) :
219     HandshakeClosure("Shenandoah Flush SATB Handshake"),
220     _qset(qset) {}
221 
222   void do_thread(Thread* thread) {
223     _qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
224   }
225 };
226 
227 void ShenandoahConcurrentMark::concurrent_mark() {
228   ShenandoahHeap* const heap = ShenandoahHeap::heap();
229   WorkerThreads* workers = heap->workers();
230   uint nworkers = workers->active_workers();
231   task_queues()->reserve(nworkers);
232 
233   ShenandoahSATBMarkQueueSet& qset = ShenandoahBarrierSet::satb_mark_queue_set();
234   ShenandoahFlushSATBHandshakeClosure flush_satb(qset);
235   for (uint flushes = 0; flushes < ShenandoahMaxSATBBufferFlushes; flushes++) {
236     switch (_generation->generation_mode()) {
237       case YOUNG: {
238         TaskTerminator terminator(nworkers, task_queues());
239         ShenandoahConcurrentMarkingTask<YOUNG> task(this, &terminator);
240         workers->run_task(&task);
241         break;
242       }
243       case OLD: {
244         TaskTerminator terminator(nworkers, task_queues());
245         ShenandoahConcurrentMarkingTask<OLD> task(this, &terminator);
246         workers->run_task(&task);
247         break;
248       }
249       case GLOBAL: {
250         TaskTerminator terminator(nworkers, task_queues());
251         ShenandoahConcurrentMarkingTask<GLOBAL> task(this, &terminator);
252         workers->run_task(&task);
253         break;
254       }
255       default:
256         ShouldNotReachHere();
257     }
258 
259     if (heap->cancelled_gc()) {
260       // GC is cancelled, break out.
261       break;
262     }
263 
264     size_t before = qset.completed_buffers_num();
265     Handshake::execute(&flush_satb);
266     size_t after = qset.completed_buffers_num();
267 
268     if (before == after) {
269       // No more retries needed, break out.
270       break;
271     }
272   }
273   assert(task_queues()->is_empty() || heap->cancelled_gc(), "Should be empty when not cancelled");
274 }
275 
276 void ShenandoahConcurrentMark::finish_mark() {
277   assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
278   assert(Thread::current()->is_VM_thread(), "Must by VM Thread");
279   finish_mark_work();
280   assert(task_queues()->is_empty(), "Should be empty");
281   TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats());
282   TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
283 
284   _generation->set_concurrent_mark_in_progress(false);
285   _generation->set_mark_complete();

286 
287   end_mark();
288 }
289 
290 void ShenandoahConcurrentMark::finish_mark_work() {
291   // Finally mark everything else we've got in our queues during the previous steps.
292   // It does two different things for concurrent vs. mark-compact GC:
293   // - For concurrent GC, it starts with empty task queues, drains the remaining
294   //   SATB buffers, and then completes the marking closure.
295   // - For mark-compact GC, it starts out with the task queues seeded by initial
296   //   root scan, and completes the closure, thus marking through all live objects
297   // The implementation is the same, so it's shared here.
298   ShenandoahHeap* const heap = ShenandoahHeap::heap();
299   ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark);
300   uint nworkers = heap->workers()->active_workers();
301   task_queues()->reserve(nworkers);
302 
303   StrongRootsScope scope(nworkers);
304   TaskTerminator terminator(nworkers, task_queues());


305 
306   switch (_generation->generation_mode()) {
307     case YOUNG:{
308       ShenandoahFinalMarkingTask<YOUNG> task(this, &terminator, ShenandoahStringDedup::is_enabled());
309       heap->workers()->run_task(&task);
310       break;
311     }
312     case OLD:{
313       ShenandoahFinalMarkingTask<OLD> task(this, &terminator, ShenandoahStringDedup::is_enabled());
314       heap->workers()->run_task(&task);
315       break;
316     }
317     case GLOBAL:{
318       ShenandoahFinalMarkingTask<GLOBAL> task(this, &terminator, ShenandoahStringDedup::is_enabled());
319       heap->workers()->run_task(&task);
320       break;
321     }
322     default:
323       ShouldNotReachHere();
324   }
325 
326 
327   assert(task_queues()->is_empty(), "Should be empty");



328 }
< prev index next >