java栈映射表(StackMapTable)
源码
public String hello(String content) throws RemoteException {
int i= 10;
if (i==10) {
System.out.println("10");
}else {
System.out.println(i);
}
if(content == null) {
return "null is not allowed";
}
if (content.equals("hello")) {
return "how are you?";
}
if (content.equals("bye")) {
return "bye bye!";
}
return "This is your input :"+content;
}
反编译
javap -c -v -cp bin .\bin\com\ymx\rmi\service\TestServiceImpl.class
部分结果如下:
public java.lang.String hello(java.lang.String) throws java.rmi.RemoteException;
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: bipush 10
2: istore_2
3: iload_2
4: bipush 10
6: if_icmpne 20
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: ldc #3 // String 10
14: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: goto 27
20: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
23: iload_2
24: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
27: aload_1
28: ifnonnull 34
31: ldc #6 // String null is not allowed
33: areturn
34: aload_1
35: ldc #7 // String hello
37: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
40: ifeq 46
43: ldc #9 // String how are you?
45: areturn
46: aload_1
47: ldc #10 // String bye
49: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
52: ifeq 58
55: ldc #11 // String bye bye!
57: areturn
58: new #12 // class java/lang/StringBuilder
61: dup
62: invokespecial #13 // Method java/lang/StringBuilder."<init>":()V
65: ldc #14 // String This is your input :
67: invokevirtual #15 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
70: aload_1
71: invokevirtual #15 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
74: invokevirtual #16 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
77: areturn
LineNumberTable:
line 24: 0
line 25: 3
line 26: 9
line 28: 20
line 30: 27
line 31: 31
line 33: 34
line 34: 43
line 36: 46
line 37: 55
line 39: 58
StackMapTable: number_of_entries = 5
frame_type = 252 /* append */
offset_delta = 20
locals = [ int ]
frame_type = 6 /* same */
frame_type = 6 /* same */
frame_type = 11 /* same */
frame_type = 11 /* same */
Exceptions:
throws java.rmi.RemoteException
其中StackMapTable即为栈映射表。
意义
- 仅用于有跳转的字节指令中,如goto、ifeq、if_icmpne、ifnonnull等
- 跳转语句有块的概念。块的起点是跳转字节指令的目的地址,如第6条:
指令:6: if_icmpne 20
意义是,如果整数比较不相等,则跳转到第20条指令。20条为:
指令:20: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
所以,第一个frame_type的offset_delta是20,代表第一个块偏移量是20。
第二个frame_type是6,代表第二块偏移量是6。
以此类推,第三块偏移量6,第四块偏移量是11,第五块偏移量是11。 - 说明
每个基本块是以栈映射帧的形式存在的。字节码偏移量,和栈映射帧的偏移量不是一样的,字节码偏移量+1=帧偏移量。
第一个的frame_type是根据类的签名算出来的,如果frame_type和offset_delta一样,则不显示offset_delta
因为可以计算出:
第一块的字节码偏移量20,StackMapFrame偏移量21,结束是21+6-1=26。
第二块的字节码偏移量21+6=27,StackMapFrame偏移量6,结束是27+6=33。
第三块的字节码偏移量33+1=34,StackMapFrame偏移量11,结束是34+11=45。
第四块的字节码偏移量45+1=46,StackMapFrame偏移量11,结束是46+11=57。
第五块的字节码偏移量57+1=58。 - 图示
0 20 27 34 46 58
|------20------|------6------|------6------|------11------| ------11------|------------|