【问题标题】:Parse receiver of Java method invocation on the Bytecode level在字节码级别解析 Java 方法调用的接收者
【发布时间】:2015-07-22 18:14:32
【问题描述】:

我正在寻找在分析 Java 字节码时识别方法调用的正确接收者的解决方案。即识别接收者是否来自于哪个类的字段成员或参数。

以下面的字节码为例,有两个字段成员:_caller1_caller2

public Class MyClass{
  test.code.jit.asm.classInline.CI_Caller1 _caller1;
    flags: 

  test.code.jit.asm.classInline.CI_Caller1 _caller2;
    flags: 

  public int test(java.lang.String, java.lang.String, test.code.jit.asm.classInline.CI_Caller1);
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=5, args_size=3
         0: aload_0       
         1: getfield      #14                 // Field _caller1:Ltest/code/jit/asm/classInline/CI_Caller1;
         4: invokevirtual #26                 // Method test/code/jit/asm/classInline/CI_Caller1.test_two_fields_callee:()I
         7: istore_3      
         8: aload_0       
         9: getfield      #16                 // Field _caller2:Ltest/code/jit/asm/classInline/CI_Caller1;
        12: invokevirtual #26                 // Method test/code/jit/asm/classInline/CI_Caller1.test_two_fields_callee:()I
        15: istore        4
        17: getstatic     #32                 // Field java/lang/System.out:Ljava/io/PrintStream;
        20: new           #38                 // class java/lang/StringBuilder
        23: dup           
         .....
        72: ireturn       

我想知道的是如何在 #4、#12 识别方法调用的正确接收者。接收者是类字段成员(哪一个)或方法参数?人眼阅读相对容易,但我如何通过 Java 代码实现它(如果已有工具更好)。

目前我正在使用 Java ASM 框架来解析类字节码序列。如果可以提供一些想法将不胜感激(看来我必须在这里构建字节码 AST),或者一些 Java util/相关链接也有帮助。

【问题讨论】:

    标签: compiler-construction bytecode abstract-syntax-tree java-bytecode-asm


    【解决方案1】:

    invokevirtual 指令被执行时,所有的参数都从堆栈中弹出,然后弹出接收器对象。因此,您的示例是最简单的示例:该方法没有要弹出的参数,因此在它提供接收器之前的指令,但即使对于无参数方法,它也是最简单的情况,因为理论上,可能存在在提供接收器的指令和调用之间的堆栈中性指令序列。此外,前面的字段读取是最简单的情况,因为幸运的是它前面有 aload_0 指令,该指令提供了正在读取其字段的实例。并且只要没有事先写入变量0,它仍然会包含this 实例,如果我们正在查看非static 方法...

    在命名所有幸运的巧合之后,应该提到的是,对于普通的 Java 代码和主流编译器,这些先决条件中的大部分都将成立,所以如果你能忍受覆盖,比如说 99% 的代码,最大的障碍是堆栈顶部的参数,可能由任意表达式产生,包括条件,因此接收器实例的提供者和实际调用之间的代码可能很长。

    追踪推送方法接收器的指令的唯一方法是向前扫描代码并将操作数堆栈建模为存储其源指令的对象堆栈,并解释所有指令对该操作数堆栈的影响。请注意,此类解释器的基础工作already exists

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 2021-08-14
      • 2015-05-03
      • 1970-01-01
      • 2014-07-27
      • 1970-01-01
      • 2013-01-22
      相关资源
      最近更新 更多