【Java】JVM 字节码指令大全

下文中的操作数栈

对于非静态方法,局部变量表的 0 号槽为 this 变量。

局部变量表中的变量槽可以复用。

Constants 常量相关

十进制 操作码 助记符 含义 备注
0 0x00 nop 什么都不做
1 0x01 aconst_null 把 null 压入栈顶 a 代表引用
2 0x02 iconst_m1 把 int 常量 –1 压入栈顶 i 代表 int
3 0x03 iconst_0 把 int 常量 0 压入栈顶
4 0x04 iconst_1 把 int 常量 1 压入栈顶
5 0x05 iconst_2 把 int 常量 2 压入栈顶
6 0x06 iconst_3 把 int 常量 3 压入栈顶
7 0x07 iconst_4 把 int 常量 4 压入栈顶
8 0x08 iconst_5 把 int 常量 5 压入栈顶
9 0x09 lconst_0 把 long 常量 0 压入栈顶 l 代表 long
10 0x0A lconst_1 把 long 常量 1 压入栈顶
11 0x0B fconst_0 把 float 常量 0 压入栈顶 f 代表 float
12 0x0C fconst_1 把 float 常量 1 压入栈顶
13 0x0D fconst_2 把 float 常量 2 压入栈顶
14 0x0E dconst_0 把 double 常量 0 压入栈顶 d 代表 double
15 0x0F dconst_1 把 double 常量 1 压入栈顶
16 0x10 bipush 把单字节常量(-128~127)压入栈顶 b 代表 byte
17 0x11 sipush 把 short 常量(-32768~32767)压入栈顶
18 0x12 ldc 把常量池中的 int,float,String 型常量取出并压入栈顶 ld 应该是 load
19 0x13 ldc_w 把常量池中的 int,float,String 型常量取出并压入栈顶(宽索引)

Loads 加载相关

将局部变量复制到栈顶,局部变量表中仍然存在该变量。

十进制 操作码 助记符 含义 备注
21 0x15 iload 把 int 型局部变量压入栈顶
22 0x16 lload 把 long 型局部变量压入栈顶
23 0x17 fload 把 float 型局部变量压入栈顶
24 0x18 dload 把 double 型局部变量压入栈顶
25 0x19 aload 把引用型局部变量压入栈顶
26 0x1A iload_0 把局部变量第 1 个 int 型局部变量压入栈顶
27 0x1B iload_1 把局部变量第 2 个 int 型局部变量压入栈顶
28 0x1C iload_2 把局部变量第 3 个 int 型局部变量压入栈顶
29 0x1D iload_3 把局部变量第 4 个 int 型局部变量压入栈顶
30 0x1E lload_0 把局部变量第 1 个 long 型局部变量压入栈顶
31 0x1F lload_1 把局部变量第 2 个 long 型局部变量压入栈顶
32 0x20 lload_2 把局部变量第 3 个 long 型局部变量压入栈顶
33 0x21 lload_3 把局部变量第 4 个 long 型局部变量压入栈顶
34 0x22 fload_0 把局部变量第 1 个 float 型局部变量压入栈顶
35 0x23 fload_1 把局部变量第 2 个 float 型局部变量压入栈顶
36 0x24 fload_2 把局部变量第 3 个 float 型局部变量压入栈顶
37 0x25 fload_3 把局部变量第 4 个 float 型局部变量压入栈顶
38 0x26 dload_0 把局部变量第 1 个 double 型局部变量压入栈顶
39 0x27 dload_1 把局部变量第 2 个 double 型局部变量压入栈顶
40 0x28 dload_2 把局部变量第 3 个 double 型局部变量压入栈顶
41 0x29 dload_3 把局部变量第 4 个 double 型局部变量压入栈顶
42 0x2A aload_0 把局部变量第 1 个引用型局部变量压入栈顶
43 0x2B aload_1 把局部变量第 2 个引用型局部变量压入栈顶
44 0x2C aload_2 把局部变量第 3 个引用型局部变量压入栈顶
45 0x2D aload_3 把局部变量第 4 个引用 型局部变量压入栈顶
46 0x2E iaload 把 int 型数组指定索引的值压入栈顶
47 0x2F laload 把 long 型数组指定索引的值压入栈顶
48 0x30 faload 把 float 型数组指定索引的值压入栈顶
49 0x31 daload 把 double 型数组指定索引的值压入栈顶
50 0x32 aaload 把引用型数组指定索引的值压入栈顶
51 0x33 baload 把 boolean 或 byte 型数组指定索引的值压入栈顶
52 0x34 caload 把 char 型数组指定索引的值压入栈顶
53 0x35 saload 把 short 型数组指定索引的值压入栈顶

Store 存储相关

将栈顶弹出到局部变量表中,栈中就没有该变量了。

十进制 操作码 助记符 含义 备注
54 0x36 istore 把栈顶 int 型数值存入指定局部变量
55 0x37 lstore 把栈顶 long 型数值存入指定局部变量
56 0x38 fstore 把栈顶 float 型数值存入指定局部变量
57 0x39 dstore 把栈顶 double 型数值存入指定局部变量
58 0x3A astore 把栈顶引用型数值存入指定局部变量
59 0x3B istore_0 把栈顶 int 型数值存入第 1 个局部变量
60 0x3C istore_1 把栈顶 int 型数值存入第 2 个局部变量
61 0x3D istore_2 把栈顶 int 型数值存入第 3 个局部变量
62 0x3E istore_3 把栈顶 int 型数值存入第 4 个局部变量
63 0x3F lstore_0 把栈顶 long 型数值存入第 1 个局部变量
64 0x40 lstore_1 把栈顶 long 型数值存入第 2 个局部变量
65 0x41 lstore_2 把栈顶 long 型数值存入第 3 个局部变量
66 0x42 lstore_3 把栈顶 long 型数值存入第 4 个局部变量
67 0x43 fstore_0 把栈顶 float 型数值存入第 1 个局部变量
68 0x44 fstore_1 把栈顶 float 型数值存入第 2 个局部变量
69 0x45 fstore_2 把栈顶 float 型数值存入第 3 个局部变量
70 0x46 fstore_3 把栈顶 float 型数值存入第 4 个局部变量
71 0x47 dstore_0 把栈顶 double 型数值存入第 1 个局部变量
72 0x48 dstore_1 把栈顶 double 型数值存入第 2 个局部变量
73 0x49 dstore_2 把栈顶 double 型数值存入第 3 个局部变量
74 0x4A dstore_3 把栈顶 double 型数值存入第 4 个局部变量
75 0x4B astore_0 把栈顶 引用 型数值存入第 1 个局部变量
76 0x4C astore_1 把栈顶 引用 型数值存入第 2 个局部变量
77 0x4D astore_2 把栈顶 引用 型数值存入第 3 个局部变量
78 0x4E astore_3 把栈顶 引用 型数值存入第 4 个局部变量
79 0x4F iastore 把栈顶 int 型数值存入数组指定索引位置
80 0x50 lastore 把栈顶 long 型数值存入数组指定索引位置
81 0x51 fastore 把栈顶 float 型数值存入数组指定索引位置
82 0x52 dastore 把栈顶 double 型数值存入数组指定索引位置
83 0x53 aastore 把栈顶 引用 型数值存入数组指定索引位置
84 0x54 bastore 把栈顶 boolean or byte 型数值存入数组指定索引位置
85 0x55 castore 把栈顶 char 型数值存入数组指定索引位置
86 0x56 sastore 把栈顶 short 型数值存入数组指定索引位置

Stack 栈相关

十进制 操作码 助记符 含义 备注
87 0x57 pop 把栈顶数值弹出(非 long,double 数值)
88 0x58 pop2 把栈顶的一个 long 或 double 值弹出,或弹出 2 个其他类型数值
89 0x59 dup 复制栈顶数值并把数值入栈 dup 为 duplicate
90 0x5A dup_x1 复制栈顶数值并将两个复制值压入栈顶
91 0x5B dup_x2 复制栈顶数值并将三个(或两个)复制值压入栈顶
92 0x5C dup2 复制栈顶一个(long 或 double 类型的) 或两个(其它)数值并将复制值压入栈顶
93 0x5D dup2_x1 dup_x1 指令的双倍版本
94 0x5E dup2_x2 dup_x2 指令的双倍版本
95 0x5F swap 把栈顶端的两个数的值交换(数值不能是 long 或 double 类型 的)

Math 运算相关

Java 虚拟机在处理浮点数运算时,不会抛出任何运行时异常,当一个操作产生溢出时,将会使用有符号的无穷大来表示,如果某个操作结果没有明确的数学定义的话,将会使用 NaN 值来表示。所有使用 NaN 值作为操作数的算术操作,结果都会返回 NaN。

十进制 操作码 助记符 含义 备注
96 0x60 iadd 把栈顶两个 int 型数值相加并将结果入栈
97 0x61 ladd 把栈顶两个 long 型数值相加并将结果入栈
98 0x62 fadd 把栈顶两个 float 型数值相加并将结果入栈
99 0x63 dadd 把栈顶两个 double 型数值相加并将结果入栈
100 0x64 isub 把栈顶两个 int 型数值相减并将结果入栈 sub 为 subtract
101 0x65 lsub 把栈顶两个 long 型数值相减并将结果入栈
102 0x66 fsub 把栈顶两个 float 型数值相减并将结果入栈
103 0x67 dsub 把栈顶两个 double 型数值相减并将结果入栈
104 0x68 imul 把栈顶两个 int 型数值相乘并将结果入栈 mul 为 multiple
105 0x69 lmul 把栈顶两个 long 型数值相乘并将结果入栈
106 0x6A fmul 把栈顶两个 float 型数值相乘并将结果入栈
107 0x6B dmul 把栈顶两个 double 型数值相乘并将结果入栈
108 0x6C idiv 把栈顶两个 int 型数值相除并将结果入栈 div 为 divide
109 0x6D ldiv 把栈顶两个 long 型数值相除并将结果入栈
110 0x6E fdiv 把栈顶两个 float 型数值相除并将结果入栈
111 0x6F ddiv 把栈顶两个 double 型数值相除并将结果入栈
112 0x70 irem 把栈顶两个 int 型数值模运算并将结果入栈 rem 为 remainder
113 0x71 lrem 把栈顶两个 long 型数值模运算并将结果入栈
114 0x72 frem 把栈顶两个 float 型数值模运算并将结果入栈
115 0x73 drem 把栈顶两个 double 型数值模运算并将结果入栈
116 0x74 ineg 把栈顶 int 型数值取负并将结果入栈 neg 为 negative
117 0x75 lneg 把栈顶 long 型数值取负并将结果入栈
118 0x76 fneg 把栈顶 float 型数值取负并将结果入栈
119 0x77 dneg 把栈顶 double 型数值取负并将结果入栈
120 0x78 ishl 把 int 型数左移指定位数并将结果入栈 sh 为 shift
121 0x79 lshl 把 long 型数左移指定位数并将结果入栈 不管左移还是右移,位数必定在(0~31),若大于,会先求余
122 0x7A ishr 把 int 型数右移指定位数并将结果入栈(有符号)
123 0x7B lshr 把 long 型数右移指定位数并将结果入栈(有符号)
124 0x7C iushr 把 int 型数右移指定位数并将结果入栈(无符号) u 为 unsigned
125 0x7D lushr 把 long 型数右移指定位数并将结果入栈(无符号)
126 0x7E iand 把栈顶两个 int 型数值 按位与 并将结果入栈
127 0x7F land 把栈顶两个 long 型数值 按位与 并将结果入栈
128 0x80 ior 把栈顶两个 int 型数值 按位或 并将结果入栈
129 0x81 lor 把栈顶两个 long 型数值 按或与 并将结果入栈
130 0x82 ixor 把栈顶两个 int 型数值 按位异或 并将结果入栈
131 0x83 lxor 把栈顶两个 long 型数值 按位异或 并将结果入栈
132 0x84 iinc 把指定 int 型增加指定值 inc 为 increment

Conversions 转换相关

十进制 操作码 助记符 含义 备注
133 0x85 i2l 把栈顶 int 强转 long 并入栈
134 0x86 i2f 把栈顶 int 强转 float 并入栈
135 0x87 i2d 把栈顶 int 强转 double 并入栈
136 0x88 l2i 把栈顶 long 强转 int 并入栈
137 0x89 l2f 把栈顶 long 强转 float 并入栈
138 0x8A l2d 把栈顶 long 强转 double 并入栈
139 0x8B f2i 把栈顶 float 强转 int 并入栈
140 0x8C f2l 把栈顶 float 强转 long 并入栈
141 0x8D f2d 把栈顶 float 强转 double 并入栈
142 0x8E d2i 把栈顶 double 强转 int 并入栈
143 0x8F d2l 把栈顶 double 强转 long 并入栈
144 0x90 d2f 把栈顶 double 强转 float 并入栈
145 0x91 i2b 把栈顶 int 强转 byte 并入栈
146 0x92 i2c 把栈顶 int 强转 char 并入栈
147 0x93 i2s 把栈顶 int 强转 short 并入栈

Comparisons 比较相关

十进制 操作码 助记符 含义 备注
148 0x94 lcmp 比较栈顶两 long 型数值大小,并将结果(1,0,-1)压入栈顶 cmp 为 compare
149 0x95 fcmpl 比较栈顶两 float 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 “NaN” 时,将 - 1 压入栈顶
150 0x96 fcmpg 比较栈顶两 float 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 “NaN” 时,将 1 压入栈顶
151 0x97 dcmpl 比较栈顶两 double 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 “NaN” 时,将 - 1 压入栈顶
152 0x98 dcmpg 比较栈顶两 double 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 “NaN” 时,将 1 压入栈顶
153 0x99 ifeq 当栈顶 int 型数值等于 0 时,跳转 eq 为 equal
154 0x9A ifne 当栈顶 int 型数值不等于 0 时,跳转 ne 为 not equal
155 0x9B iflt 当栈顶 int 型数值小于 0 时,跳转 lt 为 less than
156 0x9C ifge 当栈顶 int 型数值大于等于 0 时,跳转
157 0x9D ifgt 当栈顶 int 型数值大于 0 时,跳转 gt 为 greater than
158 0x9E ifle 当栈顶 int 型数值小于等于 0 时,跳转
159 0x9F if_icmpeq 比较栈顶两个 int 型数值,等于 0 时,跳转
160 0xA0 if_icmpne 比较栈顶两个 int 型数值,不等于 0 时,跳转
161 0xA1 if_icmplt 比较栈顶两个 int 型数值,小于 0 时,跳转
162 0xA2 if_icmpge 比较栈顶两个 int 型数值,大于等于 0 时,跳转
163 0xA3 if_icmpgt 比较栈顶两个 int 型数值,大于 0 时,跳转
164 0xA4 if_icmple 比较栈顶两个 int 型数值,小于等于 0 时,跳转
165 0xA5 if_acmpeq 比较栈顶两个 引用 型数值,相等时跳转
166 0xA6 if_acmpne 比较栈顶两个 引用 型数值,不相等时跳转

Control 控制相关

控制转移指令可以让 Java 虚拟机有条件或无条件地从指定的位置指令而不是控制转移指令的下一条指令继续执行程序,从概念模型上理解,可以认为控制转移指令就是在有条件或无条件地修改 PC 寄存器的值。

十进制 操作码 助记符 含义 备注
167 0xA7 goto 无条件分支跳转
168 0xA8 jsr 跳转至指定 16 位 offset(bit) 位置,并将 jsr 下一条指令地址压入栈顶 Jump to SubRoutine
169 0xA9 ret 返回至局部变量指定的 index 的指令位置(一般与 jsr,jsr_w 联合使用)
170 0xAA tableswitch 用于 switch 条件跳转,case 值连续(可变长度指令)
171 0xAB lookupswitch 用于 switch 条件跳转,case 值不连续(可变长度指令)
172 0xAC ireturn 结束方法,并返回一个 int 类型数据
173 0xAD lreturn 从当前方法返回 long
174 0xAE freturn 从当前方法返回 float
175 0xAF dreturn 从当前方法返回 double
176 0xB0 areturn 从当前方法返回 对象引用
177 0xB1 return 从当前方法返回 void

references 引用、方法、异常、同步相关

十进制 操作码 助记符 含义 备注
178 0xB2 getstatic 获取指定类的静态域,并将其值压入栈顶
179 0xB3 putstatic 为类的静态域赋值
180 0xB4 getfield 获取指定类的实例域(对象的字段值),并将其值压入栈顶
181 0xB5 putfield 为指定的类的实例域赋值
182 0xB6 invokevirtual 调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),是 Java 语言中最常见的方法分派方式。
183 0xB7 invokespecial 调用一些需要特殊处理的实例方法,包括实例初始化方法()、私有方法和父类方法。这三类方法的调用对象在编译时就可以确定。
184 0xB8 invokestatic 调用静态方法
185 0xB9 invokeinterface 调用接口方法调,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。
186 0xBA invokedynamic 调用动态链接方法(该指令是指令是 Java SE 7 中新加入的)。用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法,前面 4 条调用指令的分派逻辑都固化在 Java 虚拟机内部,而 invokedynamic 指令的分派逻辑是由用户所设定的引导方法决定的。
187 0xBB new 创建一个对象,并将其引用值压入栈顶
188 0xBC newarray 创建一个指定原始类型(如 int、float、char……)的数组,并将其引用值压入栈顶
189 0xBD anewarray 创建一个引用型(如类,接口,数组)的数组,并将其引用值压入栈顶
190 0xBE arraylength 获得数组的长度值并压入栈顶
191 0xBF athrow 将栈顶的异常直接抛出。Java 程序中显式抛出异常的操作(throw 语句)都由 athrow 指令来实现,并且,在 Java 虚拟机中,处理异常(catch 语句)不是由字节码指令来实现的,而是采用异常表来完成的。
192 0xC0 checkcast 检验类型转换,检验未通过将抛出 ClassCastException
193 0xC1 instanceof 检验对象是否是指定的类的实例,如果是将 1 压入栈顶,否则将 0 压入栈顶
194 0xC2 monitorenter 获取对象的 monitor,用于同步块或同步方法
195 0xC3 monitorexit 释放对象的 monitor,用于同步块或同步方法

Java 虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程(Monitor)来支持的。
方法级的同步是隐式的,即无须通过字节码指令来控制,它实现在方法调用和返回操作之中。 虚拟机可以从方法常量池的方法表结构中的 ACC_SYNCHRONIZED 方法标志得知一个方法是否声明为同步方法。当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那么这个??同步方法所持有的管程将在异常抛到同步方法之外时自动释放。
同步一段指令集序列通常是由 Java 语言中的 synchronized 语句块来表示的,Java 虚拟机的指令集中有 monitorenter 和 monitorexit 两条指令来支持 synchronized 关键字的语义。
编译器必须确保无论方法通过何种方式完成,方法中调用过的每条 monitorenter 指令都必须执行其对应的 monitorexit 指令,而无论这个方法是正常结束还是异常结束。

Extended 扩展相关

十进制 操作码 助记符 含义 备注
196 0xC4 wide 扩展访问局部变量表的索引宽度
197 0xC5 multianewarray 创建指定类型和指定维度的多维数组(执行该指令时,操作栈中必须包含各维度的长度值),并将其引用值压入栈顶
198 0xC6 ifnull 为 null 时跳转
199 0xC7 ifnonnull 非 null 时跳转
200 0xC8 goto_w 无条件跳转(宽索引)
201 0xC9 jsr_w 跳转指定 32bit 偏移位置,并将 jsr_w 下一条指令地址入栈

Reserved 保留指令

十进制 操作码 助记符 含义 备注
202 0xCA breakpoint 调试时的断点
254 0xFE impdep1 用于在特定硬件中使用的语言后门
255 0xFF impdep2 用于在特定硬件中使用的语言后门

参考

Java 的 JVM 字节码指令集详解

JVM 规范 Java SE 8 官方文档

JVM 规范第 4 章:class 文件格式

JVM 规范第 6 章:JVM 指令集

JVM 规范第 7 章:操作码助记符表

【Java】JVM 字节码指令大全

上一篇:牛逼!Python常用数据类型的基本操作(长文系列第①篇)(二)


下一篇:阿里云视觉智能开放平台--视觉搜索(图像搜索)使用教程