字节码指令
- 字节码指令
- 加载和存储指令
- 运算指令
- 类型转换指令
- 对象创建和访问指令
- 操作数栈管理指令
- 控制转移指令
- 方法调用和返回指令
- 异常处理指令
- 同步指令
- 大全
字节码指令
JVM采用操作数栈架构,指令由操作码Opcode+操作数Operand构成
- 大多指令不包含操作数,只有一个操作码,指令参数放在操作数栈
- 操作码长度为一个字节,故总数不能超过256
- 操作数未长度对齐,需在运行时重构回去
- 操作码隐含数据类型,如iload从局部变量表中加载int数据到操作数栈中,a代表reference
- byte和short符号扩展为int,boolean和char零位扩展为int
加载和存储指令
用于将数据在栈帧中的局部变量表和操作数栈之间的来回传输
- 将一个局部变量加载到操作数栈:iload、iload_<n>、lload、lload_<n>、fload、fload_<n>、dload、dload_<n>、aload、aload_<n>
- 将一个数值从操作数栈存储到局部变量表:istore、istore_<n>、lstore、lstore_<n>、fstore、fstore_、dstore、dstore_<n>、astore、astore_<n>
- 将一个常量加载到操作数栈:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_<i>、lconst_<l>、fconst_<f>、dconst_<d>
- 扩充局部变量表的访问索引的指令:wide
其中n代表数字,将操作数隐含到指令中
运算指令
用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶,可分为对整数和对浮点数进行运算的指令
- 加: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
整型数据运算可能会导致溢出
除和求余中当除数为0时抛出ArithmeticException异常
类型转换指令
将两种不同的数值类型相互转换,一般用于显示转换
JVM直接支持宽化类型转换,无需显示的转换
- int 转为 long、float、double
- long 转为 float、double
- float 转为 double
而窄化类型转换,必须显式使用转换指令
- i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l、d2f
int或long窄化转换为其他整型时直接高位截断,可能导致符号位改变
浮点值窄化转换为其他整型时
- 若为NaN,结果为0
- 若是无穷大,则向零舍入取整,若取整后不在表示范围,则为最大或最小正数
doulbe转为float时
- 向最接近数舍入
- 若转换结果的绝对值太小,则返回float的正负0
- 若转换结果的绝对值太大,则返回float类型的正负无穷大
- NaN依旧为NaN
对象创建和访问指令
用于创建和访问对象和数组实例
- 创建类:new
- 创建数组:newarray、anewarray、multianewarray
- 访问字段:getfield、putfield、getstatic、putstatic
- 把数组元素加载到操作数栈:baload、caload、saload、iaload、laload、faload、daload、aaload
- 将操作数栈的值存到数组:bastore、castore、sastore、iastore、fastore、dastore、aastore
- 取数组长度:arraylength
- 检查类型:instanceof、checkcast
操作数栈管理指令
用于直接操作操作数栈
- 出栈:pop、pop2
- 复制栈顶元素并入栈:dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2
- 将栈顶两元素互换:swap
控制转移指令
让JVM有条件或无条件地从指定位置指令的下一条指令继续执行程序
- 条件分支:ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne
- 复合条件分支:tableswitch、lookupswitch
- 无条件分支:goto、goto_w、jsr、jsr_w、ret
long、float、double的条件分支操作,会先执行比较运算指令得到int值,再执行int类型的条件分支指令来完成分支跳转
方法调用和返回指令
方法调用
- invokevirtual:调用对象实例方法,根据对象的实际类型进行分派(虚方法分派)
- invokeinterface:调用接口方法,会在运行时搜索实现这个接口方法的对象,找出适合的方法进行调用
- invokespecial:调用一些需要特殊处理的实例方法,包括构造方法、私有方法和父类方法
- invokestatic:调用static方法
- invokedynamic:在运行时动态解析出调用点限定符所引用的方法并执行,分派逻辑由用户所设定的引导方法决定
方法返回
- ireturn、lreturn、freturn、dreturn、areturn,return(void)
异常处理指令
显式抛出异常的操作(throw语句)都由athrow指令来实现
运行时异常会在其他指令检测到异常时自动抛出
处理异常(catch语句)不由字节码指令实现,而是采用异常表
同步指令
JVM通过管程(Monitor)可以支持方法级的同步和方法内部一段指令序列的同步
方法级的同步无须通过字节码指令来控制,当方法调用时检查ACC_SYNCHRONIZED,如果设置了,线程就要先持有管程才能执行方法,方法完成时释放管程
同步一段指令序列由synchronized语句块表示,monitorenter和monitorexit实现
大全