JVM instruction ALOAD_0 in the 'main' method points to 'args' instead of 'this'?
Asked Answered
S

1

24

I am trying to implement a subset of Java for an academic study. Well, I'm in the last stages (code generation) and I wrote a rather simple program to see how method arguments are handled:

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

Then I built it, and ran 'Main.class' through an online disassembler I found at: http://www.cs.cornell.edu/People/egs/kimera/disassembler.html

I get the following implementation for the 'main' method: (the disassembled output is in 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

My problem with this is:
1. aload_0 is supposed to push 'this' on to the stack (thats what the JVM spec seems to say)
2. arraylength is supposed to return the length of the array whose reference is on the top-of-stack

So according to me the combination of 1 & 2 should not even work.

How/why is it working? Or is the disassembler buggy and the actual bytecode is something else?

Staten answered 9/1, 2011 at 19:59 Comment(0)
C
54

aload_0 is supposed to push 'this' on to the stack

Not quite … aload_0 reads the first reference argument (or, more generally, the first local reference variable) of the method and pushes it onto the stack.

In member functions, the first local variable happens to be the this reference.

But main is not a member function, it’s a static function so there is no this argument, and the true first argument of the method is args.

Coaptation answered 9/1, 2011 at 20:5 Comment(15)
Does this hold true for all static methods?Rania
@KonradRudolph - Don't think above statement is correct. aload_0 reads the instance on which this method is invoked (i.e. this variable) and aload_1 reads 1st argument to this method (from the local variable array of the current frame and pushed onto the operand stack). Ref JVM document for SE8 (also section 2.6) [docs.oracle.com/javase/specs/jvms/se8/html/…Enthymeme
@BuckCherry And what happens for static methods? For clarification, see the first comment, by "grinch".Coaptation
@grinch - I ready didn't get this.foo(x,y) is really Foo.foo(this, x, y). Are you saying for static method, aload_0 reads current-class onto stack!!Enthymeme
@KonradRudolph - The meaning of aload_<n> is precisely, as the JVM doc says, to load reference typed value from local-array at index 'n' onto operand stack. For static methods, arguments are stored from index 0,1,.. as opposed to from 1,2,.. for non-static method. Either way, statements like- aload_0 reads 1st arg or 'this' are incorrect without referring to the static or no-static context. In fact, for a static method if 1st argument is not of 'reference' type, then there would be no aload_0 for that method. Btw, it would be nice if you could reflect that in your answer.Enthymeme
@BuckCherry I’ve made some clarifications. But your concern seems to be unrelated, and ultimately based on a misreading of the documentation: the JVM makes no difference between this and other arguments, and it makes no difference in its treatment of static and non-static methods (after invocation).Coaptation
@KonradRudolph - Conceptually, a JVM doesn't need to bother about knowing which index stores what. However, JVM (SE8) does mandate the behavior and w.r.t. static and non-static aspects. Excerpts from sec. 2.6.1 of the spec. -"On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language)...."Enthymeme
@BuckCherry I know what the documentation says. It doesn’t support your claim.Coaptation
@KonradRudolph - Would you clearly state which claim you're referring to!Enthymeme
Let us continue this discussion in chat.Enthymeme
@Enthymeme No, what I meant is that a member function call like this.foo(x,y) is really just treated as a static function that passes the this reference as a parameter. So it turns into Foo.foo(this, x, y)Astigmatism
@Astigmatism Not sure if this way of explaining (conversion between static and non-static methods) has any basis! Seems to me not so right!Enthymeme
@Enthymeme I'm just saying that at the bytecode level the code is more like a bunch of static method calls with a this parameter being passed around.Astigmatism
@Astigmatism - I don't mean to dwell on this so long...but even at bytecode level we have certain differentiation between static and non-static e.g. getfield vs. getstatic, invokespecial vs. invokestatic are JVM instructions that do differentiate static and non-static contexts.Enthymeme
@Enthymeme yes I understand there are differences between static and non static. When I made the comment 5 years ago I was just pointing out that the call in java: this.foo(x,y) is more like this in byte code: Foo.foo(this, x, y).Astigmatism

© 2022 - 2024 — McMap. All rights reserved.