This PR proposes to improve the initialization and access performance of 
`LazyConstantImpl`.

## Tiered access ##

The first-tier (already-initialized) fast path in `get()` remains 
`@ForceInline` and contains only a minimal _acquire_ load of the computed 
constant, a null check, and a cast. 

A second-tier method, which includes the successful computation path, is no 
longer annotated with `@DontInline`, allowing the C2 to make its own inlining 
decisions. 

In tier three, contention handling and exceptional paths are further isolated 
in a `@DontInline` method and other helper methods.

## Other optimizations ##

The previous monitor-based initialization with `synchronized` and the recursive 
detection via the native method `Thread.holdsLock()` are replaced by a 
CAS-based _state machine_. A new `state` field can now represent the initial 
supplier, the computing thread, registered waiters, or a terminal 
success/failure state. Normally, the computing `Thread` object is stored 
directly, but in the unusual case a `Thread` also implements `Supplier`, the 
scheme falls back to using a boxed `Long`, keeping the statemachine types 
disjoint.

Contending threads initially spin, followed by short randomized timed backoffs. 
If computation is still in progress, they register in a waiting queue and park 
until signalled by the computing thread. Virtual threads use significantly less 
spinning and timed waiting to limit carrier thread and scheduler pressure. 
Completion atomically detaches and signals registered waiters on both 
successful and failed computations. Interrupted waiters retain their interrupt 
status, and spurious wakeups are handled by rechecking the `state`.

The polling loop uses _opaque_ `state` loads while the `state` remains 
unchanged (for optimal performance on weaker platforms) and then performs a 
final _acquire_ load before acting on the state transition. Publication of the 
computed constant continues to use _acquire_/_release_ semantics.

The constructor deliberately initializes the _volatile_ `state` using a direct 
store to avoid bootstrap issues.

## Tests ##

The PR also proposes to add several new tests and a new benchmark that tests 
dynamic performance when creating and using `LazyConstant` instances on the fly.

On multiple platforms, this branch passes testing in:
 - [x] tier1
 - [x] tier2
 - [x] tier3
 - [x] tier4

## Future work ##

Similar schemes may be introduced in `LazyConstants` under a separate PR.

---------
- [x] I confirm that I make this contribution in accordance with the [OpenJDK 
Interim AI Policy](https://openjdk.org/legal/ai).

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

Commit messages:
 - Fix bootstrap issue
 - Merge branch 'master' into rfe-lazyconstant-performance
 - Add a dynamic benchmark
 - Add special handling for VTs
 - Use waiters to improve discovery latency
 - Transition to opaque semantic in the hot loop
 - Use CAE instead of CAS and move checks
 - Improve performance
 - Eliminate Long boxing
 - Use CAS instead of synchronized
 - ... and 2 more: https://git.openjdk.org/jdk/compare/64e0cf41...e8aa625b

Changes: https://git.openjdk.org/jdk/pull/32450/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=32450&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8390381
  Stats: 571 lines in 4 files changed: 471 ins; 20 del; 80 mod
  Patch: https://git.openjdk.org/jdk/pull/32450.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/32450/head:pull/32450

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

Reply via email to