JVM总结(六):字节码指令

 字节码指令简介

Java虚拟机的指令由一个字节长度的,代表着某种特定操作含义的数字(操作码)以及跟随其后的零至多个代表此操作所需参数(操作数)而构成。由于Java虚拟机采用面向操作数栈而不是寄存器的架构,所以大多数的指令都不包含操作数,只有一个操作码。

字节码与数据类型

 

 Class文件中对于Java的类型描述:

加载和存储指令

加载和存储指令是用于将数据在栈桢中的局部变量表和操作数栈之间来回传输。

  • 将一个局部变量加载到操作栈: ILOAD, LLOAD, FLOAD, DLOAD,ALOAD 及对应的X_<N>
  • 将一个数值从操作数栈存储到局部变量表:ISTORE,LSTORE,FSTORE,DSTORE,ASTORE 及对应的X_<N>
  • 将一个常量加载到操作数栈:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_m1,iconst_<i>,lconst_<l>,fconst_<f>,dconst_<d>
  • 扩充局部变量表的访问索引的指令:wide

运算指令

运算或算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。对于byte,short,char boolean类型,使用int类型的指令代替

  • 加法指令:iadd,ladd,fadd,dadd
  • 减法指令:isub,lsub,fsub,dsub
  • 乘法指令:imul,lmul,fmul,dmul
  • 除法指令:idiv,ldiv,fidv,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

Java虚拟机规范没有明确定义过整型数据溢出的具体运算结果,仅规定了在处理整型数据时,只有除法指令(idiv和ldiv)以及求余指令(irem he  lrem )中当出现除数为零时会导致虚拟机抛出ArithmeticException异常,其余任何整数运行不应该抛出运行时异常。

类型转换指令

类型转换指令可以将两种不同的数值类型进行相互转换。

  • 宽化类型转换(小范围到大范围的安全转换)

  int->long,float,double
  long-> float,double
  float->double

  • 窄化类型转换(必须显式地使用转化指令)

  指令如下:i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f
  窄化指令可能会导致转换结果产生不同的正负号,不同的数量级,精度丢失。

  将一个浮点值窄化传唤为整数类型T(int或long)的时候,将遵循以下转换规则:

  1.   如果浮点数是NaN,那转换结果就是0
  2.   如果浮点值不是无穷大的话,浮点值使用IEEE 754的向零舍入模式取整,获得整数值v,如果v在目标类型T的表示范围内,那转换结果就是v.
  3.   否则,将数据v的符合,转换为T所能表示的最大或最小正数。

对象创建与访问指令

  • 创建类实例的指令:new
  • 创建数组的指令:newarray,anewarray,multianewarray
  • 访问类字段(static字段)和实例字段(非static字段)的指令: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

控制转移指令

该指令可以让java虚拟机有条件或无条件地从指定的位置指令而不是控制转移指令的下一条指令继续执行程序,从概念模型上理解,可以认为控制转移指令就是在有条件或无条件地修改PC寄存器的值。对于byte,short,char boolean类型,使用int类型的指令代替。

  • 条件分支: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

方法调用和返回指令

方法调用:

  • invokevirtual指令用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这是Java语音中最常见的方法分派方式。
  • invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出合适的方法进行调用。
  • invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法,私有方法和父类方法。
  • invokestatic指令用于调用类方法(static方法)
  • invokedynamic指令用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法,前面4条调用指令的分派逻辑都固化在Java虚拟机内部,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。

放回指令:

  ireturn lreturn freturn dreturn areturn

异常指令和同步指令

athrow 显式抛出异常

monitorenter和monitorexit来支持synchronized关键字的同步语义

 

posted @ 2018-05-08 14:07  Mr.years  阅读(146)  评论(0)    收藏  举报