'main'方法中的JVM指令ALOAD_0指向'args'而不是'this'?

Arj*_*kar 21 java jvm bytecode instructions jasmin

我正在尝试为学术研究实现Java的一个子集.好吧,我处于最后阶段(代码生成),我编写了一个相当简单的程序来查看如何处理方法参数:

class Main {
    public static void main(String[] args) {
        System.out.println(args.length);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我构建了它,并通过我在以下网址找到的在线反汇编程序运行'Main.class':http: //www.cs.cornell.edu/People/egs/kimera/disassembler.html

我得到了'main'方法的以下实现:(反汇编输出在Jasmin中)

.method public static main([Ljava/lang/String;)V
    .limit locals 1
    .limit stack 2

    getstatic   java/lang/System/out Ljava/io/PrintStream;
    aload_0
    arraylength
    invokevirtual   java/io/PrintStream.println(I)V
    return
.end method
Run Code Online (Sandbox Code Playgroud)

我的问题是:
1.aload_0应该将'this'推送到堆栈(这就是JVM规范似乎说的)
2.arraylength应该返回引用位于堆栈顶部的数组的长度

所以根据我的说法,1和2的组合甚至不应该起作用.

它是如何/为什么有效?或者是反汇编工具,实际的字节码是别的吗?

Kon*_*lph 46

aload_0应该将'this'推送到堆栈

不完全... aload_0读取方法的第一个引用参数(或更一般地说,第一个本地引用变量)并将其推送到堆栈.

在成员函数中,第一个局部变量恰好是this引用.

但是main不是成员函数,它是一个静态函数,因此没有this参数,并且该方法的真正的第一个参数是args.

  • +1.this.foo(x,y)真的是Foo.foo(this,x,y) (14认同)
  • 这适用于*all*静态方法吗? (3认同)
  • @ dohaqatar7是的. (2认同)
  • @KonradRudolph - 从概念上讲,JVM 不需要费心去了解哪个索引存储什么。然而,JVM (SE8) 确实强制要求行为以及静态和非静态方面。摘自第二节。规范 2.6.1 -*`“在类方法调用中,任何参数都从局部变量 0 开始传递到连续的局部变量中。在实例方法调用中,局部变量 0 始终用于传递对正在调用实例方法的对象的引用(这是 Java 编程语言中的)..."`* (2认同)