@@ -279,21 +279,6 @@ bool ShenandoahConcurrentGC::complete_abbreviated_cycle() {
279279 heap->update_region_ages (_generation->complete_marking_context ());
280280 }
281281
282- if (!heap->is_concurrent_old_mark_in_progress ()) {
283- heap->concurrent_final_roots ();
284- } else {
285- // Since the cycle was shortened for having enough immediate garbage, this will be
286- // the last phase before concurrent marking of old resumes. We must be sure
287- // that old mark threads don't see any pointers to garbage in the SATB queues. Even
288- // though nothing was evacuated, overwriting unreachable weak roots with null may still
289- // put pointers to regions that become trash in the SATB queues. The following will
290- // piggyback flushing the thread local SATB queues on the same handshake that propagates
291- // the gc state change.
292- ShenandoahSATBMarkQueueSet& satb_queues = ShenandoahBarrierSet::satb_mark_queue_set ();
293- ShenandoahFlushSATBHandshakeClosure complete_thread_local_satb_buffers (satb_queues);
294- heap->concurrent_final_roots (&complete_thread_local_satb_buffers);
295- heap->old_generation ()->concurrent_transfer_pointers_from_satb ();
296- }
297282 return true ;
298283}
299284
@@ -684,16 +669,10 @@ void ShenandoahConcurrentGC::op_init_mark() {
684669 assert (!heap->has_forwarded_objects (), " No forwarded objects on this path" );
685670
686671 if (heap->mode ()->is_generational ()) {
687-
688672 if (_generation->is_global ()) {
689673 heap->old_generation ()->cancel_gc ();
690- } else if (heap->is_concurrent_old_mark_in_progress ()) {
691- // Purge the SATB buffers, transferring any valid, old pointers to the
692- // old generation mark queue. Any pointers in a young region will be
693- // abandoned.
694- ShenandoahGCPhase phase (ShenandoahPhaseTimings::init_transfer_satb);
695- heap->old_generation ()->transfer_pointers_from_satb ();
696674 }
675+
697676 {
698677 // After we swap card table below, the write-table is all clean, and the read table holds
699678 // cards dirty prior to the start of GC. Young and bootstrap collection will update
@@ -1131,7 +1110,7 @@ class ShenandoahUpdateThreadHandshakeClosure : public HandshakeClosure {
11311110 ShenandoahNonConcUpdateRefsClosure _cl;
11321111public:
11331112 ShenandoahUpdateThreadHandshakeClosure ();
1134- void do_thread (Thread* thread);
1113+ void do_thread (Thread* thread) override ;
11351114};
11361115
11371116ShenandoahUpdateThreadHandshakeClosure::ShenandoahUpdateThreadHandshakeClosure () :
@@ -1146,9 +1125,49 @@ void ShenandoahUpdateThreadHandshakeClosure::do_thread(Thread* thread) {
11461125 }
11471126}
11481127
1128+ class ShenandoahUpdateThreadRootsAndFlushOldSatbBuffers final : public HandshakeClosure {
1129+ // When Shenandoah is marking the old generation, it is possible for the SATB barrier
1130+ // to pick up overwritten pointers that point into a cset region. If these pointers
1131+ // are accessed by mark threads, they will crash. Once update refs has completed, it is
1132+ // no longer possible for a mutator thread to overwrite a pointer into a cset region.
1133+ //
1134+ // Therefore, at the end of update refs, we use this closure to update the thread roots
1135+ // and 'complete' all the thread local SATB buffers. Completing these will filter out
1136+ // anything that has already been marked or anything that points to a region which is
1137+ // not old. We do not need to worry about ABA situations where a region may become old
1138+ // after the pointer is enqueued but before it is filtered. There are only two ways a
1139+ // region may become old:
1140+ // 1. The region is promoted in place. This is safe because such regions will never
1141+ // be in the collection set. If this happens, the pointer will be preserved, essentially
1142+ // becoming part of the old snapshot.
1143+ // 2. The region is allocated during evacuation of old. This is also not a concern because
1144+ // we haven't yet finished marking old so no mixed evacuations will happen.
1145+ ShenandoahUpdateThreadHandshakeClosure _update_roots;
1146+ ShenandoahFlushSATB _flush_all_satb;
1147+
1148+ public:
1149+ ShenandoahUpdateThreadRootsAndFlushOldSatbBuffers () :
1150+ HandshakeClosure (" Shenandoah Update Thread Roots and Flush SATB" ),
1151+ _flush_all_satb (ShenandoahBarrierSet::satb_mark_queue_set()) {
1152+ assert (ShenandoahBarrierSet::satb_mark_queue_set ().get_filter_out_young (),
1153+ " Should be filtering pointers outside of old during old marking" );
1154+ }
1155+
1156+ void do_thread (Thread* thread) override {
1157+ _update_roots.do_thread (thread);
1158+ _flush_all_satb.do_thread (thread);
1159+ }
1160+ };
1161+
11491162void ShenandoahConcurrentGC::op_update_thread_roots () {
1150- ShenandoahUpdateThreadHandshakeClosure cl;
1151- Handshake::execute (&cl);
1163+ ShenandoahHeap* const heap = ShenandoahHeap::heap ();
1164+ if (heap->is_concurrent_old_mark_in_progress ()) {
1165+ ShenandoahUpdateThreadRootsAndFlushOldSatbBuffers cl;
1166+ Handshake::execute (&cl);
1167+ } else {
1168+ ShenandoahUpdateThreadHandshakeClosure cl;
1169+ Handshake::execute (&cl);
1170+ }
11521171}
11531172
11541173void ShenandoahConcurrentGC::op_final_update_refs () {
@@ -1177,23 +1196,6 @@ void ShenandoahConcurrentGC::op_final_update_refs() {
11771196 heap->set_has_forwarded_objects (false );
11781197
11791198 if (heap->mode ()->is_generational () && heap->is_concurrent_old_mark_in_progress ()) {
1180- // When the SATB barrier is left on to support concurrent old gen mark, it may pick up writes to
1181- // objects in the collection set. After those objects are evacuated, the pointers in the
1182- // SATB are no longer safe. Once we have finished update references, we are guaranteed that
1183- // no more writes to the collection set are possible.
1184- //
1185- // This will transfer any old pointers in _active_ regions from the SATB to the old gen
1186- // mark queues. All other pointers will be discarded. This would also discard any pointers
1187- // in old regions that were included in a mixed evacuation. We aren't using the SATB filter
1188- // methods here because we cannot control when they execute. If the SATB filter runs _after_
1189- // a region has been recycled, we will not be able to detect the bad pointer.
1190- //
1191- // We are not concerned about skipping this step in abbreviated cycles because regions
1192- // with no live objects cannot have been written to and so cannot have entries in the SATB
1193- // buffers.
1194- ShenandoahGCPhase phase (ShenandoahPhaseTimings::final_update_refs_transfer_satb);
1195- heap->old_generation ()->transfer_pointers_from_satb ();
1196-
11971199 // Aging_cycle is only relevant during evacuation cycle for individual objects and during final mark for
11981200 // entire regions. Both of these relevant operations occur before final update refs.
11991201 ShenandoahGenerationalHeap::heap ()->set_aging_cycle (false );
@@ -1228,13 +1230,13 @@ bool ShenandoahConcurrentGC::entry_final_roots() {
12281230 ShenandoahWorkerPolicy::calc_workers_for_conc_evac (),
12291231 msg);
12301232
1231- if (!heap->mode ()->is_generational ()) {
1232- heap->concurrent_final_roots ();
1233- } else {
1233+ if (heap->mode ()->is_generational ()) {
12341234 if (!complete_abbreviated_cycle ()) {
12351235 return false ;
12361236 }
12371237 }
1238+
1239+ heap->concurrent_final_roots ();
12381240 return true ;
12391241}
12401242
0 commit comments