JVM指令java
本篇指令碼錶,參考自ASM文檔手冊,若是你對asm感興趣,可到ASM官網下載手冊學習。數組
1、本地變量操做指令(I,L,F,D,A這些前綴表示對int,long,float,double,引用進行操做)學習
本地變量指令集this |
指令spa |
意義htm |
ILOAD_n(0~3), LLOAD_n(0~3), FLOAD_n(0~3), DLOAD_n(0~3)對象 超過三的 直接 xLoad n,如ILOAD 4,LLOAD 5blog |
將局部變量表中第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這些指令
2、棧操做指令
指令 棧操做前 棧操做後
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複製
3、常量操做
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
}
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) |
5、轉換
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 |
6、對象,字段,方法操做
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 |
... |
7、數組操做
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 |
8、跳轉語句
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 |
9、return
IRETURN, LRETURN, FRETURN, DRETURN |
... , a |
|
ARETURN |
... , o |
|
RETURN |
... |
|
ATHROW |
... , o |
|
10、泛型
如: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;
11、描述符表
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; |
12、方法描述符
方法 |
方法描述符 |
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; |
|