为什么优化后的虚拟调用会指向热点jit汇编中的相同地址?

问题描述 投票:0回答:1

这里有一篇文章介绍虚拟调用的jit优化策略。

但令我惊讶的是,所有优化的虚拟调用都使用相同的地址,就像文章中的

callq 0x000000011418ea00

所以我很好奇它在该地址中实际执行的操作,以及它如何知道要调用哪个函数,因为所有优化的虚拟调用都定向到同一地址。

java assembly jit jvm-hotspot
1个回答
1
投票

我的理解是,幕后发生了另一种优化,相同的代码折叠

CustObj::methodCall
CustObj2::methodCall
的代码非常相似,仅打印字符串不同。因此,JVM 编译器能够为它们生成相同的代码:

$ javac tmp.java
$ javap -c -constants 'TestVirtualCall2$CustObj.class'
Compiled from "tmp.java"
class TestVirtualCall2$CustObj {
  public void methodCall();
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lconst_0
       4: lcmp
       5: ifne          16
       8: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      11: ldc           #4                  // String CustObj is very good!
      13: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      16: return
}
$ javap -c -constants 'TestVirtualCall2$CustObj2.class'
Compiled from "tmp.java"
class TestVirtualCall2$CustObj2 extends TestVirtualCall2$CustObj {
  public final void methodCall();
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lconst_0
       4: lcmp
       5: ifne          16
       8: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      11: ldc           #4                  // String CustObj2 is very good!
      13: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      16: return
}

请注意,即使字符串加载命令

ldc #4
也恰好相同,因为编译器将字符串放入各个类常量池中的相同位置。

因此 JIT 肯定只会为这两种虚拟方法生成一个 x86 代码实例。

附注

我认为这种优化更多的是随机副作用,并不是作者的意图。要求他在文章的下一个版本中对

CustObj2
类中的代码进行更多更改可能是有意义的。

© www.soinside.com 2019 - 2024. All rights reserved.