Last active
December 15, 2022 00:06
-
-
Save navyxliu/ee4465e2146ef99c5ae1fa1ba6b70e25 to your computer and use it in GitHub Desktop.
Example2.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -Xcomp -Xms16M -Xmx16M -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:-UseOnStackReplacement -XX:CompileOnly='Example2.foo' -XX:CompileCommand=dontinline,Example2.blackhole | |
class Example2 { | |
private Object _cache; | |
public Object foo(boolean cond) { | |
Object x = new Object(); | |
blackhole(); | |
if (cond) { | |
_cache = x; | |
} | |
return x; | |
} | |
public static void blackhole() {} | |
public static void main(String[] args) { | |
Example2 kase = new Example2(); | |
// Epsilon Test: | |
// By setting the maximal heap and use EpsilonGC, let's see how long and how many iterations the program can sustain. | |
// if PEA manages to reduce allocation rate, we expect the program to stay longer. | |
// Roman commented it with a resonable doubt: "or your code slow down the program..." | |
// That's why I suggest to observe iterations. It turns out not trivial because inner OOME will implode hotspot. We don't have a chance to execute the final statement... | |
long iterations = 0; | |
try { | |
while (true) { | |
kase.foo(0 == (iterations & 0xf)); | |
iterations++; | |
} | |
} finally { | |
System.err.println("Epsilon Test: " + iterations); | |
} | |
} | |
} |
C2 generates code like this after parser with -XX:+DoPartialEscapeAnalysis
.
public void foo(boolean cond1, boolean cond2) {
Object x0 = new Object();
blackhole();
if (cond1) {
x1 = new Object();
_cache1 = x1;
}
x2 = phi(x2=new Object(), x1);
blackhole();
if (cond2) {
_cache2 = x2;
}
}
if cond1 == true && cond2== true, then we have _cache1 == __cache2 == x1
Thank you for vetting this. here is a modified program from and enable assertion.
We can verify that cache1 == cache2.
The reason is explained above. One thing is worth noting: when we parse "if(cond2) ...", object x has been materialized. PEA won't materialize it again at "_cache2 = x".
// -ea -Xcomp -Xms16M -Xmx16M -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:-UseOnStackReplacement -XX:CompileOnly='Example2_merykitty.foo' -XX:CompileCommand=dontinline,Example2_merykitty.blackhole -XX:+DoPartialEscapeAnalysis
class Example2_merykitty {
private static Object _cache1;
private static Object _cache2;
public void foo(boolean cond1, boolean cond2) {
Object x = new Object();
blackhole();
if (cond1) {
_cache1 = x;
}
blackhole();
if (cond2) {
_cache2 = x;
}
}
public static void blackhole() {}
public static void main(String[] args) {
Example2_merykitty kase = new Example2_merykitty();
long iterations = 0;
try {
while (true) {
boolean cond = 0 == (iterations & 0xf);
kase.foo(cond, cond);
assert Example2_merykitty._cache1 == Example2_merykitty._cache2 :"check";
iterations++;
}
} finally {
System.err.println("Epsilon Test: " + iterations);
}
}
}
Link to Example3_1. It features non-trivial object with stateful fields and inlined methods.
https://gist.github.com/navyxliu/74d0546004a773cb5219754f6ed63d43
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wonder how can you deal with the identity issue mentioned by Vladimir, i.e this code
Here if
cond1 && cond2
, we must have_cache1 == _cache2
, so you can't perform the transformation as you do above. In other word, the transformation can only be done if the object is sure to have not escaped at that point.