假设我有这个简单的方法:
static final Integer me = Integer.parseInt("2");
static int go() {
return me * 2;
}
对于 javac,me不是常量(根据 JLS 规则),但对于 JIT 很可能是。
我尝试使用以下方法对此进行测试:
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;
}
}
并运行它:
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
"-XX:CompileCommand=print,StaticFinal.go"
-XX:PrintAssemblyOptions=intel
StaticFinal.java
我不知道组装很好,但这很明显:
mov eax,0x4
的结果go是立即的4,即:JIT “信任”me是一个常数,因此2 * 2 = 4。
如果我删除static并将代码更改为:
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;
}
}
并运行它:
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
"-XX:CompileCommand=print,NonStaticFinal.go"
-XX:PrintAssemblyOptions=intel
NonStaticFinal.java
我确实在汇编中看到:
shl eax,1
这实际上是mewith的乘法2,通过移位完成。所以 JIT 不相信me是一个常数,这是意料之中的。
现在的问题。我想如果我添加TrustFinalNonStaticFields标志,我会看到相同的mov eax 0x4,即:运行:
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
"-XX:CompileCommand=print,NonStaticFinal.go"
-XX:+UnlockExperimentalVMOptions
-XX:+TrustFinalNonStaticFields
-XX:PrintAssemblyOptions=intel
NonStaticFinal.java
应该显示mov eax,0x4,但令我惊讶的是它没有,并且代码保持为:
shl eax,1
有人可以解释发生了什么以及我缺少什么吗?