常见字节码指令
加载和存储指令
加载(load)和存储(store)相关的指令是使用得最频繁的指令,分为load类、stroe类、常量加载这三种。
- load类指令
load类指令是将局部变量表中的变量加载到操作数栈。
比如iload_0将局部变量表中下标为0的int型变量加载到操作数栈上,根据不同的数据变量类型还有lload、fload、dload、aload这些指令,分别代表long、float、double、引用类型的变量。 - store类指令
store类指令是将栈顶的数据存储到局部变量表中。
比如istore_0是将操作数栈顶的int类型元素存储到局部变量表中下标为0的位置。
根据不同的数据变量类型还有lstore、fstore、dstore、astore这些指令。 - 常量加载相关指令
常见的有const类、push类、ldc类。
const、push类指令是将常量值直接加载到操作数栈顶,如iconst_0是将整数0加载到操作数栈顶,bipush100是将int类型100加载到操作数栈顶。
ldc指令是从常量池加载对应的常量到操作数栈顶,如ldc #10是将常量池中下下标为10的常量数据加载到操作数栈顶。#表示常量池的下标。
常用存储指令
| 指令 | 描述 |
|---|---|
| aconst_null | 把null压入栈顶 |
| iconst_m1 | 把-1压入栈顶 |
| iconst_ | 把int类型值(0~5)压入栈顶 |
| bipush | 把-128~127的int类型值压入栈顶,如bipush 100 |
| ldc | 把常量值从常量池压入栈顶,如ldc #10 |
| load | 把类型为T的变量从局部变量表的指定位置压入栈顶,如iload 10。T可为i、l、f、d、a,其中a为引用类型,如aload 0 |
| load_ | 把类型为T的变量从局部变量表下标为n(0~3)的位置压入栈顶,如iload_1 |
| aload | 将指定数组中类型为T的数据从指定位置压入栈顶 |
| store | 将栈顶类型为T的数据存储到局部变量表的指定位置,如astore 2 |
| store_ | 将栈顶类型为T的数据存储到局部变量表下标为n(0~3)的位置 |
| astore | 将栈顶类型为T的数据存储到指定数组的指定位置 |
操作数栈指令
常见的操作数栈指令有pop、dup和swap。
| 指令 | 描述 |
|---|---|
| pop | 将栈顶的数据出栈(非long和double类型) |
| pop2 | 将栈顶的数据出栈(long或double类型)或两个其他类型的数据出栈 |
| dup | 复制栈顶数据,并将复制的数据入栈 |
| dup_x1 | 复制栈顶数据,并将复制的数据插入栈顶第二个元素之下 |
| dup2 | 复制栈顶的两个数据并入栈 |
| swap | 交换栈顶的两个元素 |
- pop指令
用于将栈顶的值出栈。一个场景的场景是调用了有返回值的方法,但没有使用这个返回值。
public String foo() { return "str"; } public void bar() { foo(); \\没有接收foo()方法的返回值 }
bar()方法对应的字节码
0: aload_0 1: invokevirtual #13 2: pop \\用来弹出调用bar方法的返回值 3: return
- dup指令
用于复制栈顶的元素并压入栈顶。 - swap指令
用于交换栈顶的两个元素。
运算和类型转换指令
| 运算符 | 指令(int) | 指令(long) | 指令(float) | 指令(double) | |
|---|---|---|---|---|---|
| + | iadd | ladd | fadd | dadd | |
| – | isub | lsub | fsub | dsub | |
| * | imul | lmul | fmul | dmul | |
| / | idiv | ldiv | fdiv | ddiv | |
| % | irem | lrem | frem | drem | |
| negate(-:取反) | ineg | lneg | fneg | dneg | |
| & | iadn | land | — | — | |
| | | ior | lor | — | — | |
| ^ | ixor | lxor | — | — |
有多种类型数据混合运算是,系统会自动将数据转换为范围更大的数据类型,称为宽化类型转换(widening)或自动类型转换。
宽化类型转换并不意味着不会丢失精度。
把范围大的数据类型转换为范围小的数据类型,称为窄化类型转换(narrowing)或强制类型转换。
控制转移指令
| 指令 | 描述 |
|---|---|
| ifeq | 如果int类型栈顶元素=0,则跳转 |
| ifne | 如果int类型栈顶元素≠0,则跳转 |
| iflt | 如果int类型栈顶元素<0,则跳转 |
| ifge | 如果int类型栈顶元素>=0,则跳转 |
| ifgt | 如果int类型栈顶元素>0,则跳转 |
| ifle | 如果int类型栈顶元素<=0,则跳转 |
| if_icompeq | 比较栈顶两个int类型元素,=则跳转 |
| if_icmpne | 比较栈顶两个int类型元素,≠则跳转 |
| if_icmplt | 比较栈顶两个int类型元素, <则跳转< td=""> 则跳转<> |
| if_icmpge | 比较栈顶两个int类型元素,>=则跳转 |
| … | … |
| goto | 无条件跳转 |
| tabelswitch | switch条件跳转,case值紧凑的情况下使用 |
| lookupswitch | swithc条件跳转,case值稀疏的情况下使用 |
public int isPositive(int n) { if (n > 0) { return 1; } else { return 0; } }
字节码
0: iload_1 1: ifle 4 4: iconst_1 5: ireturn 6: iconst_0 7: ireturn
其他
| 指令 | 描述 |
|---|---|
| iinc | 直接对局部变量表的数据进行加运行,如iinc 5,1表示对局部变量表下标为5的值+1。该操作无需对局部变量表数据做入栈相加出栈操作 |
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176173.html原文链接:https://javaforall.net
