--- old/src/hotspot/share/gc/g1/g1OopClosures.hpp 2018-10-30 11:38:00.512935675 +0100 +++ new/src/hotspot/share/gc/g1/g1OopClosures.hpp 2018-10-30 11:38:00.077922301 +0100 @@ -36,6 +36,7 @@ class DirtyCardToOopClosure; class G1CMBitMap; class G1ParScanThreadState; +class G1ScanEvacuatedObjClosure; class G1CMTask; class ReferenceProcessor; @@ -82,15 +83,22 @@ virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; + // This closure is applied to the fields of the objects that have just been copied during evacuation. class G1ScanEvacuatedObjClosure : public G1ScanClosureBase { - bool _scanning_in_young; + friend class G1ScanInYoungSetter; + + enum ScanningInYoungValues { + False = 0, + True, + Uninitialized + }; + + ScanningInYoungValues _scanning_in_young; public: G1ScanEvacuatedObjClosure(G1CollectedHeap* g1h, G1ParScanThreadState* par_scan_state) : - G1ScanClosureBase(g1h, par_scan_state), _scanning_in_young(false) { } - - void set_scanning_in_young(bool scanning_in_young) { _scanning_in_young = scanning_in_young; } + G1ScanClosureBase(g1h, par_scan_state), _scanning_in_young(Uninitialized) { } template void do_oop_work(T* p); virtual void do_oop(oop* p) { do_oop_work(p); } @@ -104,6 +112,21 @@ } }; +// RAII object to properly set the _scanning_in_young field in G1ScanEvacuatedObjClosure. +class G1ScanInYoungSetter : public StackObj { + G1ScanEvacuatedObjClosure* _closure; + +public: + G1ScanInYoungSetter(G1ScanEvacuatedObjClosure* closure, bool new_value) : _closure(closure) { + assert(_closure->_scanning_in_young == G1ScanEvacuatedObjClosure::Uninitialized, "Must not be set"); + _closure->_scanning_in_young = new_value ? G1ScanEvacuatedObjClosure::True : G1ScanEvacuatedObjClosure::False; + } + + ~G1ScanInYoungSetter() { + DEBUG_ONLY(_closure->_scanning_in_young = G1ScanEvacuatedObjClosure::Uninitialized;) + } +}; + // Add back base class for metadata class G1ParCopyHelper : public OopClosure { protected: --- old/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp 2018-10-30 11:38:02.137985633 +0100 +++ new/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp 2018-10-30 11:38:01.705972352 +0100 @@ -84,7 +84,8 @@ prefetch_and_push(p, obj); } else if (!HeapRegion::is_in_same_region(p, obj)) { handle_non_cset_obj_common(state, p, obj); - if (_scanning_in_young) { + assert(_scanning_in_young != Uninitialized, "Scan location has not been initialized."); + if (_scanning_in_young == True) { return; } _par_scan_state->enqueue_card_if_tracked(p, obj); --- old/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp 2018-10-30 11:38:03.798036667 +0100 +++ new/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp 2018-10-30 11:38:03.363023293 +0100 @@ -311,7 +311,7 @@ oop* old_p = set_partial_array_mask(old); do_oop_partial_array(old_p); } else { - _scanner.set_scanning_in_young(dest_state.is_young()); + G1ScanInYoungSetter x(&_scanner, dest_state.is_young()); obj->oop_iterate_backwards(&_scanner); } return obj; @@ -366,7 +366,7 @@ _g1h->preserve_mark_during_evac_failure(_worker_id, old, m); - _scanner.set_scanning_in_young(r->is_young()); + G1ScanInYoungSetter x(&_scanner, r->is_young()); old->oop_iterate_backwards(&_scanner); return old; --- old/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp 2018-10-30 11:38:05.439087116 +0100 +++ new/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp 2018-10-30 11:38:05.007073835 +0100 @@ -114,7 +114,7 @@ } HeapRegion* hr = _g1h->heap_region_containing(to_obj); - _scanner.set_scanning_in_young(hr->is_young()); + G1ScanInYoungSetter x(&_scanner, hr->is_young()); // Process indexes [start,end). It will also process the header // along with the first chunk (i.e., the chunk with start == 0). // Note that at this point the length field of to_obj_array is not