# 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 an `AtomicReference` and one 
protected by double-checked locking under concurrent access by 8 threads:


Benchmark                       Mode  Cnt  Score   Error  Units
StableBenchmark.instanceAtomic  avgt   10  1.576 ? 0.052  ns/op
StableBenchmark.instanceDCL     avgt   10  1.608 ? 0.059  ns/op
StableBenchmark.instanceStable  avgt   10  0.979 ? 0.023  ns/op <- StableValue 
(~40% faster than DCL)


Performance compared to static variables protected by `AtomicReference`, 
class-holder idiom holder, and double-checked locking (8 threads):


Benchmark                       Mode  Cnt  Score   Error  Units
StableBenchmark.staticAtomic    avgt   10  1.335 ? 0.056  ns/op
StableBenchmark.staticCHI       avgt   10  0.623 ? 0.086  ns/op
StableBenchmark.staticDCL       avgt   10  1.418 ? 0.171  ns/op
StableBenchmark.staticList      avgt   10  0.617 ? 0.024  ns/op
StableBenchmark.staticStable    avgt   10  0.604 ? 0.022  ns/op <- StableValue 
( > 2x faster than `AtomicInteger` and DCL)


Performance for stable lists in both instance and static contexts whereby the 
sum of random contents is calculated for stable lists (which are thread-safe) 
compared to `ArrayList` instances (which are not thread-safe) (under single 
thread access):


Benchmark                                     Mode  Cnt  Score   Error  Units
StableListSumBenchmark.instanceArrayList      avgt   10  0.356 ? 0.005  ns/op
StableListSumBenchmark.instanceList           avgt   10  0.373 ? 0.017  ns/op 
<- Stable list
StableListSumBenchmark.staticArrayList        avgt   10  0.352 ? 0.002  ns/op
StableListSumBenchmark.staticList             avgt   10  0.356 ? 0.003  ns/op 
<- Stable list


Performance for stable maps in a static context compared to a 
`ConcurrentHashMap` (under single thread access):


Benchmark                                     Mode  Cnt  Score   Error  Units
StablePropertiesBenchmark.chmRaw              avgt   10  3.416 ? 0.031  ns/op
StablePropertiesBenchmark.mapRaw              avgt   10  2.105 ? 0.012  ns/op 
<- Stable map (~40% faster)


All figures above are from local tests on a Mac M1 laptop and should only be 
constructed as indicative figures.

## Implementation details

There are some noteworthy implementation details in this PR:

 * A field is _trusted_ if it is _declared_ as a `final StableValue`. 
Previously, the determination of trustworthiness was connected to the _class in 
which it was declared_ (e.g. is it a `record` or a hidden class). In order to 
grant such trust, there are extra restrictions imposed on reflection and 
`sun.misc.Unsafe` usage for such declared `StableValue` fields. This is similar 
to how `record` classes are handled.
 * In order to allow plain memory semantics for read operations across threads 
(rather than `volatile` semantics which is slower and which is normally 
required for double-checked-locking access), we perform a _freeze_ operation 
before an object becomes visible to other threads. This will prevent 
store-store reordering and hence, we are able to guarantee complete objects are 
always seen even under plain memory semantics.
 * In collections with `StableValue` elements/values, a transient `StableValue` 
view backed by internal arrays is created upon read operations. This improves 
initialization time, reduces storage requirements, and improves access 
performance as these transient objects are eliminated by the C2 compiler.

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

Commit messages:
 - Merge branch 'master' into stable-value
 - Rework the creation of StableEnumMaps
 - Update sun.misc.Unsafe
 - Fix error in hash code
 - Add methods to create generic arrays
 - Change class types
 - Add a marker interface TrustedFieldType
 - Improve array test
 - Clean up tests
 - Add tests
 - ... and 162 more: https://git.openjdk.org/jdk/compare/4ba74475...5d5dcced

Changes: https://git.openjdk.org/jdk/pull/18794/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=18794&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8330465
  Stats: 5733 lines in 39 files changed: 5708 ins; 13 del; 12 mod
  Patch: https://git.openjdk.org/jdk/pull/18794.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/18794/head:pull/18794

PR: https://git.openjdk.org/jdk/pull/18794

Reply via email to