RFC : Approach to handle Allocation Merges in C2 Scalar Replacement
Cesar Soares Lucas
Divino.Cesar at microsoft.com
Tue Apr 5 04:34:16 UTC 2022
Hi, Xin Liu.
Thank you for asking these questions and sharing your ideas!
You understand is correct. I’m trying to make objects that currently are NonEscape but NSR become Scalar Replaceable. These objects are marked as NSR because they are connected in a Phi node.
You understood Vladimir selector idea correctly (AFAIU). The problem with that idea is that we can’t directly access the objects after the Region node merging the control branches that define such objects. However, after playing for a while with this Selector idea I found out that it seems we don’t really need it: if we generalize split_through_phi enough we can handle many cases that cause objects to be marked as NSR.
I’ve observed the CastPP nodes. I did some experiments to identify the most frequent node types that come after Phi nodes merging object allocation. ***Roughly the numbers are***: ~70% CallStaticJava, 6% Allocate, 3% CmpP, 3% CastPP, etc.
The split_through_phi idea works great (AFAIU) if we are floating up nodes that don’t have control inputs, unfortunately often nodes do and that’s a bummer. However, as I mentioned above, looks like that in most of the cases the nodes that consume the merge Phi _and_ have control input, are CallStaticJava “Uncommon Trap” and I’ve an idea to “split through phi” these nodes.
Thanks again for the question and sorry for the long text.
Cesar
On 4/4/22, 4:10 PM, "Liu, Xin" <xxinliu at amazon.com> wrote:
hi, Cesar
I am trying to catch up your conversation. Allow me to repeat the
problem. You are improving NonEscape but NSR objects, tripped by
merging. The typical form is like the example from "Control Flow
Merges".
https://cr.openjdk.java.net/~cslucas/escape-analysis/EscapeAnalysis.html
Those two JavaObjects in your example 'escapeAnalysisFails' are NSR
because they intertwine and will hinder split_unique_types. In Ivanov's
approach, we insert an explicit selector to split JOs at uses. Because
uses are separate, we then can proceed with split_unique_types() for
them individually. (please correct me if I misunderstand here)
here is the original control flow.
B0--
o1 = new MyPair(0,0)
cond
----
| \
| B1--------------------
| | o2 = new MyPair(x, y)
| -----------------------
| /
B2-------------
o3 = phi(o1, o2)
x = o3.x;
---------------
here is after?
B0--
o1 = new MyPair(0,0)
cond
----
| \
| B1--------------------
| | o2 = new MyPair(x, y)
| -----------------------
| /
B2-------------
selector = phi(o1, o2)
cmp(select, 0)
---------------
| \
-------- --------
x1 = o1.x| x2 = o2.x
--------- -------
| /
---------------
x3 = phi(x1, x2)
---------------
Besides the fixed form Load/Store(PHI(base1, base2), ADDP), I'd like to
report that C2 sometimes insert CastPP in between. Object
'Integer(65536)' in the following example is also non-escape but NSR.
there's a CastPP to make sure the object is not NULL. The more general
case is that the object is returned from a inlined function called.
public class MergingAlloc {
...
public static Integer zero = Integer.valueOf(0);
public static int testBoxingObject(boolean cond) {
Integer i = zero;
if (cond) {
i = new Integer(65536);
}
return i; // i.intValue();
}
public static void main(String[] args) {
MyPair p = new MyPair(0, 0);
escapeAnalysisFails(true, 1, 0);
testBoxingObject(true);
}
}
I though that LoadNode::split_through_phi() should split the LoadI of
i.intValue() in the Iterative GVN before Escape Analysis but current
it's not. I wonder if it's possible to make
LoadNode::split_through_phi() or PhaseIdealLoop::split_thru_phi() more
general. if so, it will fit better in C2 design. i.e. we evolve code in
local scope. In this case, splitting through a phi node of multiple
objects is beneficial when the result disambiguate memories.
In your example, ideally split_through_phi() should be able to produce
simpler code. currently, split_through_phi only works for load node and
there are a few constraints.
B0-------------
o1 = new MyPair(0,0)
x1 = o1.x
cond
----------------
| \
| B1--------------------
| | o2 = new MyPair(x, y)
| | x2 = o2.x;
| -----------------------
| /
-------------
x3 = phi(x1, x2)
---------------
thanks,
--lx
More information about the hotspot-compiler-dev
mailing list