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

Quan Anh Mai qamai at openjdk.org
Wed Jan 14 17:33:49 UTC 2026


On Sat, 13 Dec 2025 03:51:32 GMT, Vladimir Ivanov <vlivanov 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...
>
> Very nice! I definitely prefer the approach here to #28764.
> 
> I see that the unit test stays the same and there's an adjustment in some other test, so I assume this version is functionally more powerful than #28764 version.
> 
> Have you had a chance to measure how much it affects compilation speed compared to #28764?
> 
> (The code is dense and hard to reason about, so some polishing/refactoring to make it more readable. Also, please, think about verification checks.)

@iwanowww Unfortunately, I believe there is no such feature yet. That's why we skip `LoadNode`s in `PhaseIterGVN::verify_Ideal|Identity|Value_for`. I think it is profitable to investigate manually appending them to the work list after each round of IGVN, similar to how it is handled in `PhaseCCP`.

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

PR Comment: https://git.openjdk.org/jdk/pull/28812#issuecomment-3750712766


More information about the hotspot-compiler-dev mailing list