JVM | 字节码指令基础

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 | 字节码指令基础的主要内容,如果未能解决你的问题,请参考以下文章

深入理解JVM - 字节码指令

JVM理论:(三/2)字节码指令

jvm中篇-05-字节码指令集与解析

基于栈的虚拟机字节码执行引擎

JVM进阶之字节码文件解析指令

JVM虚拟机