@@ -249,29 +249,35 @@ inline oop ShenandoahBarrierSet::oop_load(DecoratorSet decorators, T* addr) {
249249
250250template <typename T>
251251inline oop ShenandoahBarrierSet::oop_cmpxchg (DecoratorSet decorators, T* addr, oop compare_value, oop new_value) {
252- oop res;
253- oop expected = compare_value;
254- do {
255- compare_value = expected;
256- res = RawAccess<>::oop_atomic_cmpxchg (addr, compare_value, new_value);
257- expected = res;
258- } while ((compare_value != expected) && (resolve_forwarded (compare_value) == resolve_forwarded (expected)));
252+ shenandoah_assert_not_in_cset_except (nullptr , compare_value, (compare_value == nullptr || ShenandoahHeap::heap ()->cancelled_gc ()));
253+ shenandoah_assert_not_in_cset_except (nullptr , new_value, (new_value == nullptr || ShenandoahHeap::heap ()->cancelled_gc ()));
259254
260- // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway,
261- // because it must be the previous value.
262- res = load_reference_barrier (decorators, res, static_cast <T*>(nullptr ));
263- satb_enqueue (res);
264- return res;
255+ // Handle the previous value through SATB, as we are about to perform the store.
256+ oop prev = RawAccess<>::oop_load (addr);
257+ satb_enqueue (prev);
258+
259+ // Perform LRB on location to fix it up for this and all following accesses.
260+ // This guarantees there are no false negatives due to concurrent evacuation,
261+ // and the value loaded later by CAS is sanitized by some LRB, or is null.
262+ load_reference_barrier (decorators, prev, addr);
263+
264+ return RawAccess<>::oop_atomic_cmpxchg (addr, compare_value, new_value);
265265}
266266
267267template <typename T>
268268inline oop ShenandoahBarrierSet::oop_xchg (DecoratorSet decorators, T* addr, oop new_value) {
269- oop previous = RawAccess<>::oop_atomic_xchg (addr, new_value);
270- // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway,
271- // because it must be the previous value.
272- previous = load_reference_barrier<T>(decorators, previous, static_cast <T*>(nullptr ));
273- satb_enqueue (previous);
274- return previous;
269+ shenandoah_assert_not_in_cset_except (nullptr , new_value, (new_value == nullptr || ShenandoahHeap::heap ()->cancelled_gc ()));
270+
271+ // Handle the previous value through SATB, as we are about to perform the store.
272+ oop prev = RawAccess<>::oop_load (addr);
273+ satb_enqueue (prev);
274+
275+ // Perform LRB on location to fix it up for this and all following accesses.
276+ // This is purely opportunistic: we would not have any false negatives here.
277+ // This guarantees the value loaded later by XCHG is sanitized by some LRB, or is null.
278+ load_reference_barrier (decorators, prev, addr);
279+
280+ return RawAccess<>::oop_atomic_xchg (addr, new_value);
275281}
276282
277283template <DecoratorSet decorators, typename BarrierSetT>
@@ -338,15 +344,17 @@ inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_st
338344template <DecoratorSet decorators, typename BarrierSetT>
339345template <typename T>
340346inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value) {
341- assert ((decorators & (AS_NO_KEEPALIVE | ON_UNKNOWN_OOP_REF)) == 0 , " must be absent" );
347+ assert ((decorators & AS_NO_KEEPALIVE) == 0 , " CAS only with keep-alive" );
348+ assert ((decorators & ON_STRONG_OOP_REF) != 0 , " CAS only for strong refs" );
342349 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set ();
343350 return bs->oop_cmpxchg (decorators, addr, compare_value, new_value);
344351}
345352
346353template <DecoratorSet decorators, typename BarrierSetT>
347354template <typename T>
348355inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_cmpxchg_in_heap(T* addr, oop compare_value, oop new_value) {
349- assert ((decorators & (AS_NO_KEEPALIVE | ON_UNKNOWN_OOP_REF)) == 0 , " must be absent" );
356+ assert ((decorators & AS_NO_KEEPALIVE) == 0 , " CAS only with keep-alive" );
357+ assert ((decorators & ON_STRONG_OOP_REF) != 0 , " CAS only for strong refs" );
350358 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set ();
351359 oop result = bs->oop_cmpxchg (decorators, addr, compare_value, new_value);
352360 if (ShenandoahCardBarrier) {
@@ -357,9 +365,20 @@ inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_ato
357365
358366template <DecoratorSet decorators, typename BarrierSetT>
359367inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_cmpxchg_in_heap_at(oop base, ptrdiff_t offset, oop compare_value, oop new_value) {
360- assert ((decorators & AS_NO_KEEPALIVE) == 0 , " must be absent" );
368+ assert ((decorators & AS_NO_KEEPALIVE) == 0 , " CAS only with keep-alive" );
369+ assert ((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0 , " CAS only for strong refs OR unknown refs (Unsafe)" );
361370 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set ();
371+
372+ // Unsafe.compareAndExchange/Set come here with ON_UNKNOWN_OOP_REF set.
373+ // These are normally strong refs, but one can use Unsafe on Reference.referent.
374+ // We cannot deal with that case. If application does Unsafe operations on
375+ // Reference.referent field, this likely breaks weak reference semantics already.
376+ // We upgrade the access to strong in (sometimes futile) attempt to maintain heap
377+ // integrity, and assert in debug builds for better diagnostics.
362378 DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
379+ assert ((resolved_decorators & ON_STRONG_OOP_REF) != 0 , " Application error: CAS on weak location" );
380+ resolved_decorators = (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF;
381+
363382 auto addr = AccessInternal::oop_field_addr<decorators>(base, offset);
364383 oop result = bs->oop_cmpxchg (resolved_decorators, addr, compare_value, new_value);
365384 if (ShenandoahCardBarrier) {
@@ -371,15 +390,17 @@ inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_ato
371390template <DecoratorSet decorators, typename BarrierSetT>
372391template <typename T>
373392inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_xchg_not_in_heap(T* addr, oop new_value) {
374- assert ((decorators & (AS_NO_KEEPALIVE | ON_UNKNOWN_OOP_REF)) == 0 , " must be absent" );
393+ assert ((decorators & AS_NO_KEEPALIVE) == 0 , " XCHG only with keep-alive" );
394+ assert ((decorators & ON_STRONG_OOP_REF) != 0 , " XCHG only for strong refs" );
375395 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set ();
376396 return bs->oop_xchg (decorators, addr, new_value);
377397}
378398
379399template <DecoratorSet decorators, typename BarrierSetT>
380400template <typename T>
381401inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_xchg_in_heap(T* addr, oop new_value) {
382- assert ((decorators & (AS_NO_KEEPALIVE | ON_UNKNOWN_OOP_REF)) == 0 , " must be absent" );
402+ assert ((decorators & AS_NO_KEEPALIVE) == 0 , " XCHG only with keep-alive" );
403+ assert ((decorators & ON_STRONG_OOP_REF) != 0 , " XCHG only for strong refs" );
383404 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set ();
384405 oop result = bs->oop_xchg (decorators, addr, new_value);
385406 if (ShenandoahCardBarrier) {
@@ -390,9 +411,20 @@ inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_ato
390411
391412template <DecoratorSet decorators, typename BarrierSetT>
392413inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value) {
393- assert ((decorators & AS_NO_KEEPALIVE) == 0 , " must be absent" );
414+ assert ((decorators & AS_NO_KEEPALIVE) == 0 , " XCHG only with keep-alive" );
415+ assert ((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0 , " XCHG only for strong refs OR unknown refs (Unsafe)" );
394416 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set ();
417+
418+ // Unsafe.getAndSet comes here with ON_UNKNOWN_OOP_REF set.
419+ // These are normally strong refs, but one can use Unsafe on Reference.referent.
420+ // We cannot deal with that case. If application does Unsafe operations on
421+ // Reference.referent field, this likely breaks weak reference semantics already.
422+ // We upgrade the access to strong in (sometimes futile) attempt to maintain heap
423+ // integrity, and assert in debug builds for better diagnostics.
395424 DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
425+ assert ((resolved_decorators & ON_STRONG_OOP_REF) != 0 , " Application error: XCHG on weak location" );
426+ resolved_decorators = (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF;
427+
396428 auto addr = AccessInternal::oop_field_addr<decorators>(base, offset);
397429 oop result = bs->oop_xchg (resolved_decorators, addr, new_value);
398430 if (ShenandoahCardBarrier) {
0 commit comments