RFR: 8330465: Stable Values and Collections (Internal)
Per Minborg
pminborg at openjdk.org
Tue May 14 14:14:17 UTC 2024
# 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
More information about the compiler-dev
mailing list