1. 程式人生 > >JVM | 字節碼指令基礎

JVM | 字節碼指令基礎

odk 拋出異常 取反 dup2 位與 init int virtual exceptio

  • 操作數棧管理指令

  • 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 | 字節碼指令基礎