jvm-指令集总结
类型相关
JVM中大多数指令和类型相关,如iload
指令只能操作int类型到操作数栈,两种指令可能有相同的实现。但是有opcodes不同。
下图总结了JVM指令集支持的类型。
我们注意到,大部分操作没有整数类型byte,char,short。没有boolean类型的任何操作。在编译期或运行时,JVM加载byte和short的字面值时,
会扩展为int类型的值;boolean和char的字面值会使用指令扩展为int类型的值,对于的数据中的元素也会做扩展。
load和store指令
load和store命令用于在一个栈帧中的本地变量表和操作栈之间转移值。 load将本地变量表中的值转移到操作栈,store相反。
- load将本地变量表中的值转移到操作栈:
iload
,iload_<n>
等。 - store从操作栈转移到本地变量表:
istore
,istore_<n>
等。 - 将一个常量加载到操作栈:
bipush
,sipush
,ldc
,ldc_w
,ldc2_w
,aconst_null
,iconst_m1
,iconst_<i>
,lconst_<l>
,fconst_<f>
,dconst_<d>
。 - 访问更多的本地变量或更大的操作数:
wide
。
访问对象字段和数组元素的指令也可以和操作栈之间转移数据。
指令iload_<n>
包含了(iload_0,iload_1,iload_2,iload_3),其中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。
类型转换指令
宽化转换包括:i2l, i2f, i2d, l2f, l2d, and f2d。 窄化转换包括:i2b, i2c, i2s, l2i, f2i, f2l, d2i, d2l, and d2f。
对象创建
- 创建一个对象实例:new。
- 创建一个数组实例:newarray, anewarray, multianewarray。
- 访问静态字段:getstatic, putstatic;访问实例字段:getfield, putfield。
- 加载数组元素到操作栈:baload, caload, saload, iaload, laload, faload, daload, aaload。
- 将操作栈的值存储为数组元素:bastore, castore, sastore, iastore, lastore, fastore, dastore, aastore。
- 获取数组长度:arraylength。
- 获取类实例或数组的属性:instanceof,checkcast。
操作栈管理
操作栈的指令包括:pop, pop2, dup, dup2, dup_x1, dup2_x1, dup_x2, dup2_x2, swap。
- dup:复制栈顶部的一个字长的内容。
栈: 前:……,word 后:……,word,word - dup_x1:复制栈顶部一个字长的内容,然后将复制内容插入到栈顶(1+1)个字长下面。
栈: 前:……,word2,word1 后:……,word1,word2,word1 - dup_x2:复制栈顶部一个字长的内容,然后将复制内容插入到栈顶(1+2)个字长下面。
栈: 前:…….,word3,word2,word1 后:…….,word1,word3,word2,word1 - dup2:复制栈顶部长度为两个字长的内容
栈: 前:……,word2,word1 后:……,word2,word1,word2,word1 dup2_x1,dup2_x1 类似。long和double占两个字长,其他类型占一个字长,要注意
控制转换
- 条件分支:ifeq, ifne, iflt, ifle, ifgt, ifge, ifnull, ifnonnull, if_icmpeq, if_icmpne, if_icmplt, if_icmple, if_icmpgt if_icmpge, if_acmpeq, if_acmpne。
- 复合条件分支:tableswitch, lookupswitch。
- 非条件分支:goto, goto_w, jsr, jsr_w, ret。
方法调用和返回
- invokevirtual:调用对象的实例方法。
- invokeinterface:调用接口方法,查找所有被运行时对象实现的方法,并确定对应的方法。
- invokespecial:调用需要特殊处理的实例方法,包括实例初始化方法,private方法,或者父类方法。
- invokestatic:调用静态方法。
- invokedynamic:由用户动态分派调用,会转到bootstrap方法。bootstrap可以动态获取参数类型,然后可以根据类型分配给合适的方法,让 jvm实现动态语言的方法调用。
抛出异常
使用athrow指令。
同步
JVM使用同步monitor支持方法和方法内的指令序列两种同步。
方法级别的同步隐式执行的。一个synchronized方法会在运行时常量池的method_info中被ACC_SYNCHRONIZED
标记。
指令序列的同步通常是使用了synchronized代码块。JVM使用monitorenter
和monitorexit
支持。
monitor的进入和退出是由JVM自动执行的。