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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章