程序员Java 虚拟机

【Java 虚拟机笔记】字节码指令相关整理

2019-03-11  本文已影响29人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 概述

2. 常用的字节码指令

2.1 加载和存储指令

指令 说明 样例
load 指令 将一个局部变量加载到操作栈 iload、iload_<n>、lload、lload_<n>、fload、fload_<n>、dload、dload_<n>、aload、aload_<n>
store 指令 将一个数值从操作数栈存储到局部变量表 istore、istore_<n>、lstore、lstore_<n>、fstore、fstore_<n>、dstore、dstore_<n>、astore、astore_<n>
push、dc、const 指令 将一个常量加载到操作数栈 bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_<i>、lconst_<l>、fconst_<f>、dconst_<d>
wide 指令 扩充局部变量表的访问索引 wide

load 系列指令

指令码 助记符 说明
0x15 iload 将指定的 int 型本地变量推送至栈顶。
0x16 lload 将指定的 long 型本地变量推送至栈顶。
0x17 fload 将指定的 float 型本地变量推送至栈顶。
0x18 dload 将指定的 double 型本地变量推送至栈顶。
0x19 aload 将指定的引用类型本地变量推送至栈顶。
0x1a iload_0 将第一个 int 型本地变量推送至栈顶。
0x1b iload_1 将第二个 int 型本地变量推送至栈顶。
0x1c iload_2 将第三个 int 型本地变量推送至栈顶。
0x1d iload_3 将第四个 int 型本地变量推送至栈顶。
0x1e lload_0 将第一个 long 型本地变量推送至栈顶。
0x1f lload_1 将第二个 long 型本地变量推送至栈顶。
0x20 lload_2 将第三个 long 型本地变量推送至栈顶。
0x21 lload_3 将第四个 long 型本地变量推送至栈顶。
0x22 fload_0 将第一个 float 型本地变量推送至栈顶。
0x23 fload_1 将第二个 float 型本地变量推送至栈顶。
0x24 fload_2 将第三个 float 型本地变量推送至栈顶。
0x25 fload_3 将第四个 float 型本地变量推送至栈顶。
0x26 dload_0 将第一个 double 型本地变量推送至栈顶。
0x27 dload_1 将第二个 double 型本地变量推送至栈顶。
0x28 dload_2 将第三个 double 型本地变量推送至栈顶。
0x29 dload_3 将第四个 double 型本地变量推送至栈顶。
0x2a aload_0 将第一个引用类型本地变量推送至栈顶。
0x2b aload_1 将第二个引用类型本地变量推送至栈顶。
0x2c aload_2 将第三个引用类型本地变量推送至栈顶。
0x2d aload_3 将第四个引用类型本地变量推送至栈顶。

store 系列指令

指令码 助记符 说明
0x36 istore 将栈顶 int 型数值存入指定本地变量。
0x37 lstore 将栈顶 long 型数值存入指定本地变量。
0x38 fstore 将栈顶 float 型数值存入指定本地变量。
0x39 dstore 将栈顶 double 型数值存入指定本地变量。
0x3a astore 将栈顶引用型数值存入指定本地变量。
0x3b istore_0 将栈顶 int 型数值存入第一个本地变量。
0x3c istore_1 将栈顶 int 型数值存入第二个本地变量。
0x3d istore_2 将栈顶 int 型数值存入第三个本地变量。
0x3e istore_3 将栈顶 int 型数值存入第四个本地变量。
0x3f lstore_0 将栈顶 long 型数值存入第一个本地变量。
0x40 lstore_1 将栈顶 long 型数值存入第二个本地变量。
0x41 lstore_2 将栈顶 long 型数值存入第三个本地变量。
0x42 lstore_3 将栈顶 long 型数值存入第四个本地变量。
0x43 fstore_0 将栈顶 float 型数值存入第一个本地变量。
0x44 fstore_1 将栈顶 float 型数值存入第二个本地变量。
0x45 fstore_2 将栈顶 float 型数值存入第三个本地变量。
0x46 fstore_3 将栈顶 float 型数值存入第四个本地变量。
0x47 dstore_0 将栈顶 double 型数值存入第一个本地变量。
0x48 dstore_1 将栈顶 double 型数值存入第二个本地变量。
0x49 dstore_2 将栈顶 double 型数值存入第三个本地变量。
0x4a dstore_3 将栈顶 double 型数值存入第四个本地变量。
0x4b astore_0 将栈顶引用型数值存入第一个本地变量。
0x4c astore_1 将栈顶引用型数值存入第二个本地变量。
0x4d astore_2 将栈顶引用型数值存入第三个本地变量。
0x4e astore_3 将栈顶引用型数值存入第四个本地变量。

push 系列指令

指令码 助记符 说明
0x10 bipush 将单字节的常量值(-128~127)推送至栈顶。
0x11 sipush 将一个短整型常量值(-32768~32767)推送至栈顶。

dc 系列指令

指令码 助记符 说明
0x12 ldc 将 int,float 或 String 型常量值从常量池中推送至栈顶。
0x13 ldc_w 将 int,float 或 String 型常量值从常量池中推送至栈顶(宽索引)。
0x14 ldc2_w 将 long 或 double 型常量值从常量池中推送至栈顶(宽索引)。

const 系列指令

指令码 助记符 说明
0x02 iconst_m1 将 int 型(-1)推送至栈顶。
0x03 iconst_0 将 int 型(0)推送至栈顶。
0x04 iconst_1 将 int 型(1)推送至栈顶。
0x05 iconst_2 将 int 型(2)推送至栈顶。
0x06 iconst_3 将 int 型(3)推送至栈顶。
0x07 iconst_4 将 int 型(4)推送至栈顶。
0x08 iconst_5 将 int 型(5)推送至栈顶。
0x09 lconst_0 将 long 型(0)推送至栈顶。
0x0a lconst_1 将 long 型(1)推送至栈顶。
0x0b fconst_0 将 float 型(0)推送至栈顶。
0x0c fconst_1 将 float 型(1)推送至栈顶。
0x0d fconst_2 将 float 型(2)推送至栈顶。
0x0e dconst_0 将 double 型(0)推送至栈顶。
0x0f dconst_1 将 double 型(1)推送至栈顶。

2.2 运算指令

指令 样例
加法指令 iadd、ladd、fadd、dadd。
减法指令 isub、lsub、fsub、dsub。
乘法指令 imul、lmul、fmul、dmul。
除法指令 idiv、ldiv、fdiv、ddiv。
求余指令 irem、lrem、frem、drem。
取反指令 ineg、lneg、fneg、dneg。
位移指令 ishl、ishr、iushr、lshl、lshr、lushr。
按位或指令 ior、lor。
按位与指令 iand、land。
按位异或指令 ixor、lxor。
局部变量自增指令 iinc。
比较指令 dcmpg、dcmpl、fcmpg、fcmpl、lcmp。
指令码 助记符 说明
0x5f swap 将栈最顶端的两个数值互换(数值不能是 long 或 double 类型的)。
0x60 iadd 将栈顶两 int 型数值相加并将结果压入栈顶。
0x61 ladd 将栈顶两 long 型数值相加并将结果压入栈顶。
0x62 fadd 将栈顶两 float 型数值相加并将结果压入栈顶。
0x63 dadd 将栈顶两 double 型数值相加并将结果压入栈顶。
0x64 isub 将栈顶两 int 型数值相减并将结果压入栈顶。
0x65 lsub 将栈顶两 long 型数值相减并将结果压入栈顶。
0x66 fsub 将栈顶两 float 型数值相减并将结果压入栈顶。
0x67 dsub 将栈顶两 double 型数值相减并将结果压入栈顶。
0x68 imul 将栈顶两 int 型数值相乘并将结果压入栈顶。
0x69 lmul 将栈顶两 long 型数值相乘并将结果压入栈顶。
0x6a fmul 将栈顶两 float 型数值相乘并将结果压入栈顶。
0x6b dmul 将栈顶两 double 型数值相乘并将结果压入栈顶。
0x6c idiv 将栈顶两 int 型数值相除并将结果压入栈顶。
0x6d ldiv 将栈顶两 long 型数值相除并将结果压入栈顶。
0x6e fdiv 将栈顶两 float 型数值相除并将结果压入栈顶。
0x6f ddiv 将栈顶两 double 型数值相除并将结果压入栈顶。
0x70 irem 将栈顶两 int 型数值作取模运算并将结果压入栈顶。
0x71 lrem 将栈顶两 long 型数值作取模运算并将结果压入栈顶。
0x72 frem 将栈顶两 float 型数值作取模运算并将结果压入栈顶。
0x73 drem 将栈顶两 double 型数值作取模运算并将结果压入栈顶。
0x74 ineg 将栈顶 int 型数值取负并将结果压入栈顶。
0x75 lneg 将栈顶 long 型数值取负并将结果压入栈顶。
0x76 fneg 将栈顶 float 型数值取负并将结果压入栈顶。
0x77 dneg 将栈顶 double 型数值取负并将结果压入栈顶。
0x78 ishl 将 int 型数值左移位指定位数并将结果压入栈顶。
0x79 lshl 将 long 型数值左移位指定位数并将结果压入栈顶。
0x7a ishr 将 int 型数值右(符号)移位指定位数并将结果压入栈顶。
0x7b lshr 将 long 型数值右(符号)移位指定位数并将结果压入栈顶。
0x7c iushr 将 int 型数值右(无符号)移位指定位数并将结果压入栈顶。
0x7d lushr 将 long 型数值右(无符号)移位指定位数并将结果压入栈顶。
0x7e iand 将栈顶两 int 型数值作 " 按位与 " 并将结果压入栈顶。
0x7f land 将栈顶两 long 型数值作 " 按位与 " 并将结果压入栈顶。
0x80 ior 将栈顶两 int 型数值作 " 按位或 " 并将结果压入栈顶。
0x81 lor 将栈顶两 long 型数值作 " 按位或 " 并将结果压入栈顶。
0x82 ixor 将栈顶两 int 型数值作 " 按位异或 " 并将结果压入栈顶。
0x83 lxor 将栈顶两 long 型数值作 " 按位异或 " 并将结果压入栈顶。

2.3 类型转换指令

宽化类型转换

窄化类型转换

2.4 对象创建与访问指令

指令码 助记符 说明
0x2e iaload 将 int 型数组指定索引的值推送至栈顶。
0x2f laload 将 long 型数组指定索引的值推送至栈顶。
0x30 faload 将 float 型数组指定索引的值推送至栈顶。
0x31 daload 将 double 型数组指定索引的值推送至栈顶。
0x32 aaload 将引用型数组指定索引的值推送至栈顶。
0x33 baload 将 boolean 或 byte 型数组指定索引的值推送至栈顶。
0x34 caload 将 char 型数组指定索引的值推送至栈顶。
0x35 saload 将 short 型数组指定索引的值推送至栈顶。
指令码 助记符 说明
0x4f iastore 将栈顶 int 型数值存入指定数组的指定索引位置。
0x50 lastore 将栈顶 long 型数值存入指定数组的指定索引位置。
0x51 fastore 将栈顶 float 型数值存入指定数组的指定索引位置。
0x52 dastore 将栈顶 double 型数值存入指定数组的指定索引位置。
0x53 aastore 将栈顶引用型数值存入指定数组的指定索引位置。
0x54 bastore 将栈顶 boolean 或 byte 型数值存入指定数组的指定索引位置。
0x55 castore 将栈顶 char 型数值存入指定数组的指定索引位置。
0x56 sastore 将栈顶 short 型数值存入指定数组的指定索引位置。

2.5 操作数栈管理指令

指令码 助记符 说明
0x57 pop 将栈顶数值弹出(数值不能是 long 或 double 类型的)。
0x58 pop2 将栈顶的一个(long 或 double 类型的)或两个数值弹出(其它)。
0x59 dup 复制栈顶数值(数值不能是 long 或 double 类型的)并将复制值压入栈顶。
0x5a dup_x1 复制栈顶数值(数值不能是 long 或 double 类型的)并将两个复制值压入栈顶。
0x5b dup_x2 复制栈顶数值(数值不能是 long 或 double 类型的)并将三个(或两个)复制值压入栈顶。
0x5c dup2 复制栈顶一个(long 或 double 类型的)或两个(其它)数值并将复制值压入栈顶。
0x5d dup2_x1 复制栈顶数值(long 或 double 类型的)并将两个复制值压入栈顶。
0x5e dup2_x2 复制栈顶数值(long 或 double 类型的)并将三个(或两个)复制值压入栈顶。

2.6 控制转移指令

2.7 方法调用和返回指令

方法调用指令

方法返回指令

关于方法调用

2.8 异常处理指令

2.9 同步指令

方法级同步

方法内部一段指令序列的同步

2.10 程序执行使用样例

public class Test {

    public static int minus(int x) {
        return -x;
    }

    public static void main(String[] args) {
        int x = 5;
        int y = minus(x);
    }

}
{
  public services.Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lservices/Test;

  public static int minus(int);
    descriptor: (I)I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=1
         0: iload_0
         1: ineg
         2: ireturn
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       3     0     x   I

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=1
         0: iconst_5
         1: istore_1
         2: iload_1
         3: invokestatic  #2                  // Method minus:(I)I
         6: istore_2
         7: return
      LineNumberTable:
        line 10: 0
        line 11: 2
        line 12: 7
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       8     0  args   [Ljava/lang/String;
            2       6     1     x   I
            7       1     2     y   I
}
public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=1
         0: iconst_5
         1: istore_1
         2: iload_1
         3: invokestatic  #2                  // Method minus:(I)I
         6: istore_2
         7: return
      LineNumberTable:
        line 10: 0
        line 11: 2
        line 12: 7
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       8     0  args   [Ljava/lang/String;
            2       6     1     x   I
            7       1     2     y   I
0: iconst_5
1: istore_1
2: iload_1
3: invokestatic  #2                  // Method minus:(I)I
6: istore_2
7: return
public static int minus(int);
    descriptor: (I)I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=1
         0: iload_0
         1: ineg
         2: ireturn
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       3     0     x   I
 0: iload_0
1: ineg
2: ireturn

重载(override)

public class Test {

    static class Human {
    }

    static class Man extends Human {

    }

    static class Woman extends Human {

    }

    public void sayHello(Human human) {
        System.out.println("hello human");
    }

    public void sayHello(Man man) {
        System.out.println("hello man");
    }

    public void sayHello(Woman woman) {
        System.out.println("hello woman");
    }

    public static void main(String[] args) {
        Test demo = new Test();
        Human man = new Man();
        Human woman = new Woman();
        demo.sayHello(man);
        demo.sayHello(woman);
    }

}
/*print 
hello human
hello human
*/
public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #7                  // class services/Test
         3: dup
         4: invokespecial #8                  // Method "<init>":()V
         7: astore_1
         8: new           #9                  // class services/Test$Man
        11: dup
        12: invokespecial #10                 // Method services/Test$Man."<init>":()V
        15: astore_2
        16: new           #11                 // class services/Test$Woman
        19: dup
        20: invokespecial #12                 // Method services/Test$Woman."<init>":()V
        23: astore_3
        24: aload_1
        25: aload_2
        26: invokevirtual #13                 // Method sayHello:(Lservices/Test$Human;)V
        29: aload_1
        30: aload_3
        31: invokevirtual #13                 // Method sayHello:(Lservices/Test$Human;)V
        34: return
      LineNumberTable:
        line 29: 0
        line 30: 8
        line 31: 16
        line 32: 24
        line 33: 29
        line 34: 34
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      35     0  args   [Ljava/lang/String;
            8      27     1  demo   Lservices/Test;
           16      19     2   man   Lservices/Test$Human;
           24      11     3 woman   Lservices/Test$Human;

重写(overwrite)

public class Test {

    static class Human {
        public void sayHello() {
            System.out.println("hello human");
        }
    }

    static class Man extends Human {
        public void sayHello() {
            System.out.println("hello man");
        }
    }

    static class Woman extends Human {
        public void sayHello() {
            System.out.println("hello woman");
        }
    }

    public static void main(String[] args) {
        Human man = new Man();
        Human woman = new Woman();
        man.sayHello();
        woman.sayHello();
    }

}
/*print
hello man
hello woman
*/
public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #2                  // class services/Test$Man
         3: dup
         4: invokespecial #3                  // Method services/Test$Man."<init>":()V
         7: astore_1
         8: new           #4                  // class services/Test$Woman
        11: dup
        12: invokespecial #5                  // Method services/Test$Woman."<init>":()V
        15: astore_2
        16: aload_1
        17: invokevirtual #6                  // Method services/Test$Human.sayHello:()V
        20: aload_2
        21: invokevirtual #6                  // Method services/Test$Human.sayHello:()V
        24: return
      LineNumberTable:
        line 24: 0
        line 25: 8
        line 26: 16
        line 27: 20
        line 28: 24
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      25     0  args   [Ljava/lang/String;
            8      17     1   man   Lservices/Test$Human;
           16       9     2 woman   Lservices/Test$Human;

参考资料

https://www.jianshu.com/p/d95cfde7fc49
https://blog.csdn.net/Alexwym/article/details/82152665

上一篇 下一篇

猜你喜欢

热点阅读