8225357: Rewire ShenandoahHeap::maybe_update_with_forwarded for contending fixups
Reviewed-by: rkennke
This commit is contained in:
parent
d690fc86dd
commit
46ba311bda
@ -253,9 +253,12 @@ inline void ShenandoahConcurrentMark::mark_through_ref(T *p, ShenandoahHeap* hea
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// Note: Only when concurrently updating references can obj become NULL here.
|
||||
// It happens when a mutator thread beats us by writing another value. In that
|
||||
// case we don't need to do anything else.
|
||||
// Note: Only when concurrently updating references can obj be different
|
||||
// (that is, really different, not just different from-/to-space copies of the same)
|
||||
// from the one we originally loaded. Mutator thread can beat us by writing something
|
||||
// else into the location. In that case, we would mark through that updated value,
|
||||
// on the off-chance it is not handled by other means (e.g. via SATB). However,
|
||||
// if that write was NULL, we don't need to do anything else.
|
||||
if (UPDATE_REFS != CONCURRENT || !CompressedOops::is_null(obj)) {
|
||||
shenandoah_assert_not_forwarded(p, obj);
|
||||
shenandoah_assert_not_in_cset_except(p, obj, heap->cancelled_gc());
|
||||
|
@ -152,24 +152,29 @@ inline oop ShenandoahHeap::maybe_update_with_forwarded_not_null(T* p, oop heap_o
|
||||
}
|
||||
|
||||
shenandoah_assert_forwarded_except(p, heap_oop, is_full_gc_in_progress() || is_degenerated_gc_in_progress());
|
||||
shenandoah_assert_not_forwarded(p, forwarded_oop);
|
||||
shenandoah_assert_not_in_cset_except(p, forwarded_oop, cancelled_gc());
|
||||
|
||||
// If this fails, another thread wrote to p before us, it will be logged in SATB and the
|
||||
// reference be updated later.
|
||||
oop result = atomic_compare_exchange_oop(forwarded_oop, p, heap_oop);
|
||||
oop witness = atomic_compare_exchange_oop(forwarded_oop, p, heap_oop);
|
||||
|
||||
if (oopDesc::equals_raw(result, heap_oop)) { // CAS successful.
|
||||
return forwarded_oop;
|
||||
if (!oopDesc::equals_raw(witness, heap_oop)) {
|
||||
// CAS failed, someone had beat us to it. Normally, we would return the failure witness,
|
||||
// because that would be the proper write of to-space object, enforced by strong barriers.
|
||||
// However, there is a corner case with arraycopy. It can happen that a Java thread
|
||||
// beats us with an arraycopy, which first copies the array, which potentially contains
|
||||
// from-space refs, and only afterwards updates all from-space refs to to-space refs,
|
||||
// which leaves a short window where the new array elements can be from-space.
|
||||
// In this case, we can just resolve the result again. As we resolve, we need to consider
|
||||
// the contended write might have been NULL.
|
||||
oop result = ShenandoahBarrierSet::resolve_forwarded(witness);
|
||||
shenandoah_assert_not_forwarded_except(p, result, (result == NULL));
|
||||
shenandoah_assert_not_in_cset_except(p, result, (result == NULL) || cancelled_gc());
|
||||
return result;
|
||||
} else {
|
||||
// Note: we used to assert the following here. This doesn't work because sometimes, during
|
||||
// marking/updating-refs, it can happen that a Java thread beats us with an arraycopy,
|
||||
// which first copies the array, which potentially contains from-space refs, and only afterwards
|
||||
// updates all from-space refs to to-space refs, which leaves a short window where the new array
|
||||
// elements can be from-space.
|
||||
// assert(CompressedOops::is_null(result) ||
|
||||
// oopDesc::equals_raw(result, ShenandoahBarrierSet::resolve_oop_static_not_null(result)),
|
||||
// "expect not forwarded");
|
||||
return NULL;
|
||||
// Success! We have updated with known to-space copy. We have already asserted it is sane.
|
||||
return forwarded_oop;
|
||||
}
|
||||
} else {
|
||||
shenandoah_assert_not_forwarded(p, heap_oop);
|
||||
|
Loading…
Reference in New Issue
Block a user