RFR: 8351565: Implement JEP 502: Stable Values (Preview) [v56]

Viktor Klang vklang at openjdk.org
Thu Apr 17 11:10:12 UTC 2025


On Thu, 10 Apr 2025 14:19:25 GMT, Per Minborg <pminborg at openjdk.org> wrote:

>> Implement JEP 502.
>> 
>> The PR passes tier1-tier3 tests.
>
> Per Minborg has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Address comments on original vs underlying

Last review pass? :)

src/java.base/share/classes/java/lang/StableValue.java line 204:

> 202:  *         Set.of(1, 2, 4, 8, 16, 32);
> 203:  *     private static final UnaryOperator<Integer> UNDERLYING_LOG2 =
> 204:  *         i -> 31 - Integer.numberOfLeadingZeros(i);

Would boxing be necessary—i.e. what would be needed to use java.util.function.IntUnaryOperator?

src/java.base/share/classes/java/lang/StableValue.java line 318:

> 316:  * <p>
> 317:  * Another example, which has a more complex dependency graph, is to lazily computing the
> 318:  * Fibonacci sequence:

Suggestion:

 * Another example, which has a more complex dependency graph, is to compute the
 * Fibonacci sequence lazily:

src/java.base/share/classes/java/lang/StableValue.java line 410:

> 408:  *           parameter, and an {@linkplain #equals(Object) equals(obj)} parameter; all
> 409:  *           method parameters must be <em>non-null</em> or a {@link NullPointerException}
> 410:  *           will be thrown.

@minborg @mcimadamore I wonder if it makes more sense to specify that an implementation is free to synchronize on `this`, and as such, as a user, it is should be avoided to synchronize on StableValues.

This leaves the choice open to the implementations whether they want to synchonize on `this` or use some other shceme, while still discouraging users from synchronizing on StableValue instances.

src/java.base/share/classes/java/lang/StableValue.java line 415:

> 413:  *           a class and is usually neither exposed directly via accessors nor passed as
> 414:  *           a method parameter.
> 415:  *           Stable functions and collections make all reasonable efforts to provide

Suggestion:

 *           Stable functions and collections make reasonable efforts to provide

src/java.base/share/classes/java/lang/StableValue.java line 418:

> 416:  *           {@link Object#toString()} operations that do not trigger evaluation
> 417:  *           of the internal stable values when called.
> 418:  *           Stable collections have {@link Object#equals(Object)} operations that tries

Suggestion:

 *           Stable collections have {@link Object#equals(Object)} operations that try

src/java.base/share/classes/java/lang/StableValue.java line 422:

> 420:  *           As objects can be set via stable values but never removed, this can be a source
> 421:  *           of unintended memory leaks. A stable value's content is
> 422:  *           {@linkplain java.lang.ref##reachability strongly reachable}. Clients are

I wonder if "Clients" is the best word here. Perhaps "Developers"?

src/java.base/share/classes/java/lang/StableValue.java line 487:

> 485:      * <p>
> 486:      * If the supplier throws an (unchecked) exception, the exception is rethrown, and no
> 487:      * content is set. The most common usage is to construct a new object serving

Suggestion:

     * If the supplier throws an (unchecked) exception, the exception is rethrown and no
     * content is set. The most common usage is to construct a new object serving

src/java.base/share/classes/java/lang/StableValue.java line 571:

> 569:      * thrown by the computing thread.
> 570:      * <p>
> 571:      * If the provided {@code underlying} supplier throws an exception, it is relayed

Suggestion:

     * If the provided {@code underlying} supplier throws an exception, it is rethrown

src/java.base/share/classes/java/lang/StableValue.java line 670:

> 668:      * (e.g. via {@linkplain List#get(int) List::get}).
> 669:      * <p>
> 670:      * The provided {@code mapper} int function is guaranteed to be successfully invoked

Suggestion:

     * The provided {@code mapper} function is guaranteed to be successfully invoked

src/java.base/share/classes/java/lang/StableValue.java line 720:

> 718:      * <p>
> 719:      * If the provided {@code mapper} throws an exception, it is relayed to the initial
> 720:      * caller and no value associated with the provided key is recorded.

Suggestion:

     * If invoking the provided {@code mapper} function throws an exception, it is rethrown to the initial
     * caller and no value associated with the provided key is recorded.

src/java.base/share/classes/java/util/ImmutableCollections.java line 36:

> 34: import java.lang.reflect.Array;
> 35: import java.util.function.BiConsumer;
> 36: import java.util.function.BiFunction;

Make sure to update the copyright years of all the files modified in this PR.

test/jdk/java/lang/StableValue/StableMapTest.java line 140:

> 138:         String actual = newMap().toString();
> 139:         assertTrue(actual.startsWith("{"));
> 140:         for (int key:KEYS) {

Suggestion:

        for (int key : KEYS) {

test/jdk/java/lang/StableValue/StableMapTest.java line 317:

> 315:                      Consumer<Map<Integer, Integer>> consumer) implements Consumer<Map<Integer, Integer>> {
> 316:         @java.lang.Override
> 317:         public void   accept(Map<Integer, Integer> map) { consumer.accept(map); }

Suggestion:

        public void accept(Map<Integer, Integer> map) { consumer.accept(map); }

test/jdk/java/lang/StableValue/StableMapTest.java line 324:

> 322:     static Stream<Operation> nullAverseOperations() {
> 323:         return Stream.of(
> 324:                 new Operation("forEach",     m -> m.forEach(null))

Suggestion:

            new Operation("forEach",     m -> m.forEach(null))

test/jdk/java/lang/StableValue/StableMapTest.java line 341:

> 339:                 new Operation("replace2",          m -> m.replace(KEY, 1)),
> 340:                 new Operation("replace3",          m -> m.replace(KEY, KEY, 1)),
> 341:                 new Operation("replaceAll",        m -> m.replaceAll((a, _) -> a))

Suggestion:

            new Operation("clear",             Map::clear),
            new Operation("compute",           m -> m.compute(KEY, (_, _) -> 1)),
            new Operation("computeIfAbsent",   m -> m.computeIfAbsent(KEY, _ -> 1)),
            new Operation("computeIfPresent",  m -> m.computeIfPresent(KEY, (_, _) -> 1)),
            new Operation("merge",             m -> m.merge(KEY, KEY, (a, _) -> a)),
            new Operation("put",               m -> m.put(0, 0)),
            new Operation("putAll",            m -> m.putAll(Map.of())),
            new Operation("remove1",           m -> m.remove(KEY)),
            new Operation("remove2",           m -> m.remove(KEY, KEY)),
            new Operation("replace2",          m -> m.replace(KEY, 1)),
            new Operation("replace3",          m -> m.replace(KEY, KEY, 1)),
            new Operation("replaceAll",        m -> m.replaceAll((a, _) -> a))

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

PR Review: https://git.openjdk.org/jdk/pull/23972#pullrequestreview-2775117821
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048580493
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048568958
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048697517
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048698149
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048698693
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048700350
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048703097
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048705582
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048707720
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048709836
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048720211
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048722073
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048723018
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048723430
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048724778


More information about the core-libs-dev mailing list