--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Fri Jun 07 11:19:34 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Fri Jun 07 11:47:53 2019 +0200
@@ -152,24 +152,29 @@
}
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);