本文属于Java ASM系列二:OPCODE当中的一篇。
对于《Java ASM系列二:OPCODE》有配套的视频讲解,可以点击这里和这里进行查看;同时,也可以点击这里查看源码资料。
1. 概览
从Instruction的角度来说,与return相关的opcode有6个,内容如下:
opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol |
---|---|---|---|---|---|
172 | ireturn | 174 | freturn | 176 | areturn |
173 | lreturn | 175 | dreturn | 177 | return |
从ASM的角度来说,这些opcode是通过MethodVisitor.visitInsn(int opcode)
方法来调用的。
2. return void type
从Java语言的视角,有一个HelloWorld
类,代码如下:
public class HelloWorld {
public void test() {
// do nothing
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test();
Code:
0: return
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(0, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: return // {} | {}
从JVM规范的角度来看,Operand Stack的变化如下:
... →
[empty]
The current method must have return type void
.
- If no exception is thrown, any values on the operand stack of the current frame are discarded.
- The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.
3. return primitive type
3.1. ireturn
从Java语言的视角,有一个HelloWorld
类,代码如下:
public class HelloWorld {
public int test() {
return 0;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public int test();
Code:
0: iconst_0
1: ireturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(ICONST_0);
methodVisitor.visitInsn(IRETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: iconst_0 // {this} | {int}
0001: ireturn // {} | {}
从JVM规范的角度来看,Operand Stack的变化如下:
..., value →
[empty]
- The current method must have return type
boolean
,byte
,short
,char
, orint
. Thevalue
must be of typeint
. - If no exception is thrown,
value
is popped from the operand stack of the current frame and pushed onto the operand stack of the frame of the invoker. - Any other values on the operand stack of the current method are discarded.
- The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.
3.2. freturn
从Java语言的视角,有一个HelloWorld
类,代码如下:
public class HelloWorld {
public float test() {
return 0;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public float test();
Code:
0: fconst_0
1: freturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(FCONST_0);
methodVisitor.visitInsn(FRETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: fconst_0 // {this} | {float}
0001: freturn // {} | {}
从JVM规范的角度来看,Operand Stack的变化如下:
..., value →
[empty]
- The current method must have return type
float
. Thevalue
must be of typefloat
. - If no exception is thrown,
value
is popped from the operand stack of the current frame. The value is pushed onto the operand stack of the frame of the invoker. - Any other values on the operand stack of the current method are discarded.
- The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.
3.3. lreturn
这里需要注意的就是long
类型在local variable和operand stack当中占用2个slot的位置。
从Java语言的视角,有一个HelloWorld
类,代码如下:
public class HelloWorld {
public long test() {
return 0;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public long test();
Code:
0: lconst_0
1: lreturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(LCONST_0);
methodVisitor.visitInsn(LRETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: lconst_0 // {this} | {long, top}
0001: lreturn // {} | {}
从JVM规范的角度来看,Operand Stack的变化如下:
..., value →
[empty]
- The current method must have return type
long
. Thevalue
must be of typelong
. - If no exception is thrown,
value
is popped from the operand stack of the current frame and pushed onto the operand stack of the frame of the invoker. - Any other values on the operand stack of the current method are discarded.
- The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.
3.4. dreturn
从Java语言的视角,有一个HelloWorld
类,代码如下:
public class HelloWorld {
public double test() {
return 0;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public double test();
Code:
0: dconst_0
1: dreturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(DCONST_0);
methodVisitor.visitInsn(DRETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: dconst_0 // {this} | {double, top}
0001: dreturn // {} | {}
从JVM规范的角度来看,Operand Stack的变化如下:
..., value →
[empty]
- The current method must have return type
double
. Thevalue
must be of typedouble
. - If no exception is thrown,
value
is popped from the operand stack of the current frame. Thevalue
is pushed onto the operand stack of the frame of the invoker. - Any other values on the operand stack of the current method are discarded.
- The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.
4. return reference type
从Java语言的视角,有一个HelloWorld
类,代码如下:
public class HelloWorld {
public Object test() {
return null;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public java.lang.Object test();
Code:
0: aconst_null
1: areturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(ACONST_NULL);
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: aconst_null // {this} | {null}
0001: areturn // {} | {}
从JVM规范的角度来看,Operand Stack的变化如下:
..., objectref →
[empty]
- The
objectref
must be of typereference
and must refer to an object of a type that is assignment compatible with the type represented by the return descriptor of the current method. - If no exception is thrown,
objectref
is popped from the operand stack of the current frame and pushed onto the operand stack of the frame of the invoker. - Any other values on the operand stack of the current method are discarded.
- The interpreter then reinstates the frame of the invoker and returns control to the invoker.