- load 读取数据到操作栈
- add 相加 出栈比较的2个元素,入栈结果
- store 存储到变量表
const_ 读取数据
return 返回
bipush x 将x压栈
sub 减法 出栈比较的2个元素,入栈结果
mul 乘法 出栈比较的2个元素,入栈结果
i2f int转float 出栈栈顶,入栈结果
getstatic 获取静态值
putstatic 设置静态
ldc 将字符串推至栈顶
putfield 赋值 栈顶元素出栈的数据保存到再次出栈的栈顶元素中 (2次出栈)
getfield 获取栈顶元素的变量,然后将栈顶元素出栈,新的元素变量入栈 (1次出栈,1次入栈)
_new 分配空间,地址压栈
dup 复制栈顶元素,再次入栈,此时栈顶中有2个重复元素
invokespecial 需要弹出dup复制的栈顶元素
ifnonnull l0 不为空,跳转到l0
_goto l1 跳转到l1
比较 出栈比较的2个元素
- if_icmpne 不等于
- if_icmple 小于
- if_icmplt 小于等于
- if_icmpge 大于
- if_icmpgt 大于等于
- if_icmpeq 等于
iinc
- iinc 2,100 位置2slot的值加100
- iinc 2,-100
int 入栈
- 当 int 取值 -1~5 时,JVM 采用 iconst 指令将常量压入栈中。
- 当 int 取值 -128~127 时,JVM 采用 bipush 指令将常量压入栈中。
- 当 int 取值 -32768~32767 时,JVM 采用 sipush 指令将常量压入栈中。
- 当 int 取值 -2147483648~2147483647 时,JVM 采用 ldc 指令将常量压入栈中。
重点:区分哪些指令是入栈,哪些指令是出栈
分析
构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43// 源码
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void doAction() {
}
}
// groovified (字节码)
public class org/example/Person {
// access flags 0x1
public Ljava/lang/String; name
// access flags 0x1
public I age
@groovyx.ast.bytecode.Bytecode
public void <init>(String a,int b) {
aload 0 // 入栈 this
invokespecial 'java/lang/Object.<init>','()V' // 调用this的父类init并出栈
aload 0 //入栈 this
aload 1 // 入栈 a
putfield 'org/example/Person.name','Ljava/lang/String;' // 出栈this和a,将a赋值给this.name
aload 0 //入栈 this
iload 2 // 入栈 b
putfield 'org/example/Person.age','I' // 出栈this和b //将b赋值给this.age
return
}
@groovyx.ast.bytecode.Bytecode
public void doAction() {
return
}
}new
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 源码
public void method(Person person) {
new Person("songpengfei", 30);
}
// groovified
@groovyx.ast.bytecode.Bytecode
public void method(org.example.Person a) {
_new 'org/example/Person' // 初始化Person,并入栈
dup // 复制栈顶Person并入栈
ldc "songpengfei" // 入栈 字符串
bipush 30 // 入栈 30
invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V' //出战 Person,字符串,30,并执行Person构造方法
pop // invokespecial出栈了1次Person,还剩余1个Person,pop出栈Person
return
}
1 | //源码 |
invokevirtual 如果有返回值,返回值会入栈,如果没有返回值不会入栈
try-finally
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35public void method(Person person) {
try {
Person songpengfei = new Person("songpengfei", 30);
songpengfei.doAction();
} finally {
int a = 100;
}
}
public void method(org.example.Person a) {
trycatchblock l0,l1,l2,null
l0
_new 'org/example/Person'
dup
ldc "songpengfei"
bipush 30
invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
astore 2
aload 2
invokevirtual 'org/example/Person.doAction','()V'
l1
bipush 100
istore 2
_goto l3
l2 // 异常情况
astore 3 // 将异常出栈,存入slot 3
bipush 100 // 入栈 100
istore 4 // 出栈存到 slot 4
aload 3 // 入栈异常
athrow //抛出异常
l3
return
}try-catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30public void method(Person person) {
try {
Person songpengfei = new Person("songpengfei", 30);
songpengfei.doAction();
} catch (Exception e) {
int c = 20;
}
}
public void method(org.example.Person a) {
trycatchblock l0,l1,l2,'java/lang/Exception'
l0
_new 'org/example/Person'
dup
ldc "songpengfei"
bipush 30
invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
astore 2
aload 2
invokevirtual 'org/example/Person.doAction','()V'
l1
_goto l3
l2
astore 2
bipush 20
istore 3
l3
return
}try-catch-finally
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56//源码
public void method(Person person) {
try {
Person songpengfei = new Person("songpengfei", 30);
songpengfei.doAction();
} catch (Exception e) {
int c = 100;
} finally {
int a = 20;
}
}
// groovified
public void method(org.example.Person a) {
trycatchblock l0,l1,l2,'java/lang/Exception'
trycatchblock l0,l1,l3,null
trycatchblock l2,l4,l3,null
trycatchblock l3,l5,l3,null
l0 // try 块
_new 'org/example/Person'
dup
ldc "songpengfei"
bipush 30
invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
astore 2
aload 2
invokevirtual 'org/example/Person.doAction','()V'
l1 //finally块
bipush 20
istore 2
_goto l6
l2 // catch块
astore 2
bipush 100
istore 3
l4 // finally块
bipush 20
istore 2
_goto l6
l3
astore 4
l5 // finally块 athrow
bipush 20
istore 5
aload 4
athrow
l6
return
}
}synchronized
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74// 源码
public class Main {
private final Object lock = new Object();
public static void main(String[] args) {
}
public void method(Person person) {
synchronized (lock) {
Person songpengfei = new Person("songpengfei", 30);
songpengfei.doAction();
}
}
}
// groovified
// class version 52.0 (52)
// access flags 0x21
public class org/example/Main {
// access flags 0x12
private final Ljava/lang/Object; lock
@groovyx.ast.bytecode.Bytecode
public void <init>() {
aload 0 // this 入栈
invokespecial 'java/lang/Object.<init>','()V' // this出栈,并执行Object构造
aload 0 // this入栈
_new 'java/lang/Object' //执行lock对象的new 入栈
dup // 执行赋值lock对象入栈
invokespecial 'java/lang/Object.<init>','()V' // lock对象出栈,执行Object构造
putfield 'org/example/Main.lock','Ljava/lang/Object;' // 出栈this和lock,将lock赋值
return
}
@groovyx.ast.bytecode.Bytecode
public static void main(String[] a) {
return
}
@groovyx.ast.bytecode.Bytecode
public void method(org.example.Person a) {
trycatchblock l0,l1,l2,null
trycatchblock l2,l3,l2,null
aload 0 // this入栈
getfield 'org/example/Main.lock','Ljava/lang/Object;' // 出栈this,入栈lock
dup // 复制lock入栈
astore 2 // 将lock存入到slot 2
monitorenter // lock监控并出栈
l0
_new 'org/example/Person' //创建Person,并入栈
dup // 复制Person 并入栈
ldc "songpengfei" // 入栈字符串
bipush 30 // 入栈整数30
invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V' // 出栈Person,字符串,30,并调用构造方法
astore 3 //存储 Person并出栈
aload 3 // 入栈 Person
invokevirtual 'org/example/Person.doAction','()V' // 执行
aload 2 // 入栈lock
monitorexit // 出栈lock 退出监控
l1 // finally
_goto l4
l2 //
astore 4 // catch情况
aload 2
monitorexit
l3
aload 4
athrow
l4
return
}
}匿名内部类 (解析)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// 源码
public void method(final int a) {
final int c = 30;
Request request = new Request();
request.request(new Request.Callback() {
@Override
public void callback() {
int b = a + c; // 反编译之后c直接copy为30;
int d = b + 1;
}
});
}
// access flags 0x0
INNERCLASS org/example/Main$1 null null
// access flags 0x609
public static abstract INNERCLASS org/example/Request$Callback org/example/Request Callback
// groovified
public void method(int a) {
bipush 30
istore 2
_new 'org/example/Request'
dup
invokespecial 'org/example/Request.<init>','()V'
astore 3
aload 3
_new 'org/example/Main$1'
dup
aload 0
iload 1
invokespecial 'org/example/Main$1.<init>','(Lorg/example/Main;I)V'
invokevirtual 'org/example/Request.request','(Lorg/example/Request$Callback;)V'
return
}内部类Callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55{
final int val$a;
descriptor: I
flags: ACC_FINAL, ACC_SYNTHETIC
final org.example.Main this$0;
descriptor: Lorg/example/Main;
flags: ACC_FINAL, ACC_SYNTHETIC
org.example.Main$1(org.example.Main, int);
descriptor: (Lorg/example/Main;I)V
flags:
Code:
stack=2, locals=3, args_size=3
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Lorg/example/Main;
5: aload_0
6: iload_2
7: putfield #2 // Field val$a:I
10: aload_0
11: invokespecial #3 // Method java/lang/Object."<init>":()V
14: return
LineNumberTable:
line 15: 0
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lorg/example/Main$1;
0 15 1 this$0 Lorg/example/Main;
public void callback();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: getfield #2 // Field val$a:I
4: bipush 30
6: iadd
7: istore_1
8: iload_1
9: iconst_1
10: iadd
11: istore_2
12: return
LineNumberTable:
line 18: 0
line 19: 8
line 20: 12
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 this Lorg/example/Main$1;
8 5 1 b I
12 1 2 d I
}
解析内部类需要使用反斜杠
1 | javap -v org/example/Main\$1.class |
性能问题
static
1
2
3
4
5
6
7// 1
public static final int A = 5;
// 2
public static final int A;
static {
A = 5;
}上面两种静态变量的定义方式,1的性能要高于2
a+=100 和 a=a+100
1
2
3
4
5
6
7// a+=100
iinc 2,100
// a=a+100
iload 2
bipush 100
iadd
istore 2