临文乍了了,彻卷兀若无。这篇文章主要讲述Java ASM系列:(059)opcode: stack相关的知识,希望能为你提供帮助。
本文属于Java ASM系列二:OPCODE当中的一篇。
对于《java ASM系列二:OPCODE》有配套的视频讲解,可以点击这里和这里进行查看;同时,也可以点击这里查看源码资料。
1. 概览从Instruction的角度来说,与stack相关的opcode有9个,内容如下:
opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol |
---|---|---|---|---|---|
87 | pop | 90 | dup_x1 | 93 | dup2_x1 |
88 | pop2 | 91 | dup_x2 | 94 | dup2_x2 |
89 | dup | 92 | dup2 | 95 | swap |
MethodVisitor.visitXxxInsn()
方法对应关系如下:MethodVisitor.visitInsn()
:pop
,pop2
dup
,dup_x1
,dup_x2
dup2
,dup2_x1
,dup2_x2
swap
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public void test() {
Math.max(3, 4);
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test();
Code:
0: iconst_3
1: iconst_4
2: invokestatic#2// Method java/lang/Math.max:(II)I
5: pop
6: return
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(ICONST_3);
methodVisitor.visitInsn(ICONST_4);
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "max", "(II)I", false);
methodVisitor.visitInsn(POP);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: iconst_3// {this} | {int}
0001: iconst_4// {this} | {int, int}
0002: invokestatic#2// {this} | {int}
0005: pop// {this} | {}
0006: return// {} | {}
从JVM规范的角度来看,
pop
指令对应的Operand Stack的变化如下:..., value →...
Pop the top
value
from the operand stack. The pop
instruction must not be used unless value
is a value of a category 1 computational type.2.2. pop2
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public void test() {
Math.max(3L, 4L);
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test();
Code:
0: ldc2_w#2// long 3l
3: ldc2_w#4// long 4l
6: invokestatic#6// Method java/lang/Math.max:(JJ)J
9: pop2
10: return
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitLdcInsn(new Long(3L));
methodVisitor.visitLdcInsn(new Long(4L));
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "max", "(JJ)J", false);
methodVisitor.visitInsn(POP2);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(4, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: ldc2_w#2// {this} | {long, top}
0003: ldc2_w#4// {this} | {long, top, long, top}
0006: invokestatic#6// {this} | {long, top}
0009: pop2// {this} | {}
0010: return// {} | {}
从JVM规范的角度来看,
pop2
指令对应的Operand Stack的变化如下:Form 1:
..., value2, value1 →...
where each of
value1
and value2
is a value of a category 1 computational type.Form 2:
..., value →...
where
value
is a value of a category 2 computational type.3. dup 3.1. dup
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public void test() {
int a;
int b;
b = a = 2;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test();
Code:
0: iconst_2
1: dup
2: istore_1
3: istore_2
4: return
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(ICONST_2);
methodVisitor.visitInsn(DUP);
methodVisitor.visitVarInsn(ISTORE, 1);
methodVisitor.visitVarInsn(ISTORE, 2);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 3);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: iconst_2// {this} | {int}
0001: dup// {this} | {int, int}
0002: istore_1// {this, int} | {int}
0003: istore_2// {this, int, int} | {}
0004: return// {} | {}
从JVM规范的角度来看,
dup
指令对应的Operand Stack的变化如下:..., value →..., value, value
Duplicate the top value on the operand stack and push the duplicated value onto the operand stack.
The
dup
instruction must not be used unless value
is a value of a category 1 computational type.3.2. dup_x1
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
private int num = 0;
public static int test(HelloWorld instance, int val) {
return instance.num = val;
}
}
【Java ASM系列((059)opcode: stack)】从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
private int num;
...public static int test(sample.HelloWorld, int);
Code:
0: aload_0
1: iload_1
2: dup_x1
3: putfield#2// Field num:I
6: ireturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ILOAD, 1);
methodVisitor.visitInsn(DUP_X1);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/HelloWorld", "num", "I");
methodVisitor.visitInsn(IRETURN);
methodVisitor.visitMaxs(3, 2);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {HelloWorld, int} | {}
0000: aload_0// {HelloWorld, int} | {HelloWorld}
0001: iload_1// {HelloWorld, int} | {HelloWorld, int}
0002: dup_x1// {HelloWorld, int} | {int, HelloWorld, int}
0003: putfield#2// {HelloWorld, int} | {int}
0006: ireturn// {} | {}
从JVM规范的角度来看,
dup_x1
指令对应的Operand Stack的变化如下:..., value2, value1 →..., value1, value2, value1
Duplicate the top value on the operand stack and insert the duplicated
value
two values down in the operand stack.The
dup_x1
instruction must not be used unless both value1
and value2
are values of a category 1 computational type.3.3. dup_x2
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public static int test(int[] array, int i, int value) {
return array[i] = value;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public static int test(int[], int, int);
Code:
0: aload_0
1: iload_1
2: iload_2
3: dup_x2
4: iastore
5: ireturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ILOAD, 1);
methodVisitor.visitVarInsn(ILOAD, 2);
methodVisitor.visitInsn(DUP_X2);
methodVisitor.visitInsn(IASTORE);
methodVisitor.visitInsn(IRETURN);
methodVisitor.visitMaxs(4, 3);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {[I, int, int} | {}
0000: aload_0// {[I, int, int} | {[I}
0001: iload_1// {[I, int, int} | {[I, int}
0002: iload_2// {[I, int, int} | {[I, int, int}
0003: dup_x2// {[I, int, int} | {int, [I, int, int}
0004: iastore// {[I, int, int} | {int}
0005: ireturn// {} | {}
从JVM规范的角度来看,
dup_x2
指令对应的Operand Stack的变化如下:Form 1:
..., value3, value2, value1 →..., value1, value3, value2, value1
where
value1
, value2
, and value3
are all values of a category 1 computational type.Form 2:
..., value2, value1 →..., value1, value2, value1
where
value1
is a value of a category 1 computational type and value2
is a value of a category 2 computational type.4. dup2 4.1. dup2
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public void test() {
long a;
long b;
b = a = 2;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test();
Code:
0: ldc2_w#2// long 2l
3: dup2
4: lstore_1
5: lstore_3
6: return
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitLdcInsn(new Long(2L));
methodVisitor.visitInsn(DUP2);
methodVisitor.visitVarInsn(LSTORE, 1);
methodVisitor.visitVarInsn(LSTORE, 3);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(4, 5);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: ldc2_w#2// {this} | {long, top}
0003: dup2// {this} | {long, top, long, top}
0004: lstore_1// {this, long, top} | {long, top}
0005: lstore_3// {this, long, top, long, top} | {}
0006: return// {} | {}
从JVM规范的角度来看,
dup2
指令对应的Operand Stack的变化如下:Form 1:
..., value2, value1 →..., value2, value1, value2, value1
where both
value1
and value2
are values of a category 1 computational type.Form 2:
..., value →..., value, value
where
value
is a value of a category 2 computational type.4.1. dup2_x1
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
private long num = 0;
public static long test(HelloWorld instance, long val) {
return instance.num = val;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
private long num;
...public static long test(sample.HelloWorld, long);
Code:
0: aload_0
1: lload_1
2: dup2_x1
3: putfield#2// Field num:J
6: lreturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(LLOAD, 1);
methodVisitor.visitInsn(DUP2_X1);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/HelloWorld", "num", "J");
methodVisitor.visitInsn(LRETURN);
methodVisitor.visitMaxs(5, 3);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {HelloWorld, long, top} | {}
0000: aload_0// {HelloWorld, long, top} | {HelloWorld}
0001: lload_1// {HelloWorld, long, top} | {HelloWorld, long, top}
0002: dup2_x1// {HelloWorld, long, top} | {long, top, HelloWorld, long, top}
0003: putfield#2// {HelloWorld, long, top} | {long, top}
0006: lreturn// {} | {}
从JVM规范的角度来看,
dup2_x1
指令对应的Operand Stack的变化如下:Form 1:
..., value3, value2, value1 →..., value2, value1, value3, value2, value1
where
value1
, value2
, and value3
are all values of a category 1 computational type.Form 2:
..., value2, value1 →..., value1, value2, value1
where
value1
is a value of a category 2 computational type and value2
is a value of a category 1 computational type.4.2. dup2_x2
从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public static long test(long[] array, int i, long value) {
return array[i] = value;
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public static long test(long[], int, long);
Code:
0: aload_0
1: iload_1
2: lload_2
3: dup2_x2
4: lastore
5: lreturn
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ILOAD, 1);
methodVisitor.visitVarInsn(LLOAD, 2);
methodVisitor.visitInsn(DUP2_X2);
methodVisitor.visitInsn(LASTORE);
methodVisitor.visitInsn(LRETURN);
methodVisitor.visitMaxs(6, 4);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {[J, int, long, top} | {}
0000: aload_0// {[J, int, long, top} | {[J}
0001: iload_1// {[J, int, long, top} | {[J, int}
0002: lload_2// {[J, int, long, top} | {[J, int, long, top}
0003: dup2_x2// {[J, int, long, top} | {long, top, [J, int, long, top}
0004: lastore// {[J, int, long, top} | {long, top}
0005: lreturn// {} | {}
从JVM规范的角度来看,
dup2_x2
指令对应的Operand Stack的变化如下:Form 1:
..., value4, value3, value2, value1 →..., value2, value1, value4, value3, value2, value1
where
value1
, value2
, value3
, and value4
are all values of a category 1 computational type.Form 2:
..., value3, value2, value1 →..., value1, value3, value2, value1
where
value1
is a value of a category 2 computational type and value2
and value3
are both values of a category 1 computational type.Form 3:
..., value3, value2, value1 →..., value2, value1, value3, value2, value1
where
value1
and value2
are both values of a category 1 computational type and value3
is a value of a category 2 computational type.Form 4:
..., value2, value1 →..., value1, value2, value1
where
value1
and value2
are both values of a category 2 computational type.5. swap从Java语言的视角,有一个
HelloWorld
类,代码如下:public class HelloWorld {
public void test() {
System.out.println("Hello ASM");
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test();
Code:
0: getstatic#2// Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc#3// String Hello ASM
5: invokevirtual #4// Method java/io/PrintStream.println:(Ljava/lang/String;
)V
8: return
}
从ASM的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;
");
methodVisitor.visitLdcInsn("Hello ASM");
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;
)V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: getstatic#2// {this} | {PrintStream}
0003: ldc#3// {this} | {PrintStream, String}
0005: invokevirtual#4// {this} | {}
0008: return// {} | {}
为了使用
swap
指令,我们编写如下ASM代码:import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;
public class HelloWorldGenerateCore {
public static void main(String[] args) throws Exception {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
// (1) 生成byte[]内容
byte[] bytes = dump();
// (2) 保存byte[]到文件
FileUtils.writeBytes(filepath, bytes);
}public static byte[] dump() throws Exception {
// (1) 创建ClassWriter对象
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// (2) 调用visitXxx()方法
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld",
null, "java/lang/Object", null);
{
MethodVisitor mv1 = cw.visitMethod(ACC_PUBLIC, "<
init>
", "()V", null, null);
mv1.visitCode();
mv1.visitVarInsn(ALOAD, 0);
mv1.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<
init>
", "()V", false);
mv1.visitInsn(RETURN);
mv1.visitMaxs(1, 1);
mv1.visitEnd();
}{
MethodVisitor mv2 = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null);
mv2.visitCode();
mv2.visitLdcInsn("Hello ASM");
mv2.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;
");
mv2.visitInsn(SWAP);
mv2.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;
)V", false);
mv2.visitInsn(RETURN);
mv2.visitMaxs(2, 1);
mv2.visitEnd();
}
cw.visitEnd();
// (3) 调用toByteArray()方法
return cw.toByteArray();
}
}
从Instruction的视角来看,方法体对应的内容如下:
$ javap -c -p sample.HelloWorld
public class sample.HelloWorld {
...
public void test();
Code:
0: ldc#11// String Hello ASM
2: getstatic#17// Field java/lang/System.out:Ljava/io/PrintStream;
5: swap
6: invokevirtual #23// Method java/io/PrintStream.println:(Ljava/lang/String;
)V
9: return
}
从Frame的视角来看,local variable和operand stack的变化:
// {this} | {}
0000: ldc#11// {this} | {String}
0002: getstatic#17// {this} | {String, PrintStream}
0005: swap// {this} | {PrintStream, String}
0006: invokevirtual#23// {this} | {}
0009: return// {} | {}
从JVM规范的角度来看,
swap
指令对应的Operand Stack的变化如下:..., value2, value1 →..., value1, value2
Swap the top two values on the operand stack.
The
swap
instruction must not be used unless value1
and value2
are both values of a category 1 computational type.推荐阅读
- web前端性能优化——图片加载的优化
- Windows 巡检脚本
- 面试中的老大难-mysql事务和锁,一次性讲清楚!
- 实践400+私有云打造的云安全高可用架构详解
- 图数据库在百度汉语中的应用
- HarmonyOS基础技术赋能之分布式数据服务功能
- Python实现发送邮件(实现单发/群发邮件验证码)
- ansible+python+shell 实现SpringCloud微服务治理
- SpringBoot任意位置获取HttpServletRequest对象