On Wed, 15 May 2024 15:27:34 GMT, Per Minborg <pminb...@openjdk.org> wrote:

>> # Stable Values & Collections (Internal)
>> 
>> ## Summary
>> This PR proposes to introduce an internal _Stable Values & Collections_ API, 
>> which provides immutable value holders where elements are initialized _at 
>> most once_. Stable Values & Collections offer the performance and safety 
>> benefits of final fields while offering greater flexibility as to the timing 
>> of initialization.
>> 
>> ## Goals
>>  * Provide an easy and intuitive API to describe value holders that can 
>> change at most once.
>>  * Decouple declaration from initialization without significant footprint or 
>> performance penalties.
>>  * Reduce the amount of static initializer and/or field initialization code.
>>  * Uphold integrity and consistency, even in a multi-threaded environment.
>>  
>> For more details, see the draft JEP: https://openjdk.org/jeps/8312611
>> 
>> ## Performance 
>> Performance compared to instance variables using two `AtomicReference` and 
>> two protected by double-checked locking under concurrent access by all 
>> threads:
>> 
>> 
>> Benchmark                                      Mode  Cnt      Score      
>> Error   Units
>> StableBenchmark.atomic                        thrpt   10    259.478 ?   
>> 36.809  ops/us
>> StableBenchmark.dcl                           thrpt   10    225.710 ?   
>> 26.638  ops/us
>> StableBenchmark.stable                        thrpt   10   4382.478 ? 
>> 1151.472  ops/us <- StableValue significantly faster
>> 
>> 
>> Performance compared to static variables protected by `AtomicReference`, 
>> class-holder idiom holder, and double-checked locking (all threads):
>> 
>> 
>> Benchmark                                      Mode  Cnt      Score      
>> Error   Units
>> StableStaticBenchmark.atomic                  thrpt   10   6487.835 ?  
>> 385.639  ops/us
>> StableStaticBenchmark.dcl                     thrpt   10   6605.239 ?  
>> 210.610  ops/us
>> StableStaticBenchmark.stable                  thrpt   10  14338.239 ? 
>> 1426.874  ops/us
>> StableStaticBenchmark.staticCHI               thrpt   10  13780.341 ? 
>> 1839.651  ops/us
>> 
>> 
>> Performance for stable lists (thread safe) in both instance and static 
>> contexts whereby we access a single value compared to `ArrayList` instances 
>> (which are not thread-safe) (all threads):
>> 
>> 
>> Benchmark                                      Mode  Cnt      Score      
>> Error   Units
>> StableListElementBenchmark.instanceArrayList  thrpt   10   5812.992 ? 
>> 1169.730  ops/us
>> StableListElementBenchmark.instanceList       thrpt   10   4818.643 ?  
>> 704.893  ops/us
>> StableListElementBenchmark...
>
> Per Minborg has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Switch to monomorphic StableValue and use lazy arrays

src/java.base/share/classes/jdk/internal/lang/StableValue.java line 384:

> 382:      * @param <T>      the memoized type
> 383:      */
> 384:     static <T> Supplier<T> ofSupplier(Supplier<? extends T> original) {

`ofSupplier` sounds like this method returns a `StableValue` from a `Supplier`. 
I recommend another name, such as `stableSupplier`, `wrapSupplier`, or 
`memoize`, to better associate with the method's types.

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

> 73:      */
> 74:     @Stable
> 75:     private int state;

Can we change this to be a byte, so state and supplying fields can be packed 
together in 4 bytes in some layouts?

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

> 102:         // Optimistically try plain semantics first
> 103:         final V v = value;
> 104:         if (v != null) {

If `value == null && state == NULL`, can the path still be constant folded? I 
doubt it because `value` in this case may not be promoted to constant.

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

> 137:             case NON_NULL: { return valueVolatile(); }
> 138:             case ERROR:    { throw StableUtil.error(this); }
> 139:             case DUMMY:    { throw shouldNotReachHere(); }

Redundant branch?

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

> 234:                 } catch (Throwable t) {
> 235:                     putState(ERROR);
> 236:                     putMutex(t.getClass());

Should we cache the exception instance so we can rethrow it in future ERROR 
state `orThrow` calls?

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

> 238:                 }
> 239:             } finally {
> 240:                 supplying = false;

Resetting a stable field is a bad idea. I recommend renaming this to 
`supplierCalled` or `supplied` so we never transition this false -> true

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

> 254: 
> 255:     @ForceInline
> 256:     private <K> V computeIfUnsetShared(Object provider, K key) {

Can we let suppliers share this path too, with a null key? I see this path 
supports suppliers but supplier code path doesn't call this path.

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

> 401:                     stable.computeIfUnset(supplier);
> 402:                 } catch (Throwable throwable) {
> 403:                     final Thread.UncaughtExceptionHandler 
> uncaughtExceptionHandler =

Does this exception handling differ from the default one for threads? If not, I 
think we can safely remove this catch block, as all exceptions are just 
propagated and computeIfUnset doesn't declare any checked exception.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601935261
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601937748
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601916538
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601918911
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601940341
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601941518
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601942956
PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1601927751

Reply via email to