小注:去年在看《深入解析jvm》書的時候做的一些記錄,同時參考了《java虛拟機規範》。隻是對指令的一些列舉,加入了一些自己的了解。可以用來查詢。
java源碼在運作之前都要編譯成為位元組碼格式(如.class檔案),然後由classloader将位元組碼載入運作。在位元組碼檔案中,指令代碼隻是其中的一部分,裡面還記錄了位元組碼檔案的編譯版本、常量池、通路權限、所有成員變量和成員方法等資訊(詳見java位元組碼格式詳解)。本文主要簡單介紹不同java指令的功能以及在代碼中如何解析二進制指令。
java指令是基于棧的體系結構,大部分的指令預設的操作數在棧中。映像中arm是基于寄存器的操作指令,而x86好像是混合寄存器和存儲器的,發現基于棧的操作指令确實簡單,學起來很快。不過不知道這種操作的效率怎麼樣,以我自己的推測應該是不太好的。對這方面不太了解,随便扯幾句。
java總共有200多條指令,不過很多都是重複的。我的了解,網絡是java一個非常重要的特性,而且java在設計之初就認為位元組碼是要在網絡中傳輸的,為了減少網絡傳輸流量,位元組碼就要盡量設計精簡、緊湊。因而java增加了很多重複指令,比如盡量減少操作數,因而我們會發現java的很多指令都是沒有操作數的;并且指令中的操作數基本上都是當無法将值放到棧中的資料,比如局部變量的索引号和常量池中的索引号。
還有一點需要注意的是,在運作過程中,所有boolean、byte、char、short都是以int類型值存在,因而對這些類型的指令操作很少。然而好像sun實作的虛拟機中。這些類型的數組據說不是以int類型的形式儲存的,這個很奇怪。我的了解,以字對齊方式的操作效率會比較高,因而做了這種轉換,以空間換時間。
常量入棧指令
操作碼(助記符)
操作數
描述(棧指操作數棧)
aconst_null
null值入棧。
iconst_m1
-1(int)值入棧。
iconst_0
0(int)值入棧。
iconst_1
1(int)值入棧。
iconst_2
2(int)值入棧。
iconst_3
3(int)值入棧。
iconst_4
4(int)值入棧。
iconst_5
5(int)值入棧。
lconst_0
0(long)值入棧。
lconst_1
1(long)值入棧。
fconst_0
0(float)值入棧。
fconst_1
1(float)值入棧。
fconst_2
2(float)值入棧。
dconst_0
0(double)值入棧。
dconst_1
1(double)值入棧。
bipush
valuebyte
valuebyte值帶符号擴充成int值入棧。
sipush
valuebyte1
valuebyte2
(valuebyte1 << 8) | valuebyte2 值帶符号擴充成int值入棧。
ldc
indexbyte1
常量池中的常量值(int, float, string reference, object reference)入棧。
ldc_w
indexbyte2
常量池中常量(int, float, string reference, object reference)入棧。
ldc2_w
常量池中常量(long, double)入棧。
局部變量值轉載到棧中指令
(wide)aload
indexbyte
從局部變量indexbyte中裝載引用類型值入棧。
aload_0
從局部變量0中裝載引用類型值入棧。
aload_1
從局部變量1中裝載引用類型值入棧。
aload_2
從局部變量2中裝載引用類型值入棧。
aload_3
從局部變量3中裝載引用類型值入棧。
(wide)iload
從局部變量indexbyte中裝載int類型值入棧。
iload_0
從局部變量0中裝載int類型值入棧。
iload_1
從局部變量1中裝載int類型值入棧。
iload_2
從局部變量2中裝載int類型值入棧。
iload_3
從局部變量3中裝載int類型值入棧。
(wide)lload
從局部變量indexbyte中裝載long類型值入棧。
lload_0
lload_1
lload_2
lload_3
(wide)fload
從局部變量indexbyte中裝載float類型值入棧。
fload_0
從局部變量0中裝載float類型值入棧。
fload_1
從局部變量1中裝載float類型值入棧。
fload_2
從局部變量2中裝載float類型值入棧。
fload_3
從局部變量3中裝載float類型值入棧。
(wide)dload
從局部變量indexbyte中裝載double類型值入棧。
dload_0
從局部變量0中裝載double類型值入棧。
dload_1
從局部變量1中裝載double類型值入棧。
dload_2
從局部變量2中裝載double類型值入棧。
dload_3
從局部變量3中裝載double類型值入棧。
aaload
從引用類型數組中裝載指定項的值。
iaload
從int類型數組中裝載指定項的值。
laload
從long類型數組中裝載指定項的值。
faload
從float類型數組中裝載指定項的值。
daload
從double類型數組中裝載指定項的值。
baload
從boolean類型數組或byte類型數組中裝載指定項的值(先轉換為int類型值,後壓棧)。
caload
從char類型數組中裝載指定項的值(先轉換為int類型值,後壓棧)。
saload
從short類型數組中裝載指定項的值(先轉換為int類型值,後壓棧)。
将棧頂值儲存到局部變量中指令
(wide)astore
将棧頂引用類型值儲存到局部變量indexbyte中。
astroe_0
将棧頂引用類型值儲存到局部變量0中。
astore_1
将棧頂引用類型值儲存到局部變量1中。
astore_2
将棧頂引用類型值儲存到局部變量2中。
astore_3
将棧頂引用類型值儲存到局部變量3中。
(wide)istore
将棧頂int類型值儲存到局部變量indexbyte中。
istore_0
将棧頂int類型值儲存到局部變量0中。
istore_1
将棧頂int類型值儲存到局部變量1中。
istore_2
将棧頂int類型值儲存到局部變量2中。
istore_3
将棧頂int類型值儲存到局部變量3中。
(wide)lstore
将棧頂long類型值儲存到局部變量indexbyte中。
lstore_0
将棧頂long類型值儲存到局部變量0中。
lstore_1
将棧頂long類型值儲存到局部變量1中。
lstore_2
将棧頂long類型值儲存到局部變量2中。
lstroe_3
将棧頂long類型值儲存到局部變量3中。
(wide)fstore
将棧頂float類型值儲存到局部變量indexbyte中。
fstore_0
将棧頂float類型值儲存到局部變量0中。
fstore_1
将棧頂float類型值儲存到局部變量1中。
fstore_2
将棧頂float類型值儲存到局部變量2中。
fstore_3
将棧頂float類型值儲存到局部變量3中。
(wide)dstore
将棧頂double類型值儲存到局部變量indexbyte中。
dstore_0
将棧頂double類型值儲存到局部變量0中。
dstore_1
将棧頂double類型值儲存到局部變量1中。
dstore_2
将棧頂double類型值儲存到局部變量2中。
dstore_3
将棧頂double類型值儲存到局部變量3中。
aastore
将棧頂引用類型值儲存到指定引用類型數組的指定項。
iastore
将棧頂int類型值儲存到指定int類型數組的指定項。
lastore
将棧頂long類型值儲存到指定long類型數組的指定項。
fastore
将棧頂float類型值儲存到指定float類型數組的指定項。
dastore
将棧頂double類型值儲存到指定double類型數組的指定項。
bastroe
将棧頂boolean類型值或byte類型值儲存到指定boolean類型數組或byte類型數組的指定項。
castore
将棧頂char類型值儲存到指定char類型數組的指定項。
sastore
将棧頂short類型值儲存到指定short類型數組的指定項。
wide指令
wide
使用附加位元組擴充局部變量索引(iinc指令特殊)。
通用(無類型)棧操作指令
nop
空操作。
pop
從棧頂彈出一個字長的資料。
pop2
從棧頂彈出兩個字長的資料。
dup
複制棧頂一個字長的資料,将複制後的資料壓棧。
dup_x1
複制棧頂一個字長的資料,彈出棧頂兩個字長資料,先将複制後的資料壓棧,再将彈出的兩個字長資料壓棧。
dup_x2
複制棧頂一個字長的資料,彈出棧頂三個字長的資料,将複制後的資料壓棧,再将彈出的三個字長的資料壓棧。
dup2
複制棧頂兩個字長的資料,将複制後的兩個字長的資料壓棧。
dup2_x1
複制棧頂兩個字長的資料,彈出棧頂三個字長的資料,将複制後的兩個字長的資料壓棧,再将彈出的三個字長的資料壓棧。
dup2_x2
複制棧頂兩個字長的資料,彈出棧頂四個字長的資料,将複制後的兩個字長的資料壓棧,再将彈出的四個字長的資料壓棧。
swap
交換棧頂兩個字長的資料的位置。java指令中沒有提供以兩個字長為機關的交換指令。
類型轉換指令
i2f
将棧頂int類型值轉換為float類型值。
i2l
将棧頂int類型值轉換為long類型值。
i2d
将棧頂int類型值轉換為double類型值。
f2i
将棧頂float類型值轉換為int類型值。
f2l
将棧頂float類型值轉換為long類型值。
f2d
将棧頂float類型值轉換為double類型值。
l2i
将棧頂long類型值轉換為int類型值。
l2f
将棧頂long類型值轉換為float類型值。
l2d
将棧頂long類型值轉換double類型值。
d2i
将棧頂double類型值轉換為int類型值。
d2f
将棧頂double類型值轉換為float類型值。
d2l
将棧頂double類型值轉換為long類型值。
i2b
将棧頂int類型值截斷成byte類型,後帶符号擴充成int類型值入棧。
i2c
将棧頂int類型值截斷成char類型值,後帶符号擴充成int類型值入棧。
i2s
将棧頂int類型值截斷成short類型值,後帶符号擴充成int類型值入棧。
整數運算
iadd
将棧頂兩int類型數相加,結果入棧。
isub
将棧頂兩int類型數相減,結果入棧。
imul
将棧頂兩int類型數相乘,結果入棧。
idiv
将棧頂兩int類型數相除,結果入棧。
irem
将棧頂兩int類型數取模,結果入棧。
ineg
将棧頂int類型值取負,結果入棧。
ladd
将棧頂兩long類型數相加,結果入棧。
lsub
将棧頂兩long類型數相減,結果入棧。
lmul
将棧頂兩long類型數相乘,結果入棧。
ldiv
将棧頂兩long類型數相除,結果入棧。
lrem
将棧頂兩long類型數取模,結果入棧。
lneg
将棧頂long類型值取負,結果入棧。
(wide)iinc
constbyte
将整數值constbyte加到indexbyte指定的int類型的局部變量中。
浮點運算
fadd
将棧頂兩float類型數相加,結果入棧。
fsub
将棧頂兩float類型數相減,結果入棧。
fmul
将棧頂兩float類型數相乘,結果入棧。
fdiv
将棧頂兩float類型數相除,結果入棧。
frem
将棧頂兩float類型數取模,結果入棧。
fneg
将棧頂float類型值取反,結果入棧。
dadd
将棧頂兩double類型數相加,結果入棧。
dsub
将棧頂兩double類型數相減,結果入棧。
dmul
将棧頂兩double類型數相乘,結果入棧。
ddiv
将棧頂兩double類型數相除,結果入棧。
drem
将棧頂兩double類型數取模,結果入棧。
dneg
将棧頂double類型值取負,結果入棧。
邏輯運算——移位運算
ishl
左移int類型值。
lshl
左移long類型值。
ishr
算術右移int類型值。
lshr
算術右移long類型值。
iushr
邏輯右移int類型值。
lushr
邏輯右移long類型值。
邏輯運算——按位布爾運算
iand
對int類型按位與運算。
land
對long類型的按位與運算。
ior
對int類型的按位或運算。
lor
對long類型的按位或運算。
ixor
對int類型的按位異或運算。
lxor
對long類型的按位異或運算。
控制流指令——條件跳轉指令
ifeq
branchbyte1
branchbyte2
若棧頂int類型值為0則跳轉。
ifne
若棧頂int類型值不為0則跳轉。
iflt
若棧頂int類型值小于0則跳轉。
ifle
若棧頂int類型值小于等于0則跳轉。
ifgt
若棧頂int類型值大于0則跳轉。
ifge
若棧頂int類型值大于等于0則跳轉。
if_icmpeq
若棧頂兩int類型值相等則跳轉。
if_icmpne
若棧頂兩int類型值不相等則跳轉。
if_icmplt
若棧頂兩int類型值前小于後則跳轉。
if_icmple
若棧頂兩int類型值前小于等于後則跳轉。
if_icmpgt
若棧頂兩int類型值前大于後則跳轉。
if_icmpge
若棧頂兩int類型值前大于等于後則跳轉。
ifnull
若棧頂引用值為null則跳轉。
ifnonnull
若棧頂引用值不為null則跳轉。
if_acmpeq
若棧頂兩引用類型值相等則跳轉。
if_acmpne
若棧頂兩引用類型值不相等則跳轉。
控制流指令——比較指令
lcmp
比較棧頂兩long類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧。
fcmpl
比較棧頂兩float類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧;有nan存在,-1入棧。
fcmpg
dcmpl
比較棧頂兩double類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧;有nan存在,-1入棧。
dcmpg
控制流指令——無條件跳轉指令
goto
無條件跳轉到指定位置。
goto_w
branchbyte3
branchbyte4
無條件跳轉到指定位置(寬索引)。
控制流指令——表跳轉指令
tableswitch
<0-3bytepad>
defaultbyte1
defaultbyte2
defaultbyte3
defaultbyte4
lowbyte1
lowbyte2
lowbyte3
lowbyte4
highbyte1
highbyte2
highbyte3
highbyte4
jump offsets...
通過索引通路跳轉表,并跳轉。
lookupswitch
npairs1
npairs2
npairs3
npairs4
match offsets
通過鍵值通路跳轉表,并跳轉。
控制流指令——異常和finally
athrow
抛出異常。
jsr
跳轉到子例程式。
jsr_w
跳轉到子例程式(寬索引)。
(wide)ret
傳回子例程式。
對象操作指令
new
建立新的對象執行個體。
checkcast
類型強轉。
instanceof
判斷類型。
getfield
擷取對象字段的值。
putfield
給對象字段指派。
getstatic
擷取靜态字段的值。
putstatic
給靜态字段指派。
數組操作指令
newarray
atype
建立type類型的數組。
anewarray
建立引用類型的數組。
arraylength
擷取一維數組的長度。
multianewarray
dimension
建立dimension次元的數組。
方法調用指令
invokespecial
編譯時方法綁定調用方法。
invokevirtual
運作時方法綁定調用方法。
invokestatic
調用靜态方法。
invokeinterface
count
調用接口方法。
方法傳回指令
ireturn
傳回int類型值。
lreturn
傳回long類型值。
freturn
傳回float類型值。
dreturn
傳回double類型值。
areturn
傳回引用類型值。
return
void函數傳回。
線程同步指令
monitorenter
進入并獲得對象螢幕。
monitorexit
釋放并退出對象螢幕。