2. 前端编译阶段及字节码文件
https://www.cnblogs.com/chanshuyi/p/jvm_serial_05_jvm_bytecode_analysis.html
1. 作用
字节码文件本质上是一个以 8 位字节为基础单位的二进制流文件,各个数据项目严格按照顺序紧凑的排列在 class 文件中。jvm 根据其特定的规则解析该二进制数据,从而得到相关信息。
从更高层次上抽象的话,如果 jvm 就是一个计算机操作系统,而字节码文件就是操作系统的指令集。高级语言通过各种各样的编译器生成字节码文件,然后通过字节码文件操纵 jvm 完成实际的程序功能。
字节码增强技术 和 运行时类重载技术:
因为已经了解到字节码指令了,因此,我们就可以对字节码文件进行编辑,让字节码文件操作 jvm 完成某项功能。这就是所谓的字节码增强技术。
由于字节码增强技术只能用于操作字节码文件,对于已经加载到 jvm 中的 class 类对象,并没有办法进行操作,因此 jvm 对外提供了一整套的 api,可以用来专门解决这个问题。这一套 API 就是运行时类重载技术。
为什么要了解字节码?
- 有利于编写更加高效,性能更高的程序;
- 通过修改字节码来调整程序行为;
- 对于了解一些利用字节码相关技术完成软件功能的实现原理有帮助,如了解 AOP 的实现原理、Profiler 的实现原理、Mock 框架的实现原理等;
- 热部署、性能诊断工具等;
2. 查看 class 文件的方法
- javap 进行反编译;
- idea 中的 show bytecode;
- idea 插件中的 jclasslib 插件包;
- arths
3. Appendix:指令集
字节码指令根据功能、属性不同,可以分为 11 大类。下面附上字节码指令的分类,用于简单、临时查看,字节码指令的详细介绍,还需要查看官网的介绍。
Constants 常量相关
十进制 | 操作码 | 助记符 | 含义 |
---|---|---|---|
00 | 0x00 | nop | 什么都不做 |
01 | 0x01 | aconst_null | 把 null 推到操作数栈 |
02 | 0x02 | iconst_m1 | 把 int 常量 –1 推到操作数栈 |
03 | 0x03 | iconst_0 | 把 int 常量 0 推到操作数栈 |
04 | 0x04 | iconst_1 | 把 int 常量 1 推到操作数栈 |
05 | 0x05 | iconst_2 | 把 int 常量 2 推到操作数栈 |
06 | 0x06 | iconst_3 | 把 int 常量 3 推到操作数栈 |
07 | 0x07 | iconst_4 | 把 int 常量 4 推到操作数栈 |
08 | 0x08 | iconst_5 | 把 int 常量 5 推到操作数栈 |
09 | 0x09 | lconst_0 | 把 long 常量 0 推到操作数栈 |
10 | 0x0A | lconst_1 | 把 long 常量 1 推到操作数栈 |
11 | 0x0B | fconst_0 | 把 float 常量 0 推到操作数栈 |
12 | 0x0C | fconst_1 | 把 float 常量 1 推到操作数栈 |
13 | 0x0D | fconst_2 | 把 float 常量 2 推到操作数栈 |
14 | 0x0E | dconst_0 | 把 double 常量 0 推到操作数栈 |
15 | 0x0F | dconst_1 | 把 double 常量 1 推到操作数栈 |
16 | 0x10 | bipush | 把单字节常量(-128~127)推到操作数栈 |
17 | 0x11 | sipush | 把 short 常量(-32768~32767)推到操作数栈 |
18 | 0x12 | ldc | 把常量池中的 int,float,String 型常量取出并推到操作数栈顶 |
19 | 0x13 | ldc_w | 把常量池中的 int,float,String 型常量取出并推到操作数栈顶(宽索引) |
20 | 0x14 | ldc2_w | 把常量池中的 long,double 型常量取出并推到操作数栈顶(宽索引) |
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 型数组指定索引的值推到操作数栈 |
Loads 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 型数值存入数组指定索引位置 |
Loads Stack 栈相关
十进制 | 操作码 | 助记符 | 含义 |
---|---|---|---|
87 | 0x57 | pop | 把栈顶数值弹出(非 long,double 数值) |
88 | 0x58 | pop2 | 把栈顶的一个 long 或 double 值弹出,或弹出 2 个其他类型数值 |
89 | 0x59 | dup | 复制栈顶数值并把数值入栈 |
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 类型< td >的) |
Loads 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 型数值相减并将结果入栈 |
101 | 0x65 | lsub | 把栈顶两个 long 型数值相减并将结果入栈 |
102 | 0x66 | fsub | 把栈顶两个 float 型数值相减并将结果入栈 |
103 | 0x67 | dsub | 把栈顶两个 double 型数值相减并将结果入栈 |
104 | 0x68 | imul | 把栈顶两个 int 型数值相乘并将结果入栈 |
105 | 0x69 | lmul | 把栈顶两个 long 型数值相乘并将结果入栈 |
106 | 0x6A | fmul | 把栈顶两个 float 型数值相乘并将结果入栈 |
107 | 0x6B | dmul | 把栈顶两个 double 型数值相乘并将结果入栈 |
108 | 0x6C | idiv | 把栈顶两个 int 型数值相除并将结果入栈 |
109 | 0x6D | ldiv | 把栈顶两个 long 型数值相除并将结果入栈 |
110 | 0x6E | fdiv | 把栈顶两个 float 型数值相除并将结果入栈 |
111 | 0x6F | ddiv | 把栈顶两个 double 型数值相除并将结果入栈 |
112 | 0x70 | irem | 把栈顶两个 int 型数值模运算并将结果入栈 |
113 | 0x71 | lrem | 把栈顶两个 long 型数值模运算并将结果入栈 |
114 | 0x72 | frem | 把栈顶两个 float 型数值模运算并将结果入栈 |
115 | 0x73 | drem | 把栈顶两个 double 型数值模运算并将结果入栈 |
116 | 0x74 | ineg | 把栈顶 int 型数值取负并将结果入栈 |
117 | 0x75 | lneg | 把栈顶 long 型数值取负并将结果入栈 |
118 | 0x76 | fneg | 把栈顶 float 型数值取负并将结果入栈 |
119 | 0x77 | dneg | 把栈顶 double 型数值取负并将结果入栈 |
120 | 0x78 | ishl | 把 int 型数左移指定位数并将结果入栈 |
121 | 0x79 | lshl | 把 long 型数左移指定位数并将结果入栈 |
122 | 0x7A | ishr | 把 int 型数右移指定位数并将结果入栈(有符号) |
123 | 0x7B | lshr | 把 long 型数右移指定位数并将结果入栈(有符号) |
124 | 0x7C | iushr | 把 int 型数右移指定位数并将结果入栈(无符号) |
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 型增加指定值 |
Loads Conversions 转换相关
类型转换指令可以将两种不同的数值类型进行相互转换,这些转换操作一般用于实现用户代码中的显示类型转换操作。 Java 虚拟机直接支持(即转换时无需显示的转换指令)小范围类型向大范围类型的安全转换,但在处理窄化类型转换时,必须显式使用转换指令来完成。
十进制 | 操作码 | 助记符 | 含义 |
---|---|---|---|
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 并入栈 |
Loads Comparisons 比较相关
十进制 | 操作码 | 助记符 | 含义 |
---|---|---|---|
148 | 0x94 | lcmp | 比较栈顶两 long 型数值大小,并将结果(1,0,-1)压入栈顶 |
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 时,跳转 |
154 | 0x9A | ifne | 当栈顶 int 型数值不等于 0 时,跳转 |
155 | 0x9B | iflt | 当栈顶 int 型数值小于 0 时,跳转 |
156 | 0x9C | ifge | 当栈顶 int 型数值大于等于 0 时,跳转 |
157 | 0x9D | ifgt | 当栈顶 int 型数值大于 0 时,跳转 |
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 | 比较栈顶两个 引用 型数值,不相等时跳转 |
Loads Control 控制相关
控制转移指令可以让 Java 虚拟机有条件或无条件地从指定的位置指令而不是控制转移指令的下一条指令继续执行程序,从概念模型上理解,可以认为控制转移指令就是在有条件或无条件地修改 PC 寄存器的值。
十进制 | 操作码 | 助记符 | 含义 |
---|---|---|---|
167 | 0xA7 | goto | 无条件分支跳转 |
168 | 0xA8 | jsr | 跳转至指定 16 位 offset(bit) 位置,并将 jsr 下一条指令地址压入栈顶 |
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 |
Loads 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 指令,而无论这个方法是正常结束还是异常结束。
Loads 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 下一条指令地址入栈 |
Loads Reserved 保留指令
十进制 | 操作码 | 助记符 | 含义 |
---|---|---|---|
202 | 0xCA | breakpoint | 调试时的断点 |
254 | 0xFE | impdep1 | 用于在特定硬件中使用的语言后门 |
255 | 0xFF | impdep2 | 用于在特定硬件中使用的语言后门 |
作者:刘 Java 链接:https://juejin.cn/post/7027707475503611940 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。