RFR: 8351565: Implement JEP 502: Stable Values (Preview)

Per Minborg pminborg at openjdk.org
Thu Mar 13 11:20:14 UTC 2025


On Tue, 11 Mar 2025 07:50:38 GMT, Quan Anh Mai <qamai at openjdk.org> wrote:

>> Implement JEP 502.
>> 
>> The PR passes tier1-tier3 tests.
>
> src/java.base/share/classes/java/util/ImmutableCollections.java line 777:
> 
>> 775:         private final IntFunction<? extends E> mapper;
>> 776:         @Stable
>> 777:         private final StableValueImpl<E>[] backing;
> 
> You can use a backing `@Stable Object[]` instead. It will reduce indirection when accessing this list.

Can you please elaborate a bit more on your proposal @merykitty?

> src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java line 65:
> 
>> 63:     //
>> 64:     @Stable
>> 65:     private volatile Object value;
> 
> Can we use `acquire`/`release` semantics instead of `volatile`?

Yes we can. However, I am uncertain if the added complexity can motivate any performance benefits. Perhaps on ARM? I can do a benchmark on it.

> src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java line 128:
> 
>> 126:             final T newValue = supplier.get();
>> 127:             // The mutex is reentrant so we need to check if the value was actually set.
>> 128:             return wrapAndCas(newValue) ? newValue : orElseThrow();
> 
> Reentrancy into here seems really buggy, I would endorse disallowing it instead. In that case, a `ReentrantLock` seems better than the native monitor as we can cheaply check `lock.isHeldByCurrentThread()`

StableValueImpl was carefully designed to minimize memory footprint. Adding a lock would inflate memory usage substantially.

> src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java line 159:
> 
>> 157:     private boolean wrapAndCas(Object value) {
>> 158:         // This upholds the invariant, a `@Stable` field is written to at most once
>> 159:         return UNSAFE.compareAndSetReference(this, UNDERLYING_DATA_OFFSET, null, wrap(value));
> 
> There is no need for a cas here as all setters have to hold the lock. We should have a dedicated private `set` that asserts `Thread.holdsLock(this)`.

This is more of a belt and suspenders solution. It is true that it is redundant. A set volatile would suffice here.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1989016337
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1988630199
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1993142117
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1988634451


More information about the compiler-dev mailing list