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

Luca Kellermann duke at openjdk.org
Sun Mar 16 19:41:02 UTC 2025


On Thu, 13 Mar 2025 15:22:43 GMT, Per Minborg <pminborg at openjdk.org> wrote:

>> Implement JEP 502.
>> 
>> The PR passes tier1-tier3 tests.
>
> Per Minborg has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 246 commits:
> 
>  - Merge branch 'master' into implement-jep502
>  - Clean up exception messages and fix comments
>  - Rename field
>  - Rename method and fix comment
>  - Rework reenterant logic
>  - Use acquire semantics for reading rather than volatile semantics
>  - Add missing null check
>  - Simplify handling of sentinel, wrap, and unwrap
>  - Fix JavaDoc issues
>  - Fix members in StableEnumFunction
>  - ... and 236 more: https://git.openjdk.org/jdk/compare/4e51a8c9...d6e1573f

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

> 796:                 throw new IndexOutOfBoundsException(i);
> 797:             }
> 798:         }

I think `orElseSet` should be outside of the `try` block, otherwise an `ArrayIndexOutOfBoundsException` thrown by `mapper.apply` will be wrapped.

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

> 1486:             final K k = (K) key;
> 1487:             return stable.orElseSet(new Supplier<V>() {
> 1488:                 @Override public V get() { return mapper.apply(k); }});

This can return `null` (`StableMap` does allow `null` values), so the `getOrDefault` implementation in `AbstractImmutableMap` does not properly work for `StableMap`:

var map = StableValue.map(Set.of(1), _ -> null);
// should print "null", but prints "default value"
System.out.println(map.getOrDefault(1, "default value"));

src/java.base/share/classes/jdk/internal/lang/stable/EmptyStableFunction.java line 47:

> 45:     @Override
> 46:     public R apply(T value) {
> 47:         throw new IllegalArgumentException("Input not allowed: " + value);

`StableEnumFunction` and `StableFunction` throw a `NullPointerException` if `value` is `null`.

src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java line 68:

> 66:         } catch (ArrayIndexOutOfBoundsException ioob) {
> 67:             throw new IllegalArgumentException("Input not allowed: " + value, ioob);
> 68:         }

Same here.

src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java line 61:

> 59:             throw new IllegalArgumentException("Input not allowed: " + index, ioob);
> 60:         }
> 61:     }

Same here.

src/java.base/share/classes/jdk/internal/lang/stable/StableValueFactories.java line 77:

> 75:         int i = 0;
> 76:         for (K key : keys) {
> 77:             entries[i++] = Map.entry(key, StableValueImpl.newInstance());

`Map.entry` causes `null` keys to throw a `NullPointerException`, meaning there can't be stable functions/maps with a `null` input/key. They can however have `null` values. Is that intended?

src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java line 132:

> 130:         // Prevent reentry
> 131:         if (Thread.holdsLock(this)) {
> 132:             throw new IllegalStateException("Recursing supplier detected: " + supplier);

Is it right to include `supplier` in the message? The actual recursing supplier could be another one:


var s = StableValue.<Integer>of();
// throws java.lang.IllegalStateException: Recursing supplier detected: supplier 2
s.orElseSet(new Supplier<>() {
    public String toString() {return "supplier 1";}
    public Integer get() {
        s.orElseSet(new Supplier<>() {
            public String toString() {return "supplier 2";}
            public Integer get() {return 2;}
        });
        return 1;
    }
});

The exception message could also be confusing in cases like this:

var s = StableValue.of();
synchronized (s) {
    // throws java.lang.IllegalStateException: Recursing supplier detected
    s.trySet(null);
}

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

PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997660330
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997685354
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997681440
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997660665
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997660937
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997680982
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r1997689245


More information about the core-libs-dev mailing list