JVM | 字節碼指令基礎
操作數棧管理指令
1)pop、pop2:將操作數棧的棧頂一個或兩個元素出棧。
2)dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2:復制棧頂一個或兩個數值並將復制值或雙份的復制值重新壓入棧頂。
3)swap:將棧最頂端兩個數值互換。
public static void main(String[] args) {
heavyMethod();
}
對應的字節碼:
public static void main(java.lang.String[]); Signature: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=1, args_size=1 0: invokestatic #23 // Method heavyMethod:()I 3: pop 4: return LineNumberTable: line 115: 0 line 116: 4
-
加載、存儲指令
1)iload、iload<n>、lload、lload<n>、fload、fload<n>、dload、dload<n>、aload、aload<n>:將一個局部變量加載到操作數棧。
2)istore、istore<n>、lstore、lstore<n>、fstore、fstore<n>、dstore、dstore<n>、astore、astore<n>:將一個數值從操作數棧存儲到局部變量表。
3)bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconstm1、iconst<i>、lconst<l>、fconst<f>、dconst_<d>:將一個常量加載到操作數棧。
4)wide:擴充局部變量表的訪問索引的指令。
public static int methodE(){
int e = 100;
int c = 300;
int d = 300000;
e++;
++e;
--e;
e--;
return c + d + e;
}
對應的字節碼:
public static int methodE(); Signature: ()I flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=0 0: bipush 100 2: istore_0 3: sipush 300 6: istore_1 7: ldc #5 // int 300000 9: istore_2 10: iinc 0, 1 13: iinc 0, 1 16: iinc 0, -1 19: iinc 0, -1 22: iload_1 23: iload_2 24: iadd 25: iload_0 26: iadd 27: ireturn LineNumberTable: line 40: 0 line 41: 3 line 42: 7 line 43: 10 line 44: 13 line 45: 16 line 46: 19 line 47: 22
-
運算指令
1)iadd、ladd、fadd、dadd:加法指令。
2)isub、lsub、fsub、dsub:減法指令。
3)imul、lmul、fmul、dmul:乘法指令。
4)idiv、ldiv、fdiv、ddiv:除法指令。
5)irem、lrem、frem、drem:求余指令。
6)ineg、lneg、fneg、dneg:取反指令。
7)ishl、ishr、iushr、lshl、lshr、lushr:位移指令。
8)ior、lor:按位或指令。
9)iand、land:按位與指令。
10)ixor、lxor:按位異或指令。
11)iinc:局部變量自增指令。
12)dcmpg、dcmpl、fcmpg、fcmpl、lcmp:比較指令。
參照上例。
-
類型轉換指令
1)int類型到long、float或者double類型,long類型到float、double類型,float類型到double類型:寬化類型轉換(虛擬機直接支持)。
2)i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l、d2f:窄化類型轉換(顯式指令)。
public static void methodK(){
int i = 97;
short i2s = (short) i;
char i2c = (char) i;
long i2l = i;
float i2f = i;
double i2d = i;
float l2f = i2l;
double l2d = i2l;
}
對應的字節碼:
public static void methodK();
Signature: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=11, args_size=0
0: bipush 97
2: istore_0
3: iload_0
4: i2s
5: istore_1
6: iload_0
7: i2c
8: istore_2
9: iload_0
10: i2l
11: lstore_3
12: iload_0
13: i2f
14: fstore 5
16: iload_0
17: i2d
18: dstore 6
20: lload_3
21: l2f
22: fstore 8
24: lload_3
25: l2d
26: dstore 9
28: return
LineNumberTable:
line 100: 0
line 101: 3
line 102: 6
line 103: 9
line 104: 12
line 105: 16
line 106: 20
line 107: 24
line 108: 28
-
對象創建與訪問指令
1)new :創建類實例的指令。
2)newarray、anewarray、multianewarray:創建數組的指令。
3)getstatic、putstatic、getfield、putfield:訪問類字段(類變量)和實例字段(實例變量)的指令。
4)baload、caload、saload、iaload、laload、faload、daload、aaload:把一個數組元素加載到操作數棧的指令。
5)bastore、castore、sastore、iastore、lastore、fastore、dastore、aastore:把一個操作數棧的值存儲到數組元素中的指令。
6)arraylength:取數組長度的指令。
7)instanceof、checkcast:檢查類實例類型的指令。
public static void methodJ(){
new SimpleMethodExecuteProcess();
System.out.println(SimpleMethodExecuteProcess.i);
}
對應的字節碼:
public static void methodJ();
Signature: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: new #9 // class edu/atlas/demo/java/jvm/SimpleMethodExecuteProcess
3: dup
4: invokespecial #10 // Method "<init>":()V
7: pop
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: getstatic #11 // Field i:I
14: invokevirtual #12 // Method java/io/PrintStream.println:(I)V
17: return
LineNumberTable:
line 91: 0
line 93: 8
line 94: 17
-
控制轉移指令
1)ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne:條件分支。
2)tableswitch、lookupswitch:復合條件分支。
3)goto、goto_w、jsr、jsr_w、ret:無條件分支。
public static void methodG(){
if(i == 0){
System.out.println(System.currentTimeMillis());
}
while(i < 1){
System.out.println(System.currentTimeMillis());
i++;
}
}
對應的字節碼:
public static void methodG();
Signature: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: getstatic #6 // Field i:I
3: ifne 15
6: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
9: invokestatic #7 // Method java/lang/System.currentTimeMillis:()J
12: invokevirtual #8 // Method java/io/PrintStream.println:(J)V
15: getstatic #6 // Field i:I
18: iconst_1
19: if_icmpge 42
22: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
25: invokestatic #7 // Method java/lang/System.currentTimeMillis:()J
28: invokevirtual #8 // Method java/io/PrintStream.println:(J)V
31: getstatic #6 // Field i:I
34: iconst_1
35: iadd
36: putstatic #6 // Field i:I
39: goto 15
42: return
LineNumberTable:
line 62: 0
line 63: 6
line 66: 15
line 67: 22
line 68: 31
line 70: 42
StackMapTable: number_of_entries = 2
frame_type = 15 /* same */
frame_type = 26 /* same */
-
異常處理指令
athrow :顯式拋出異常指令。
public static void methodH(){
try {
throw new NullPointerException("nothing ...");
// do nothing ...
} catch (Throwable t){
// do nothing ...
}
}
對應的字節碼:
public static void methodH();
Signature: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=0
0: new #9 // class java/lang/NullPointerException
3: dup
4: ldc #10 // String nothing ...
6: invokespecial #11 // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
9: athrow
10: astore_0
11: return
Exception table:
from to target type
0 10 10 Class java/lang/Throwable
LineNumberTable:
line 77: 0
line 79: 10
line 82: 11
StackMapTable: number_of_entries = 1
frame_type = 74 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
-
同步指令
monitorenter、monitorexit:支持synchronized語句塊語義的指令。
public void methodI(){
synchronized (Integer.class){
// do nothing ...
}
}
對應的字節碼:
public void methodI();
Signature: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: ldc_w #13 // class java/lang/Integer
3: dup
4: astore_1
5: monitorenter
6: aload_1
7: monitorexit
8: goto 16
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow
16: return
Exception table:
from to target type
6 8 11 any
11 14 11 any
LineNumberTable:
line 88: 0
line 90: 6
line 91: 16
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 11
locals = [ class edu/atlas/demo/java/jvm/SimpleMethodExecuteProcess, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
- synchronized 修飾方法的語義解析:可以直接從方法常量池的方法表結構中ACC_SYNCHRONIZED訪問標誌得知一個方法是否聲明為同步方法,不需要解析出monitorenter、monitorexit同步指令。
public static synchronized void methodL(){
int i = 97;
}
public static synchronized void methodL();
Signature: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=1, locals=1, args_size=0
0: bipush 97
2: istore_0
3: return
LineNumberTable:
line 120: 0
line 121: 3
-
方法調用和返回指令
1)invokestatic:調用靜態方法。
2)invokespecial:調用實例構造器<init>方法、私有方法和父類方法。
3)invokevirtual:調用所有的虛方法。非虛方法以外的都是虛方法,非虛方法包括使用invokestatic、invokespecial調用的方法和被final修飾的方法。
4)invokeinterface:調用接口方法,運行時再確定一個實現此接口的對象。
5)invokedynamic:用於在運行時動態解析出調用點限定符所引用的方法,並執行該方法。
ireturn(返回值是boolean、byte、char、short、int)、lreturn、freturn、dreturn、areturn:方法返回指令。
public static int heavyMethod(){
int a = 200;
int b = 100;
int c = methodC(methodA(methodA(a, b), b), methodB(a, b));
methodD();
methodE();
methodF();
methodG();
methodH();
new SimpleMethodExecuteProcess().methodI();
methodJ();
methodK();
methodL();
return c;
}
對應的字節碼:
public static int heavyMethod();
Signature: ()I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=0
0: sipush 200
3: istore_0
4: bipush 100
6: istore_1
7: iload_0
8: iload_1
9: invokestatic #17 // Method methodA:(II)I
12: iload_1
13: invokestatic #17 // Method methodA:(II)I
16: iload_0
17: iload_1
18: invokestatic #18 // Method methodB:(II)I
21: invokestatic #19 // Method methodC:(II)I
24: istore_2
25: invokestatic #20 // Method methodD:()V
28: invokestatic #21 // Method methodE:()I
31: pop
32: invokestatic #22 // Method methodF:()D
35: pop2
36: invokestatic #23 // Method methodG:()V
39: invokestatic #24 // Method methodH:()V
42: new #14 // class edu/atlas/demo/java/jvm/SimpleMethodExecuteProcess
45: dup
46: invokespecial #15 // Method "<init>":()V
49: invokevirtual #25 // Method methodI:()V
52: invokestatic #26 // Method methodJ:()V
55: invokestatic #27 // Method methodK:()V
58: invokestatic #28 // Method methodL:()V
61: iload_2
62: ireturn
LineNumberTable:
line 128: 0
line 129: 4
line 130: 7
line 131: 25
line 132: 28
line 133: 32
line 134: 36
line 135: 39
line 136: 42
line 137: 52
line 138: 55
line 139: 58
line 140: 61
JVM | 字節碼指令基礎