4

我想知道为什么 Java Bytecode 的行号不连续。

例如,在以下 getter 的(未列出的)第 2 行和第 3 行中会发生什么?

public java.lang.String getX();

Code:
0:   aload_0
1:   getfield        #2; //Field x:Ljava/lang/String;
4:   areturn

我正在使用 ASM 框架来处理字节码。当使用树 API 访问方法的代码时,我也会得到这些“隐藏”指令(但是使用操作码 -1)。我想知道它们是干什么用的。

4

2 回答 2

8

我不认为那0, 1, 4是行号,而是字节码中的字节偏移量。

  • aload_0是一个字节
  • getfield是三个字节(一个操作码,一个带有两个字节的“索引”参数)
  • areturn是一个字节

所以23只是getfield操作的一部分。

于 2013-04-16T16:46:46.140 回答
4

一点解释

局部变量数组的大小在编译时确定,取决于局部变量和形式方法参数的数量和大小。操作数堆栈是一个 LIFO 堆栈,用于推送和弹出值。它的大小也是在编译时确定的。某些操作码指令将值压入操作数堆栈;其他人从堆栈中获取操作数,操作它们,然后推送结果。操作数栈也用于接收方法的返回值。

public String getBar(){ 
    return bar; 
  }

  public java.lang.String getBar();
    Code:
      0:   aload_0
      1:   getfield        #2; //Field bar:Ljava/lang/String;
      4:   areturn

上述方法的字节码由三个操作码指令组成。第一个操作码 aload_0 将值从局部变量表的索引 0 压入操作数堆栈。this 引用始终存储在构造函数和实例方法的局部变量表的位置 0 处。下一个操作码指令 getfield 用于从对象中获取字段。最后一条指令 areturn 从方法返回一个引用。

每个方法都有一个对应的字节码数组。使用十六进制编辑器查看 .class 文件,您会在字节码数组中看到以下值:

也就是说,getBar 方法的字节码是 2A B4 00 02 B0。代码2A对应aload_0指令,B0对应areturn。该方法的字节码有 3 条指令,但字节数组包含 5 个元素,这可能看起来很奇怪。这是因为 getfield (B4) 需要提供 2 个参数 (00 02),并且这些参数在数组中占据位置 2 和 3,因此数组大小为 5,并且 areturn 指令移动到位置 4。

资源

Java 字节码指令列表

于 2013-04-16T16:53:39.037 回答