JVM指令
本篇指令码表,参考自ASM文档手册,如果你对asm感兴趣,可到ASM官网下载手册学习。
一、本地变量操作指令(I,L,F,D,A这些前缀表示对int,long,float,double,引用进行操作)
本地变量指令集 | 指令 | 意义 | ILOAD_n(0~3), LLOAD_n(0~3), FLOAD_n(0~3), DLOAD_n(0~3) 超过三的 直接 xLoad n,如ILOAD 4,LLOAD 5 | 将局部变量表中第n个槽的(int|long|float|double)类型变量推送到操作数栈 | ALOAD_n(0~3) 超过3的 ALOAD n,如:ALOAD 5 | 将引用类型的局部变量第n个槽的推送到操作数栈 | ISTORE_n(0~3), LSTORE_n(0~3), FSTORE_n(0~3), DSTORE_n(0~3) 超过三的xSTORE n | 将操作数栈顶的(int|long|float|double)类型值弹出存到局部变量表的第n个槽中 | ASTORE_n(0~3) 超过3的 ASTORE n | 将栈顶引用类型的值存到局部变量表中的第n个槽中 |
IINC var incr 将局部变量表中的第var个变量增加incr,并把新值存到局部变量表
本地变量操作表对应的下标是从0开始的,比如下面一段程序
public void print(int age) {
int a = age;
a++;
}
对应的字节码文件
stack=1, locals=3, args_size=2//这里的参数为什么是2,因为参数里面有个this,这个this是隐藏的,在JVM中是以参数的形式传递进去的 iload_1//将局部变量表中的第1个槽,也就是age这个值,0是this,压入操作数栈栈顶
istore_2//将操作数栈顶的值,这里就是age,存到局部变量表的第二个槽,也就是a
iinc 2, 1//将局部变量表中的第二个槽的a加1
return//方法返回
注意,如果局部变量中有long或者double类型的值,那么会占用局部变量两个槽,如有局部变量int age,long l, double d, short s, byte b,那么对应的槽应该是1,2,4,6,7
byte,short,char,int,boolean类型的操作指令统一使用ILOAD或者ISTORE这些指令
二、栈操作指令
指令 栈操作前 栈操作后
POP | ... , v | ... (v被弹出) | POP2 | ... , v1 , v2 | ... (v1和v2被弹出) | ... , w | ... (w表示占用两个槽的变量,如long,double之类) | DUP | ... , v | ... , v , v (复制一份) | DUP2 | ... , v1 , v2 | ... , v1 , v2 , v1 , v2 (复制栈中的两个值) | ... , w | ... , w, w (复制一个long,double型的) | SWAP | ... , v1 , v2 | ... , v2 , v1 交换 | DUP_X1 | ... , v1 , v2 | ... , v2 , v1 , v2 复制栈顶值v2,并弹出v1,v2,然后压入v1,v2 |
DUP_X2 | ... , v1 , v2 , v3 | ... , v3 , v1 , v2 , v3 复制v3,并将弹出的3个值入栈 | ... , w , v | ... , v , w , v 复制v,并将复制的两个值入栈(W占两槽) | DUP2_X1 | ... , v1 , v2 , v3 | ... , v2 , v3 , v1 , v2 , v3 复制两个值,并将弹出的3个值入栈 | ... , v , w | ... , w , v , w 复制2个值,并将弹出的两个值入栈,w占两个槽 | DUP2_X2 | ... , v1 , v2 , v3 , v4 | ... , v3 , v4 , v1 , v2 , v3 , v4 复制2值,将弹出的4个值入栈 | ... , w , v1 , v2 | ... , v1 , v2 , w , v1 , v2 复制2值,将弹出的三个值入栈 | .... , v1 , v2 , w | ... , w , v1 , v2 , w 复制1个值,将弹出的3个值入栈 | ... , w1 , w2 | ... , w2 , w1 , w2 复制1个值,将弹出的1个值入栈 |
举个例子
public void print(int age, String name) {
this.age = age;
this.name = name;
}
对应的字节码指令
aload_0 //将this入栈
dup //复制一个this
aload_1 //将age入栈
putfield #n //给age复制,这里的n表示一个数字,#n表示索引,对应常量池中的常量
aload_2 //将name入栈
putfield #n //给name复制
三、常量操作
ICONST_n (−1 ≤ n ≤ 5) | ... | ... , n 将整型常量n入栈 | LCONST_n (0 ≤ n ≤ 1) | ... | ... , nL 将长整型常量n入栈 | FCONST_n (0 ≤ n ≤ 2) | ... | ... , nF 将float常量入栈 | DCONST_n (0 ≤ n ≤ 1) | ... | ... , nD 将double常量入栈 | BIPUSH b, −128 ≤ b < 127 | ... | ... , b 将byte常量入栈 | SIPUSH s, −32768 ≤ s < 32767 | ... | ... , s 将短整型入栈 | LDC cst (int, float, long, double, String or Type) | ... | ... , cst 将常量池中值入栈 | ACONST_NULL | ... | ... , null 将null值入栈 |
如:public void print(){
int a1 = 1; //ICONST_1将1入栈
//ISTORE_1 将1存入局部变量表1中,即a1
int a2 = 10; //BIPUSH 10
//ISTORE 2
int a3 = 100; // SIPUSH 100
//ISTORE 3
float a4 = 123f; //LDC #4这个#4是引用了常量池里的值,123
//FLOAD 4
}
四、算术和逻辑操作指令
IADD, LADD, FADD, DADD | ... , a , b | ... , a + b 将栈顶的两个值相加,并把结果入栈 | ISUB, LSUB, FSUB, DSUB | ... , a , b | ... , a - b | IMUL, LMUL, FMUL, DMUL | ... , a , b | ... , a * b | IDIV, LDIV, FDIV, DDIV | ... , a , b | ... , a / b | IREM, LREM, FREM, DREM | ... , a , b | ... , a b | INEG, LNEG, FNEG, DNEG | ... , a | ... , -a | ISHL, LSHL | ... , a , n | ... , a << n | ISHR, LSHR | ... , a , n | ... , a >> n | IUSHR, LUSHR | ... , a , n | ... , a >>> n | IAND, LAND | ... , a , b | ... , a & b | IOR, LOR | ... , a , b | ... , a | b | IXOR, LXOR | ... , a , b | ... , a ^ b | LCMP | ... , a , b | ... , a == b ? 0 : (a < b ? -1 : 1) |
FCMPL, FCMPG | ... , a , b | ... , a == b ? 0 : (a < b ? -1 : 1) | DCMPL, DCMPG | ... , a , b | ... , a == b ? 0 : (a < b ? -1 : 1) |
五、转换
I2B | ... , i | ... , (byte) i | I2C | ... , i | ... , (char) i | I2S | ... , i | ... , (short) i | L2I, F2I, D2I | ... , a | ... , (int) a | I2L, F2L, D2L | ... , a | ... , (long) a | I2F, L2F, D2F | ... , a | ... , (float) a | I2D, L2D, F2D | ... , a | ... , (double) a | CHECKCAST class | ... , o | ... , (class) o |
六、对象,字段,方法操作
NEW class | ... | ... , new class | GETFIELD c f t | ... , o | ... , o.f | PUTFIELD c f t | ... , o , v | ... | GETSTATIC c f t | ... | ... , c.f | PUTSTATIC c f t | ... , v | ... | INVOKEVIRTUAL c m t | ... , o , v1 , ... , vn | ... , o.m(v1, ... vn) | INVOKESPECIAL c m t | ... , o , v1 , ... , vn | ... , o.m(v1, ... vn) | INVOKESTATIC c m t | ... , v1 , ... , vn | ... , c.m(v1, ... vn) | INVOKEINTERFACE c m t | ... , o , v1 , ... , vn | ... , o.m(v1, ... vn) | INVOKEDYNAMIC m t bsm | ... , o , v1 , ... , vn | ... , o.m(v1, ... vn) | INSTANCEOF class | ... , o | ... , o instanceof class | MONITORENTER | ... , o | ... | MONITOREXIT | ... , o | ... |
七、数组操作
NEWARRAY type (for any primitive type) new基本类型的数组 | ... , n 数组长度 | ... , new type[n] new出来的数组引用 | ANEWARRAY class new引用类型的数组 | ... , n 数组长度 | ... , new class[n] | MULTIANEWARRAY [...[t n 多维数组 | ... , i1 , ... , in 各维长度 | ... , new t[i1]...[in]... |
BALOAD, CALOAD, SALOAD 将指定下标的值入栈 | ... , o , i i下标,o数组 | ... , o[i] | IALOAD, LALOAD, FALOAD, DALOAD | ... , o , i | ... , o[i] | AALOAD | ... , o , i | ... , o[i] | BASTORE, CASTORE, SASTORE | ... , o , i , j | ... | IASTORE, LASTORE, FASTORE, DASTORE | ... , o , i , a | ... | AASTORE | ... , o , i , p | ... | ARRAYLENGTH | ... , o | ... , o.length |
八、跳转语句
IFEQ | ... , i | ... | jump if i == 0 | IFNE | ... , i | ... | jump if i != 0 | IFLT | ... , i | ... | jump if i < 0 | IFGE | ... , i | ... | jump if i >= 0 | IFGT | ... , i | ... | jump if i > 0 | IFLE | ... , i | ... | jump if i <= 0 | IF_ICMPEQ | ... , i , j | ... | jump if i == j | IF_ICMPNE | ... , i , j | ... | jump if i != j | IF_ICMPLT | ... , i , j | ... | jump if i < j | IF_ICMPGE | ... , i , j | ... | jump if i >= j | IF_ICMPGT | ... , i , j | ... | jump if i > j | IF_ICMPLE | ... , i , j | ... | jump if i <= j | IF_ACMPEQ | ... , o , p | ... | jump if o == p | IF_ACMPNE | ... , o , p | ... | jump if o != p | IFNULL | ... , o | ... | jump if o == null | IFNONNULL | ... , o | ... | jump if o != null | GOTO | ... | ... | jump always | TABLESWITCH | ... , i | ... | jump always | LOOKUPSWITCH | ... , i | ... | jump always |
九、return
IRETURN, LRETURN, FRETURN, DRETURN | ... , a | | ARETURN | ... , o | | RETURN | ... | | ATHROW | ... , o | |
十、泛型
如:public class Test<T> ==> <T:Ljava/lang/Object;>
public class Test<T> extends ArrayList<E> ==> <T:Ljava/lang/Object;>Ljava/util/ArrayList<TE;>;
static <T> Class<? extends T> m (int n) ==> <T:Ljava/lang/Object;>(I)Ljava/lang/Class<+TT;>;
List<E> ==> Ljava/util/List<TE;>;
List<?> ==> Ljava/util/List<*>;
List<? extends Number> ==> Ljava/util/List<+Ljava/lang/Number;>;
List<? super Integer> ==> Ljava/util/List<-Ljava/lang/Integer;>;
List<List<String>[]> ==> Ljava/util/List<[Ljava/util/List<Ljava/lang/String;>;>;
HashMap<K, V>.HashIterator<K> ==> Ljava/util/HashMap<TK;TV;>.HashIterator<TK;>;
注意:如果是定义定义泛型,比如class Test<T>,方法中的<T>这类T,在写泛型签名的时候应当写成T:Ljava/lang/Object;而不是TT;在其他非定义泛型的位置,写成TT;
十一、描述符表
java类型 | 类型描述符 | boolean | Z | char | C | byte | B | short | S | int | I | long | J | float | F | double | D | Object | Ljava/lang/Object; | int[] | [I | Object[][] | [[Ljava/lang/Object; |
十二、方法描述符
方法 | 方法描述符 | void m(int i, float f) | (IF)V | int m(Object o) | (Ljava/lang/Object;)I | int[] m(int i, String s) | (ILjava/lang/String;)I | Object m(int[] i) | ([I)Ljava/lang/Object; | int[] m(int i, String s) | (ILjava/lang/String;)I | Object m(int[] i) | ([I)Ljava/lang/Object; |
|