RFR: 8320649: C2: Optimize scoped values [v6]

Roland Westrelin roland at openjdk.org
Thu Jan 25 14:48:06 UTC 2024


> This change implements C2 optimizations for calls to
> ScopedValue.get(). Indeed, in:
> 
> 
> v1 = scopedValue.get();
> ...
> v2 = scopedValue.get();
> 
> 
> `v2` can be replaced by `v1` and the second call to `get()` can be
> optimized out. That's true whatever is between the 2 calls unless a
> new mapping for `scopedValue` is created in between (when that happens
> no optimizations is performed for the method being compiled). Hoisting
> a `get()` call out of loop for a loop invariant `scopedValue` should
> also be legal in most cases.
> 
> `ScopedValue.get()` is implemented in java code as a 2 step process. A
> cache is attached to the current thread object. If the `ScopedValue`
> object is in the cache then the result from `get()` is read from
> there. Otherwise a slow call is performed that also inserts the
> mapping in the cache. The cache itself is lazily allocated. One
> `ScopedValue` can be hashed to 2 different indexes in the cache. On a
> cache probe, both indexes are checked. As a consequence, the process
> of probing the cache is a multi step process (check if the cache is
> present, check first index, check second index if first index
> failed). If the cache is populated early on, then when the method that
> calls `ScopedValue.get()` is compiled, profile reports the slow path
> as never taken and only the read from the cache is compiled.
> 
> To perform the optimizations, I added 3 new node types to C2:
> 
> - the pair
>   ScopedValueGetHitsInCacheNode/ScopedValueGetLoadFromCacheNode for
>   the cache probe
>   
> - a cfg node ScopedValueGetResultNode to help locate the result of the
>   `get()` call in the IR graph.
> 
> In pseudo code, once the nodes are inserted, the code of a `get()` is:
> 
> 
> hits_in_the_cache = ScopedValueGetHitsInCache(scopedValue)
> if (hits_in_the_cache) {
>   res = ScopedValueGetLoadFromCache(hits_in_the_cache);
> } else {
>   res = ..; //slow call possibly inlined. Subgraph can be arbitray complex
> }
> res = ScopedValueGetResult(res)
> 
> 
> In the snippet:
> 
> 
> v1 = scopedValue.get();
> ...
> v2 = scopedValue.get();
> 
> 
> Replacing `v2` by `v1` is then done by starting from the
> `ScopedValueGetResult` node for the second `get()` and looking for a
> dominating `ScopedValueGetResult` for the same `ScopedValue`
> object. When one is found, it is used as a replacement. Eliminating
> the second `get()` call is achieved by making
> `ScopedValueGetHitsInCache` always successful if there's a dominating
> `ScopedValueGetResult` and replacing its companion
> `ScopedValueGetLoadFromCache` by the dominating
> `ScopedValueGetResult`.
> 
> Hoisting a `g...

Roland Westrelin has updated the pull request incrementally with one additional commit since the last revision:

  Update src/hotspot/share/opto/callGenerator.cpp
  
  Co-authored-by: Emanuel Peter <emanuel.peter at oracle.com>

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

Changes:
  - all: https://git.openjdk.org/jdk/pull/16966/files
  - new: https://git.openjdk.org/jdk/pull/16966/files/6e797117..a24f729f

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk&pr=16966&range=05
 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=16966&range=04-05

  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/16966.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/16966/head:pull/16966

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


More information about the hotspot-compiler-dev mailing list