Почему следующий код транслируется в новые инструкции + dup op в байт-коде Java? - PullRequest
8 голосов
/ 21 декабря 2011

Допустим, у меня есть класс Fraction:

class Fraction {
    ...

    /** Invert current fraction */
    public Fraction inverse() {
        return new Fraction(den,num);
    }

    ...
}

И вот как получается, что байт-код описанного выше метода:

 0 new #1 <xyzTestes/system/fraction/Fraction>
 3 dup
 4 aload_0
 5 getfield #16 <xyzTestes/system/fraction/Fraction.den>
 8 aload_0
 9 getfield #14 <xyzTestes/system/fraction/Fraction.num>
12 invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>>
15 areturn

Я пытаюсьчтобы понять, почему инструкция в позиции 3 была поставлена ​​там в первую очередь.Я бы сказал, что нам нужно всего лишь сделать следующее, чтобы это заработало:

 new #1 <xyzTestes/system/fraction/Fraction>
 aload_0
 getfield #16 <xyzTestes/system/fraction/Fraction.den>
 aload_0
 getfield #14 <xyzTestes/system/fraction/Fraction.num>
 invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>>
 areturn

Почему это не так?

Ответы [ 2 ]

10 голосов
/ 21 декабря 2011

Когда запускается байт-код для конструктора, объект Fraction отсутствует.Инструкция new выделяет объект Fraction (неинициализированный) из кучи и оставляет ссылку на него в стеке.Инструкция dup такова, что одна ссылка может использоваться для вызова <init>, а вторая используется для areturn в конце.

8 голосов
/ 21 декабря 2011

Ваш байт-код неверен. Давайте пройдем через это:

new #1 <xyzTestes/system/fraction/Fraction>

Стек : Fraction экземпляр (не инициализирован, только указатель на память)

aload_0

Стек : Fraction (еще не инициализирован), this

getfield #16 <xyzTestes/system/fraction/Fraction.den>

Стек : Fraction (еще не инициализирован), this.den

aload_0
getfield #14 <xyzTestes/system/fraction/Fraction.num>

Стек : Fraction (еще не инициализирован), this.den, this.num

invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>>

Stack

Это очень важно. Все invoke методы требуют, чтобы в стеке содержалось this + все аргументы. И this, и аргументы берутся из стека. После вызова в стек помещается только возвращаемое значение (если оно есть). <init> имеет тип возврата void.

Это означает, что вы позвоните:

areturn

В пустой пачке выдувается JVM.

...