Инструкция JVM ALOAD_0 в «основном» методе указывает на «аргументы» вместо «это»?

Я пытаюсь реализовать подмножество Java для академического исследования. Ну, я на последних этапах (генерация кода) и написал довольно простую программу, чтобы посмотреть, как обрабатываются аргументы метода:

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

Затем я построил его и запустил «Main.class» через онлайн-дизассемблер, который нашел по адресу: http://www.cs.cornell.edu/People/egs/kimera/disassembler.html

Я получаю следующую реализацию для основного метода: (дизассемблированный вывод находится в 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

Моя проблема заключается в следующем:
1. Предполагается, что aload_0 поместит "это" в стек (именно это, по-видимому, говорится в спецификации JVM)
2. Предполагается, что arraylength возвращает длину массива, ссылка на который находится на вершине стека

Так что, по моему мнению, комбинация 1 и 2 даже не должна работать.

Как/почему это работает? Или дизассемблер глючит и реальный байткод какой-то другой?


person ArjunShankar    schedule 09.01.2011    source источник


Ответы (1)


aload_0 должен помещать это в стек

Не совсем… aload_0 считывает первый ссылочный аргумент (или, в более общем случае, первую локальную ссылочную переменную) метода и помещает его в стек.

В функциях-членах первой локальной переменной оказывается ссылка this.

Но main не является функцией-членом, это статическая функция, поэтому здесь нет аргумента this, а истинным первым аргументом метода является args.

person Konrad Rudolph    schedule 09.01.2011
comment
Верно ли это для всех статических методов? - person ankh-morpork; 11.07.2015
comment
@KonradRudolph - Не думайте, что приведенное выше утверждение верно. aload_0 читает экземпляр, для которого вызывается этот метод (т. е. переменная this), а aload_1 читает 1-й аргумент этого метода (из массива локальных переменных текущего кадра и помещается в стек операндов). Ссылка на документ JVM для SE8 (также раздел 2.6) [docs.oracle.com/javase/specs/jvms/se8/html/ - person KGhatak; 21.12.2016
comment
@BuckCherry А что происходит со статическими методами? Для уточнения см. первый комментарий Гринча. - person Konrad Rudolph; 21.12.2016
comment
@grinch - я уже не понял this.foo(x,y) is really Foo.foo(this, x, y). Вы говорите, что для статического метода aload_0 считывает текущий класс в стек!! - person KGhatak; 21.12.2016
comment
@KonradRudolph - Значение aload_‹n› именно в том, как говорится в документе JVM, чтобы загрузить типизированное значение ссылки из локального массива с индексом 'n' в стек операндов. Для статических методов аргументы сохраняются с индекса 0,1,.. в отличие от 1,2,.. для нестатического метода. В любом случае такие операторы, как aload_0 считывает 1-й аргумент или 'this', неверны без ссылки на статический или нестатический контекст. Фактически, для статического метода, если 1-й аргумент не имеет типа «ссылка», тогда для этого метода не будет aload_0. Кстати, было бы неплохо, если бы вы отразили это в своем ответе. - person KGhatak; 21.12.2016
comment
@BuckCherry Я сделал некоторые разъяснения. Но ваше беспокойство, похоже, не связано и в конечном итоге основано на неправильном прочтении документации: JVM не делает различий между this и другими аргументами и не имеет значения в своей обработке статических и нестатических методов (после вызова). - person Konrad Rudolph; 21.12.2016
comment
@KonradRudolph - концептуально JVM не нужно беспокоиться о том, чтобы знать, какой индекс что хранит. Тем не менее, JVM (SE8) требует поведения и w.r.t. статические и нестатические аспекты. Выдержки из гл. 2.6.1 спец. -"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)...." - person KGhatak; 21.12.2016
comment
@BuckCherry Я знаю, что говорится в документации. Это не подтверждает ваше утверждение. - person Konrad Rudolph; 21.12.2016
comment
@KonradRudolph - Не могли бы вы четко указать, какое утверждение вы имеете в виду! - person KGhatak; 21.12.2016
comment
Давайте продолжим обсуждение в чате. - person KGhatak; 21.12.2016
comment
@KGhatak Нет, я имел в виду, что вызов функции-члена, такой как this.foo(x,y), на самом деле просто обрабатывается как статическая функция, которая передает ссылку this в качестве параметра. Так получается Foo.foo(this, x, y) - person grinch; 28.12.2016
comment
@grinch Не уверен, что этот способ объяснения (преобразование между статическими и нестатическими методами) имеет какое-либо основание! Мне кажется не так! - person KGhatak; 02.01.2017
comment
@KGhatak Я просто говорю, что на уровне байт-кода код больше похож на набор вызовов статических методов с передаваемым параметром this. - person grinch; 03.01.2017
comment
@grinch - я не хочу останавливаться на этом так долго ... но даже на уровне байт-кода у нас есть определенное различие между статическим и нестатическим, например. getfield vs. getstatic, invokespecial vs. invokestatic — это инструкции JVM, которые различают статические и нестатические контексты. - person KGhatak; 04.01.2017
comment
@KGhatak да, я понимаю, что есть разница между статическим и нестатическим. Когда я сделал комментарий 5 лет назад, я просто указал, что вызов в java: this.foo(x,y) больше похож на этот в байтовом коде: Foo.foo(this, x, y). - person grinch; 04.01.2017