< 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 
 45 class ShenandoahUpdateRootsTask : public AbstractGangTask {
 46 private:
 47   ShenandoahRootUpdater*  _root_updater;
 48   bool                    _check_alive;
 49 public:
 50   ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater, bool check_alive) :
 51     AbstractGangTask("Shenandoah Update Roots"),
 52     _root_updater(root_updater),
 53     _check_alive(check_alive){
 54   }
 55 
 56   void work(uint worker_id) {
 57     assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
 58     ShenandoahParallelWorkerSession worker_session(worker_id);
 59 
 60     ShenandoahHeap* heap = ShenandoahHeap::heap();
 61     ShenandoahUpdateRefsClosure cl;
 62     if (_check_alive) {
 63       ShenandoahForwardedIsAliveClosure is_alive;
 64       _root_updater->roots_do<ShenandoahForwardedIsAliveClosure, ShenandoahUpdateRefsClosure>(worker_id, &is_alive, &cl);
 65     } else {
 66       AlwaysTrueClosure always_true;;
 67       _root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl);
 68     }
 69   }
 70 };
 71 

 72 class ShenandoahConcurrentMarkingTask : public AbstractGangTask {
 73 private:
 74   ShenandoahConcurrentMark* const _cm;
 75   TaskTerminator* const           _terminator;
 76 
 77 public:
 78   ShenandoahConcurrentMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) :
 79     AbstractGangTask("Shenandoah Concurrent Mark"), _cm(cm), _terminator(terminator) {
 80   }
 81 
 82   void work(uint worker_id) {
 83     ShenandoahHeap* heap = ShenandoahHeap::heap();
 84     ShenandoahConcurrentWorkerSession worker_session(worker_id);
 85     ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers);
 86     ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);
 87     ShenandoahReferenceProcessor* rp = heap->ref_processor();
 88     assert(rp != NULL, "need reference processor");
 89     StringDedup::Requests requests;
 90     _cm->mark_loop(worker_id, _terminator, rp,
 91                    true /*cancellable*/,
 92                    ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP,
 93                    &requests);
 94   }
 95 };
 96 
 97 class ShenandoahSATBAndRemarkThreadsClosure : public ThreadClosure {
 98 private:
 99   SATBMarkQueueSet& _satb_qset;
100   OopClosure* const _cl;
101   uintx _claim_token;
102 
103 public:
104   ShenandoahSATBAndRemarkThreadsClosure(SATBMarkQueueSet& satb_qset, OopClosure* cl) :
105     _satb_qset(satb_qset),
106     _cl(cl),
107     _claim_token(Threads::thread_claim_token()) {}
108 
109   void do_thread(Thread* thread) {
110     if (thread->claim_threads_do(true, _claim_token)) {
111       // Transfer any partial buffer to the qset for completed buffer processing.
112       _satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
113       if (thread->is_Java_thread()) {
114         if (_cl != NULL) {
115           ResourceMark rm;
116           thread->oops_do(_cl, NULL);
117         }
118       }
119     }
120   }
121 };
122 

123 class ShenandoahFinalMarkingTask : public AbstractGangTask {
124 private:
125   ShenandoahConcurrentMark* _cm;
126   TaskTerminator*           _terminator;
127   bool                      _dedup_string;
128 
129 public:
130   ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
131     AbstractGangTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) {
132   }
133 
134   void work(uint worker_id) {
135     ShenandoahHeap* heap = ShenandoahHeap::heap();
136 
137     ShenandoahParallelWorkerSession worker_session(worker_id);
138     ShenandoahReferenceProcessor* rp = heap->ref_processor();
139     StringDedup::Requests requests;

140 
141     // First drain remaining SATB buffers.
142     {
143       ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);

144 
145       ShenandoahSATBBufferClosure cl(q);
146       SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();
147       while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {}
148       assert(!heap->has_forwarded_objects(), "Not expected");
149 
150       ShenandoahMarkRefsClosure             mark_cl(q, rp);
151       ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set,
152                                                ShenandoahIUBarrier ? &mark_cl : NULL);
153       Threads::threads_do(&tc);
154     }
155     _cm->mark_loop(worker_id, _terminator, rp,
156                    false /*not cancellable*/,
157                    _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
158                    &requests);
159     assert(_cm->task_queues()->is_empty(), "Should be empty");
160   }
161 };
162 
163 ShenandoahConcurrentMark::ShenandoahConcurrentMark() :
164   ShenandoahMark() {}
165 
166 // Mark concurrent roots during concurrent phases

167 class ShenandoahMarkConcurrentRootsTask : public AbstractGangTask {
168 private:
169   SuspendibleThreadSetJoiner          _sts_joiner;
170   ShenandoahConcurrentRootScanner     _root_scanner;
171   ShenandoahObjToScanQueueSet* const  _queue_set;

172   ShenandoahReferenceProcessor* const _rp;
173 
174 public:
175   ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,

176                                     ShenandoahReferenceProcessor* rp,
177                                     ShenandoahPhaseTimings::Phase phase,
178                                     uint nworkers);
179   void work(uint worker_id);
180 };
181 
182 ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
183                                                                      ShenandoahReferenceProcessor* rp,
184                                                                      ShenandoahPhaseTimings::Phase phase,
185                                                                      uint nworkers) :


186   AbstractGangTask("Shenandoah Concurrent Mark Roots"),
187   _root_scanner(nworkers, phase),
188   _queue_set(qs),

189   _rp(rp) {
190   assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected");
191 }
192 
193 void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) {

194   ShenandoahConcurrentWorkerSession worker_session(worker_id);
195   ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
196   ShenandoahMarkRefsClosure cl(q, _rp);

197   _root_scanner.roots_do(&cl, worker_id);
198 }
199 
200 void ShenandoahConcurrentMark::mark_concurrent_roots() {
201   ShenandoahHeap* const heap = ShenandoahHeap::heap();
202   assert(!heap->has_forwarded_objects(), "Not expected");
203 
204   TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
205 
206   WorkGang* workers = heap->workers();
207   ShenandoahReferenceProcessor* rp = heap->ref_processor();
208   task_queues()->reserve(workers->active_workers());
209   ShenandoahMarkConcurrentRootsTask task(task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());
210 
211   workers->run_task(&task);














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   WorkGang* 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     TaskTerminator terminator(nworkers, task_queues());
237     ShenandoahConcurrentMarkingTask task(this, &terminator);
238     workers->run_task(&task);



















239 
240     if (heap->cancelled_gc()) {
241       // GC is cancelled, break out.
242       break;
243     }
244 
245     size_t before = qset.completed_buffers_num();
246     Handshake::execute(&flush_satb);
247     size_t after = qset.completed_buffers_num();
248 
249     if (before == after) {
250       // No more retries needed, break out.
251       break;
252     }
253   }
254   assert(task_queues()->is_empty() || heap->cancelled_gc(), "Should be empty when not cancelled");
255 }
256 
257 void ShenandoahConcurrentMark::finish_mark() {
258   assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
259   assert(Thread::current()->is_VM_thread(), "Must by VM Thread");
260   finish_mark_work();
261   assert(task_queues()->is_empty(), "Should be empty");
262   TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats());
263   TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
264 
265   ShenandoahHeap* const heap = ShenandoahHeap::heap();
266   heap->set_concurrent_mark_in_progress(false);
267   heap->mark_complete_marking_context();
268 }
269 
270 void ShenandoahConcurrentMark::finish_mark_work() {
271   // Finally mark everything else we've got in our queues during the previous steps.
272   // It does two different things for concurrent vs. mark-compact GC:
273   // - For concurrent GC, it starts with empty task queues, drains the remaining
274   //   SATB buffers, and then completes the marking closure.
275   // - For mark-compact GC, it starts out with the task queues seeded by initial
276   //   root scan, and completes the closure, thus marking through all live objects
277   // The implementation is the same, so it's shared here.
278   ShenandoahHeap* const heap = ShenandoahHeap::heap();
279   ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark);
280   uint nworkers = heap->workers()->active_workers();
281   task_queues()->reserve(nworkers);
282 
283   StrongRootsScope scope(nworkers);
284   TaskTerminator terminator(nworkers, task_queues());
285   ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
286   heap->workers()->run_task(&task);
287 
288   assert(task_queues()->is_empty(), "Should be empty");
289 }

















290 
291 
292 void ShenandoahConcurrentMark::cancel() {
293   clear();
294   ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor();
295   rp->abandon_partial_discovery();
296 }

 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 class ShenandoahUpdateRootsTask : public AbstractGangTask {
 48 private:
 49   ShenandoahRootUpdater*  _root_updater;
 50   bool                    _check_alive;
 51 public:
 52   ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater, bool check_alive) :
 53     AbstractGangTask("Shenandoah Update Roots"),
 54     _root_updater(root_updater),
 55     _check_alive(check_alive){
 56   }
 57 
 58   void work(uint worker_id) {
 59     assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
 60     ShenandoahParallelWorkerSession worker_session(worker_id);
 61 
 62     ShenandoahHeap* heap = ShenandoahHeap::heap();
 63     ShenandoahUpdateRefsClosure cl;
 64     if (_check_alive) {
 65       ShenandoahForwardedIsAliveClosure is_alive;
 66       _root_updater->roots_do<ShenandoahForwardedIsAliveClosure, ShenandoahUpdateRefsClosure>(worker_id, &is_alive, &cl);
 67     } else {
 68       AlwaysTrueClosure always_true;;
 69       _root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl);
 70     }
 71   }
 72 };
 73 
 74 template <GenerationMode GENERATION>
 75 class ShenandoahConcurrentMarkingTask : public AbstractGangTask {
 76 private:
 77   ShenandoahConcurrentMark* const _cm;
 78   TaskTerminator* const           _terminator;
 79 
 80 public:
 81   ShenandoahConcurrentMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) :
 82     AbstractGangTask("Shenandoah Concurrent Mark"), _cm(cm), _terminator(terminator) {
 83   }
 84 
 85   void work(uint worker_id) {
 86     ShenandoahHeap* heap = ShenandoahHeap::heap();
 87     ShenandoahConcurrentWorkerSession worker_session(worker_id);
 88     ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers);
 89     ShenandoahReferenceProcessor* rp = heap->active_generation()->ref_processor();

 90     assert(rp != NULL, "need reference processor");
 91     StringDedup::Requests requests;
 92     _cm->mark_loop(GENERATION, worker_id, _terminator, rp,
 93                    true /*cancellable*/,
 94                    ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP,
 95                    &requests);
 96   }
 97 };
 98 
 99 class ShenandoahSATBAndRemarkThreadsClosure : public ThreadClosure {
100 private:
101   SATBMarkQueueSet& _satb_qset;
102   OopClosure* const _cl;
103   uintx _claim_token;
104 
105 public:
106   ShenandoahSATBAndRemarkThreadsClosure(SATBMarkQueueSet& satb_qset, OopClosure* cl) :
107     _satb_qset(satb_qset),
108     _cl(cl),
109     _claim_token(Threads::thread_claim_token()) {}
110 
111   void do_thread(Thread* thread) {
112     if (thread->claim_threads_do(true, _claim_token)) {
113       // Transfer any partial buffer to the qset for completed buffer processing.
114       _satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
115       if (thread->is_Java_thread()) {
116         if (_cl != NULL) {
117           ResourceMark rm;
118           thread->oops_do(_cl, NULL);
119         }
120       }
121     }
122   }
123 };
124 
125 template<GenerationMode GENERATION>
126 class ShenandoahFinalMarkingTask : public AbstractGangTask {
127 private:
128   ShenandoahConcurrentMark* _cm;
129   TaskTerminator*           _terminator;
130   bool                      _dedup_string;
131 
132 public:
133   ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
134     AbstractGangTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) {
135   }
136 
137   void work(uint worker_id) {
138     ShenandoahHeap* heap = ShenandoahHeap::heap();
139 
140     ShenandoahParallelWorkerSession worker_session(worker_id);

141     StringDedup::Requests requests;
142     ShenandoahReferenceProcessor* rp = heap->active_generation()->ref_processor();
143 
144     // First drain remaining SATB buffers.
145     {
146       ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);
147       ShenandoahObjToScanQueue* old = _cm->get_old_queue(worker_id);
148 
149       ShenandoahSATBBufferClosure<GENERATION> cl(q, old);
150       SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();
151       while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {}
152       assert(!heap->has_forwarded_objects(), "Not expected");
153 
154       ShenandoahMarkRefsClosure<GENERATION> mark_cl(q, rp, old);
155       ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set,
156                                                ShenandoahIUBarrier ? &mark_cl : NULL);
157       Threads::threads_do(&tc);
158     }
159     _cm->mark_loop(GENERATION, worker_id, _terminator, rp,
160                    false /*not cancellable*/,
161                    _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
162                    &requests);
163     assert(_cm->task_queues()->is_empty(), "Should be empty");
164   }
165 };
166 
167 ShenandoahConcurrentMark::ShenandoahConcurrentMark(ShenandoahGeneration* generation) :
168   ShenandoahMark(generation) {}
169 
170 // Mark concurrent roots during concurrent phases
171 template<GenerationMode GENERATION>
172 class ShenandoahMarkConcurrentRootsTask : public AbstractGangTask {
173 private:
174   SuspendibleThreadSetJoiner          _sts_joiner;
175   ShenandoahConcurrentRootScanner     _root_scanner;
176   ShenandoahObjToScanQueueSet* const  _queue_set;
177   ShenandoahObjToScanQueueSet* const  _old_queue_set;
178   ShenandoahReferenceProcessor* const _rp;
179 
180 public:
181   ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
182                                     ShenandoahObjToScanQueueSet* old,
183                                     ShenandoahReferenceProcessor* rp,
184                                     ShenandoahPhaseTimings::Phase phase,
185                                     uint nworkers);
186   void work(uint worker_id);
187 };
188 
189 template<GenerationMode GENERATION>
190 ShenandoahMarkConcurrentRootsTask<GENERATION>::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
191                                                                                  ShenandoahObjToScanQueueSet* old,
192                                                                                  ShenandoahReferenceProcessor* rp,
193                                                                                  ShenandoahPhaseTimings::Phase phase,
194                                                                                  uint nworkers) :
195   AbstractGangTask("Shenandoah Concurrent Mark Roots"),
196   _root_scanner(nworkers, phase),
197   _queue_set(qs),
198   _old_queue_set(old),
199   _rp(rp) {
200   assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected");
201 }
202 
203 template<GenerationMode GENERATION>
204 void ShenandoahMarkConcurrentRootsTask<GENERATION>::work(uint worker_id) {
205   ShenandoahConcurrentWorkerSession worker_session(worker_id);
206   ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
207   ShenandoahObjToScanQueue* old = _old_queue_set == NULL ? NULL : _old_queue_set->queue(worker_id);
208   ShenandoahMarkRefsClosure<GENERATION> cl(q, _rp, old);
209   _root_scanner.roots_do(&cl, worker_id);
210 }
211 
212 void ShenandoahConcurrentMark::mark_concurrent_roots() {
213   ShenandoahHeap* const heap = ShenandoahHeap::heap();
214   assert(!heap->has_forwarded_objects(), "Not expected");
215 


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

310 }
311 
312 void ShenandoahConcurrentMark::finish_mark_work() {
313   // Finally mark everything else we've got in our queues during the previous steps.
314   // It does two different things for concurrent vs. mark-compact GC:
315   // - For concurrent GC, it starts with empty task queues, drains the remaining
316   //   SATB buffers, and then completes the marking closure.
317   // - For mark-compact GC, it starts out with the task queues seeded by initial
318   //   root scan, and completes the closure, thus marking through all live objects
319   // The implementation is the same, so it's shared here.
320   ShenandoahHeap* const heap = ShenandoahHeap::heap();
321   ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark);
322   uint nworkers = heap->workers()->active_workers();
323   task_queues()->reserve(nworkers);
324 
325   StrongRootsScope scope(nworkers);
326   TaskTerminator terminator(nworkers, task_queues());


327 
328   switch (_generation->generation_mode()) {
329     case YOUNG:{
330       ShenandoahFinalMarkingTask<YOUNG> task(this, &terminator, ShenandoahStringDedup::is_enabled());
331       heap->workers()->run_task(&task);
332       break;
333     }
334     case OLD:{
335       ShenandoahFinalMarkingTask<OLD> task(this, &terminator, ShenandoahStringDedup::is_enabled());
336       heap->workers()->run_task(&task);
337       break;
338     }
339     case GLOBAL:{
340       ShenandoahFinalMarkingTask<GLOBAL> task(this, &terminator, ShenandoahStringDedup::is_enabled());
341       heap->workers()->run_task(&task);
342       break;
343     }
344     default:
345       ShouldNotReachHere();
346   }
347 
348 
349   assert(task_queues()->is_empty(), "Should be empty");



350 }
< prev index next >