【问题标题】:Javac Implementation: What jvm instructions does a method call produce?Javac 实现:方法调用会产生哪些 jvm 指令?
【发布时间】:2018-12-21 10:28:26
【问题描述】:

假设我在 java 中有一个方法调用站点。什么是等效的 jvm 字节码(除了转换为 invokevirtual/static 等的调用)?我对将接收器加载到堆栈上的命令更感兴趣。

-显然是加载了一个命令。

-另一个可能是另一个调用返回堆栈上的 refobject

-三、新指令。 (例如 new A().foo()。它被复制了。但是被复制的被构造函数消耗)

-四个,也许(??)重复。 (当有 a.foo(); a.bar(); 有没有机会编译器会产生 aload 然后 dup 而不是 aload aload?)

我最大的问题是 rest dup 命令。因为他们有点洗牌。 javac什么时候产生它们?编译调用站点时是否使用它们?

我试图找到没有运气的文档。然后找到了源代码,但要花几天时间才能深入研究。我相信Code.java and Gen.java 文件负责翻译/编译过程。

【问题讨论】:

  • 可以使用javap命令查看你的类中使用的jvm字节码---docs.oracle.com/javase/7/docs/technotes/tools/windows/…
  • 是的,但它不会涵盖所有可能性。我不能确定我的示例是否涵盖了所有内容
  • 正如您自己指出的,javac 使用 dup 进行构造函数调用。通常,当您取消引用同一个变量时,它不使用dup。变量访问将始终编译为变量访问。但反过来,它可能会添加未出现在源代码中的合成变量。堆栈操作相当少见。但是一个例子是objArray[index] += "string",它使用dup2(在JDK11中)来克隆数组引用和索引,因为更新需要aaloadaastore。另一种情况是(variable = expression).method();

标签: java jvm javac method-call


【解决方案1】:

javac 可以使用几乎任何产生引用的字节码指令来加载接收器。

  • aload、invokeX、new + dup
    您已经提到的那些。
  • getfield,getstatic

    field.method();
    
  • 加载

    arr[index].method();
    
  • 新数组

    (new Object[0]).hashCode();
    
  • 多新数组

    (new byte[5][10]).getClass();
    
  • checkcast

    ((List) obj).size();
    
  • ldc

    MyClass.class.getName();
    
  • aconst_null

    ((Object) null).getClass();
    
  • 重复

    IntSupplier s = field::hashCode;
    

    这里dup + invokevirtual 用于发出一个棘手的空检查:

    getstatic     #2      // Field field:Ljava/lang/String;
    dup
    invokevirtual #3      // Method java/lang/Object.getClass:()Ljava/lang/Class;
    pop
    invokedynamic #4,  0  // InvokeDynamic #0:getAsInt
    

【讨论】:

  • 请注意,从 JDK 9 开始,编译器将插入一个 Objects.requireNonNull(…) 调用而不是 … .getClass() 用于内部 null 检查(另请参阅 this answer
猜你喜欢
  • 1970-01-01
  • 2020-05-03
  • 1970-01-01
  • 2011-08-25
  • 2017-12-21
  • 2019-05-10
  • 2020-11-05
  • 2010-09-19
  • 2016-02-15
相关资源
最近更新 更多