二、常见字节码指令

常见字节码指令

加载和存储指令

加载(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_<n>把int类型值(0~5)压入栈顶
bipush把-128~127的int类型值压入栈顶,如bipush 100
ldc把常量值从常量池压入栈顶,如ldc #10
<T>load把类型为T的变量从局部变量表的指定位置压入栈顶,如iload 10。T可为i、l、f、d、a,其中a为引用类型,如aload 0
<T>load_<n>把类型为T的变量从局部变量表下标为n(0~3)的位置压入栈顶,如iload_1
<T>aload将指定数组中类型为T的数据从指定位置压入栈顶
<T>store将栈顶类型为T的数据存储到局部变量表的指定位置,如astore 2
<T>store_<n>将栈顶类型为T的数据存储到局部变量表下标为n(0~3)的位置
<T>astore将栈顶类型为T的数据存储到指定数组的指定位置
操作数栈指令

常见的操作数栈指令有pop、dup和swap。

指令描述
pop将栈顶的数据出栈(非long和double类型)
pop2将栈顶的数据出栈(long或double类型)或两个其他类型的数据出栈
dup复制栈顶数据,并将复制的数据入栈
dup_x1复制栈顶数据,并将复制的数据插入栈顶第二个元素之下
dup2复制栈顶的两个数据并入栈
swap交换栈顶的两个元素
  1. pop指令
    用于将栈顶的值出栈。一个场景的场景是调用了有返回值的方法,但没有使用这个返回值。
public String foo() {
    return "str";
}

public void bar() {
    foo();  \\没有接收foo()方法的返回值
}

bar()方法对应的字节码

0: aload_0
1: invokevirtual #13
2: pop  \\用来弹出调用bar方法的返回值
3: return
  1. dup指令
    用于复制栈顶的元素并压入栈顶。
  2. swap指令
    用于交换栈顶的两个元素。
运算和类型转换指令
运算符指令(int)指令(long)指令(float)指令(double)
+iaddladdfadddadd
-isublsubfsubdsub
*imullmulfmuldmul
/idivldivfdivddiv
%iremlremfremdrem
negate(-:取反)ineglnegfnegdneg
&iadnland
|iorlor
^ixorlxor

如果两个数据类型不一样的数据做运算,需要进行类型转换。
1.0 + 1的字节码如下:

fconst_1
iconst_1
i2f //将栈顶的1转化为float类型
fadd

有多种类型数据混合运算是,系统会自动将数据转换为范围更大的数据类型,称为宽化类型转换(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类型元素,<则跳转
if_icmpge比较栈顶两个int类型元素,>=则跳转
goto无条件跳转
tabelswitchswitch条件跳转,case值紧凑的情况下使用
lookupswitchswithc条件跳转,case值稀疏的情况下使用

示例
java代码

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。该操作无需对局部变量表数据做入栈相加出栈操作
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值