RFR: 8373495: C2: Aggressively fold loads from objects that have not escaped [v19]

Roberto Castañeda Lozano rcastanedalo at openjdk.org
Fri Jan 23 14:18:00 UTC 2026


On Wed, 21 Jan 2026 02:57:17 GMT, Quan Anh Mai <qamai at openjdk.org> wrote:

>> Hi,
>> 
>> This patch is an alternative to #28764 but it does the analysis during IGVN instead.
>> 
>> ## The current PR:
>> 
>> The current escape analysis mechanism is all-or-nothing: either the object does not escape, or it does. If the object escapes, we lose the ability to analyse the values of its fields completely, even if the object only escapes at return.
>> 
>> This PR tries to find the escape status of an object at a load, and if it is decided that the object has not escaped there, we can try folding the load aggressively, ignoring calls and memory barriers to find a corresponding store that the load observes. Implementation-wise, when walking at `find_previous_store`, if we encounter a call or memory barrier, we start looking at all nodes that make the allocation escape. If all such nodes have a control input that is not a transitive control input of the call/barrier we are at, then we can decidedly say that the allocation has not escaped at that call/barrier, and walk past that call/barrier to find a corresponding store.
>> 
>> I do not see a noticeable difference in C2 runtime with and without this patch.
>> 
>> ## Future work:
>> 
>> 1. Fold a memory `Phi`.
>> 
>> This is pretty straightforward. We need to create a value `Phi` for each memory `Phi` so that we can handle loop `Phi`s.
>> 
>> 2. Fold a pointer `Phi`.
>> 
>> Currently, this PR is doing the trivial approach, just give up if we don't encounter a store into that `Phi`. However, we can do better. Consider this case:
>> 
>>     Point p1 = new Point;
>>     Point p2 = new Point;
>>     p1.x = v1;
>>     p2.x = v2;
>>     Point p = Phi(p1, p2);
>>     int a = p.x;
>> 
>> Then, `a` should be able to be folded to `Phi(v1, v2)` if `p1` and `p2` are known not to alias.
>> 
>> Another interesting case:
>> 
>>     Point p = Phi(p1, p2);
>>     p.x = v;
>>     p1.x = v1;
>>     int a = p.x;
>> 
>> Then, theoretically, we can fold `a` to `Phi(v1, v)` if `p1` and `p2` are known not to alias.
>> 
>> 3. Nested objects
>> 
>> It can be observed that if an object is stored into a memory that has not escaped, then it can be considered that the object has not escaped. For example:
>> 
>>     Point p = new Point;
>>     PointHolder h = new PointHolder;
>>     h.p = p;
>>     int x = p.x;
>>     escape(h);
>> 
>> Then, `p` can be considered that it has not escaped until `escape(h)`. To do this, the computation of `_aliases` in the constructor of `LocalEA` needs to be more comprehensive. See the comments in `LocalEA::check_escape_status`.
>> 
>> Please...
>
> Quan Anh Mai has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 22 additional commits since the last revision:
> 
>  - Remove the TriBool
>  - Merge branch 'master' into loadfoldingigvn
>  - Fix dead accesses, address reviews
>  - Merge branch 'master' into loadfoldingigvn
>  - Early return when not a heap access
>  - Fix escape at store
>  - Fix outdated and unclear comments
>  - copyright year, return, comments, whitespace
>  - Merge branch 'master' into loadfoldingigvn
>  - ea of phis and nested objects
>  - ... and 12 more: https://git.openjdk.org/jdk/compare/d18e3a33...ac82c2ea

test/hotspot/jtreg/compiler/escapeAnalysis/TestLoadFolding.java line 1:

> 1: /*

All new tests trigger escaping by passing an allocated object into a non-inlined method (`escape`) or by storing the allocated object into an input `PointHolder` parameter. It would be good to add a few positive and negative tests that exercise escaping by storing the allocated object into a static field.

test/hotspot/jtreg/compiler/escapeAnalysis/TestLoadFolding.java line 129:

> 127:     @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, counts = {IRNode.ALLOC, "1"})
> 128:     public Point test105(int begin, int end) {
> 129:         // Fold the load that is a part of a cycle

This comment, and the fact that this test is part of `runPositiveTests()`, seem to imply that we expect the load to be folded, but the current version of this changeset cannot do that, right? (due to the limitations listed in the PR description). If so, please update the comment, and consider moving this test and other tests that currently illustrate "future work" scenarios (`test106` and `test112`-`test115` I believe) into a separate `@Run` method (e.g. `runUnhandledTests` or similar).

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

PR Review Comment: https://git.openjdk.org/jdk/pull/28812#discussion_r2721375326
PR Review Comment: https://git.openjdk.org/jdk/pull/28812#discussion_r2721350190


More information about the hotspot-compiler-dev mailing list