Suppose I have this simple method:
static final Integer me = Integer.parseInt("2");
static int go() {
return me * 2;
}
For javac, me
is not a constant (according to the JLS rules), but for JIT most probably is.
I tried to test this with:
public class StaticFinal {
public static void main(String[] args) {
int hash = 0;
for(int i=0;i<1000_000;++i){
hash = hash ^ go();
}
System.out.println(hash);
}
static final Integer me = Integer.parseInt("2");
static int go() {
return me * 2;
}
}
And running it with:
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
"-XX:CompileCommand=print,StaticFinal.go"
-XX:PrintAssemblyOptions=intel
StaticFinal.java
I do not know assembly very good, but this is obvious:
mov eax,0x4
The result of go
is immediately 4
, i.e.: JIT "trusted" me
to be a constant, thus 2 * 2 = 4
.
If I drop static
and change the code to:
public class NonStaticFinal {
static NonStaticFinal instance = new NonStaticFinal();
public static void main(String[] args) {
int hash = 0;
for(int i=0;i<1000_000;++i){
hash = hash ^ instance.go();
}
System.out.println(hash);
}
final Integer me = Integer.parseInt("2");
int go() {
return me * 2;
}
}
And run that with:
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
"-XX:CompileCommand=print,NonStaticFinal.go"
-XX:PrintAssemblyOptions=intel
NonStaticFinal.java
I do see in assembly:
shl eax,1
which is actually the multiplication of me
with 2
, done via a shift. So JIT did not trust me
to be a constant, which is kind of expected.
And now the question. I thought that if I add TrustFinalNonStaticFields
flag, I will see the same mov eax 0x4
, i.e.: running with:
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
"-XX:CompileCommand=print,NonStaticFinal.go"
-XX:+UnlockExperimentalVMOptions
-XX:+TrustFinalNonStaticFields
-XX:PrintAssemblyOptions=intel
NonStaticFinal.java
should reveal mov eax,0x4
, but to my surprise it does not, and the code stays as:
shl eax,1
Can someone explain what is going on and what I am missing?
ciField::trust_final_non_static_fields
for the criteria of implicitly trusted final instance fields (notice how theif
chain bottoms out inreturn TrustFinalNonStaticFields
). – Kettijava/lang
include was added as part of the first memory-access API incubator in JDK 14. I don't know off the top of my head whyjava/lang
was added, but any way, it seems the cleanup of the cases for j.l.String and the box classes was missed at that time. – Ketti