Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the following code translate to a new + dup op instructions in java bytecode?

Tags:

java

bytecode

Let's say I have a Fraction class:

class Fraction {
    ...

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

    ...
}

And this is what the bytecode of the above method turns out to be:

 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

I'm trying to understand why instruction at position 3 was put there in the first place. I'd say we'd only need to do the following to make it work:

 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

Why is not so?

like image 919
devoured elysium Avatar asked Dec 21 '11 18:12

devoured elysium


2 Answers

When the bytecode for the constructor starts, there is no Fraction object. The new instruction allocates a Fraction object (uninitialized) from the heap and leaves a reference to it on the stack. The dup instruction is so that one reference can be used to call <init> and the second used for the areturn at the end.

like image 148
Ted Hopp Avatar answered Nov 15 '22 18:11

Ted Hopp


Your bytecode is incorrect. Let's step through it:

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

Stack: Fraction instance (uninitialized, only a pointer to memory)

aload_0

Stack: Fraction (still uninitialized), this

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

Stack: Fraction (still uninitialized), this.den

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

Stack: Fraction (still uninitialized), this.den, this.num

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

Stack:

This is crucial. All invoke methods require the stack to contain this + all arguments. Both this and arguments are taken from the stack. After the invocation only a return value (if any) is placed on the stack. <init> has a void return type.

This means you will call:

areturn

On an empty stack, blowing out the JVM.

like image 22
Tomasz Nurkiewicz Avatar answered Nov 15 '22 18:11

Tomasz Nurkiewicz