2025-02-10

小註:去年在看《深入解析JVM》書的時候做的一些記錄,同時參考瞭《Java虛擬機規范》。隻是對指令的一些列舉,加入瞭一些自己的理解。可以用來查詢。

Java二進制指令代碼解析
Java源碼在運行之前都要編譯成為字節碼格式(如.class文件),然後由ClassLoader將字節碼載入運行。在字節碼文件中,指令代碼隻是其中的一部分,裡面還記錄瞭字節碼文件的編譯版本、常量池、訪問權限、所有成員變量和成員方法等信息(詳見Java字節碼格式詳解)。本文主要簡單介紹不同Java指令的功能以及在代碼中如何解析二進制指令。

Java指令是基於棧的體系結構,大部分的指令默認的操作數在棧中。映像中ARM是基於寄存器的操作指令,而x86好像是混合寄存器和存儲器的,發現基於棧的操作指令確實簡單,學起來很快。不過不知道這種操作的效率怎麼樣,以我自己的推測應該是不太好的。對這方面不太瞭解,隨便扯幾句。

Java總共有200多條指令,不過很多都是重復的。我的理解,網絡是Java一個非常重要的特性,而且Java在設計之初就認為字節碼是要在網絡中傳輸的,為瞭減少網絡傳輸流量,字節碼就要盡量設計精簡、緊湊。因而Java增加瞭很多重復指令,比如盡量減少操作數,因而我們會發現Java的很多指令都是沒有操作數的;並且指令中的操作數基本上都是當無法將值放到棧中的數據,比如局部變量的索引號和常量池中的索引號。

還有一點需要註意的是,在運行過程中,所有boolean、byte、char、short都是以int類型值存在,因而對這些類型的指令操作很少。然而好像sun實現的虛擬機中。這些類型的數組據說不是以int類型的形式保存的,這個很奇怪。我的理解,以字對齊方式的操作效率會比較高,因而做瞭這種轉換,以空間換時間。

Java指令集(按功能分類)

 

常量入棧指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

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

indexbyte1

indexbyte2

常量池中常量(int, float, string reference, object reference)入棧。

ldc2_w

indexbyte1

indexbyte2

常量池中常量(long, double)入棧。

 

局部變量值轉載到棧中指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

(wide)aload

indexbyte

從局部變量indexbyte中裝載引用類型值入棧。

aload_0

 

從局部變量0中裝載引用類型值入棧。

aload_1

 

從局部變量1中裝載引用類型值入棧。

aload_2

 

從局部變量2中裝載引用類型值入棧。

aload_3

 

從局部變量3中裝載引用類型值入棧。

(wide)iload

indexbyte

從局部變量indexbyte中裝載int類型值入棧。

iload_0

 

從局部變量0中裝載int類型值入棧。

iload_1

 

從局部變量1中裝載int類型值入棧。

iload_2

 

從局部變量2中裝載int類型值入棧。

iload_3

 

從局部變量3中裝載int類型值入棧。

(wide)lload

indexbyte

從局部變量indexbyte中裝載long類型值入棧。

lload_0

 

從局部變量0中裝載int類型值入棧。

lload_1

 

從局部變量1中裝載int類型值入棧。

lload_2

 

從局部變量2中裝載int類型值入棧。

lload_3

 

從局部變量3中裝載int類型值入棧。

(wide)fload

indexbyte

從局部變量indexbyte中裝載float類型值入棧。

fload_0

 

從局部變量0中裝載float類型值入棧。

fload_1

 

從局部變量1中裝載float類型值入棧。

fload_2

 

從局部變量2中裝載float類型值入棧。

fload_3

 

從局部變量3中裝載float類型值入棧。

(wide)dload

indexbyte

從局部變量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

將棧頂引用類型值保存到局部變量indexbyte中。

astroe_0

 

將棧頂引用類型值保存到局部變量0中。

astore_1

 

將棧頂引用類型值保存到局部變量1中。

astore_2

 

將棧頂引用類型值保存到局部變量2中。

astore_3

 

將棧頂引用類型值保存到局部變量3中。

(wide)istore

indexbyte

將棧頂int類型值保存到局部變量indexbyte中。

istore_0

 

將棧頂int類型值保存到局部變量0中。

istore_1

 

將棧頂int類型值保存到局部變量1中。

istore_2

 

將棧頂int類型值保存到局部變量2中。

istore_3

 

將棧頂int類型值保存到局部變量3中。

(wide)lstore

indexbyte

將棧頂long類型值保存到局部變量indexbyte中。

lstore_0

 

將棧頂long類型值保存到局部變量0中。

lstore_1

 

將棧頂long類型值保存到局部變量1中。

lstore_2

 

將棧頂long類型值保存到局部變量2中。

lstroe_3

 

將棧頂long類型值保存到局部變量3中。

(wide)fstore

indexbyte

將棧頂float類型值保存到局部變量indexbyte中。

fstore_0

 

將棧頂float類型值保存到局部變量0中。

fstore_1

 

將棧頂float類型值保存到局部變量1中。

fstore_2

 

將棧頂float類型值保存到局部變量2中。

fstore_3

 

將棧頂float類型值保存到局部變量3中。

(wide)dstore

indexbyte

將棧頂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類型數相乘,結果入棧。

ip

 

將棧頂兩int類型數相除,結果入棧。

irem

 

將棧頂兩int類型數取模,結果入棧。

ineg

 

將棧頂int類型值取負,結果入棧。

ladd

 

將棧頂兩long類型數相加,結果入棧。

lsub

 

將棧頂兩long類型數相減,結果入棧。

lmul

 

將棧頂兩long類型數相乘,結果入棧。

lp

 

將棧頂兩long類型數相除,結果入棧。

lrem

 

將棧頂兩long類型數取模,結果入棧。

lneg

 

將棧頂long類型值取負,結果入棧。

(wide)iinc

indexbyte

constbyte

將整數值constbyte加到indexbyte指定的int類型的局部變量中。

 

浮點運算

操作碼(助記符)

操作數

描述(棧指操作數棧)

fadd

 

將棧頂兩float類型數相加,結果入棧。

fsub

 

將棧頂兩float類型數相減,結果入棧。

fmul

 

將棧頂兩float類型數相乘,結果入棧。

fp

 

將棧頂兩float類型數相除,結果入棧。

frem

 

將棧頂兩float類型數取模,結果入棧。

fneg

 

將棧頂float類型值取反,結果入棧。

dadd

 

將棧頂兩double類型數相加,結果入棧。

dsub

 

將棧頂兩double類型數相減,結果入棧。

dmul

 

將棧頂兩double類型數相乘,結果入棧。

dp

 

將棧頂兩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

branchbyte1

branchbyte2

若棧頂int類型值不為0則跳轉。

iflt

branchbyte1

branchbyte2

若棧頂int類型值小於0則跳轉。

ifle

branchbyte1

branchbyte2

若棧頂int類型值小於等於0則跳轉。

ifgt

branchbyte1

branchbyte2

若棧頂int類型值大於0則跳轉。

ifge

branchbyte1

branchbyte2

若棧頂int類型值大於等於0則跳轉。

if_icmpeq

branchbyte1

branchbyte2

若棧頂兩int類型值相等則跳轉。

if_icmpne

branchbyte1

branchbyte2

若棧頂兩int類型值不相等則跳轉。

if_icmplt

branchbyte1

branchbyte2

若棧頂兩int類型值前小於後則跳轉。

if_icmple

branchbyte1

branchbyte2

若棧頂兩int類型值前小於等於後則跳轉。

if_icmpgt

branchbyte1

branchbyte2

若棧頂兩int類型值前大於後則跳轉。

if_icmpge

branchbyte1

branchbyte2

若棧頂兩int類型值前大於等於後則跳轉。

ifnull

branchbyte1

branchbyte2

若棧頂引用值為null則跳轉。

ifnonnull

branchbyte1

branchbyte2

若棧頂引用值不為null則跳轉。

if_acmpeq

branchbyte1

branchbyte2

若棧頂兩引用類型值相等則跳轉。

if_acmpne

branchbyte1

branchbyte2

若棧頂兩引用類型值不相等則跳轉。

 

控制流指令——比較指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

lcmp

 

比較棧頂兩long類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧。

fcmpl

 

比較棧頂兩float類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧;有NaN存在,-1入棧。

fcmpg

 

比較棧頂兩float類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧;有NaN存在,-1入棧。

dcmpl

 

比較棧頂兩double類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧;有NaN存在,-1入棧。

dcmpg

 

比較棧頂兩double類型值,前者大,1入棧;相等,0入棧;後者大,-1入棧;有NaN存在,-1入棧。

 

控制流指令——無條件跳轉指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

goto

branchbyte1

branchbyte2

無條件跳轉到指定位置。

goto_w

branchbyte1

branchbyte2

branchbyte3

branchbyte4

無條件跳轉到指定位置(寬索引)。

 

控制流指令——表跳轉指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

tableswitch

<0-3bytepad>

defaultbyte1

defaultbyte2

defaultbyte3

defaultbyte4

lowbyte1

lowbyte2

lowbyte3

lowbyte4

highbyte1

highbyte2

highbyte3

highbyte4

jump offsets…

通過索引訪問跳轉表,並跳轉。

lookupswitch

<0-3bytepad>

defaultbyte1

defaultbyte2

defaultbyte3

defaultbyte4

npairs1

npairs2

npairs3

npairs4

match offsets

通過鍵值訪問跳轉表,並跳轉。

 

控制流指令——異常和finally

操作碼(助記符)

操作數

描述(棧指操作數棧)

athrow

 

拋出異常。

jsr

branchbyte1

branchbyte2

跳轉到子例程序。

jsr_w

branchbyte1

branchbyte2

branchbyte3

branchbyte4

跳轉到子例程序(寬索引)。

(wide)ret

indexbyte

返回子例程序。

 

對象操作指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

new

indexbyte1

indexbyte2

創建新的對象實例。

checkcast

indexbyte1

indexbyte

類型強轉。

instanceof

indexbyte1

indexbyte2

判斷類型。

getfield

indexbyte1

indexbyte2

獲取對象字段的值。

putfield

indexbyte1

indexbyte2

給對象字段賦值。

getstatic

indexbyte1

indexbyte2

獲取靜態字段的值。

putstatic

indexbyte1

indexbyte2

給靜態字段賦值。

 

數組操作指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

newarray

atype

創建type類型的數組。

anewarray

indexbyte1

indexbyte2

創建引用類型的數組。

arraylength

 

獲取一維數組的長度。

multianewarray

indexbyte1

indexbyte2

dimension

創建dimension維度的數組。

 

方法調用指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

invokespecial

indexbyte1

indexbyte2

編譯時方法綁定調用方法。

invokevirtual

indexbyte1

indexbyte2

運行時方法綁定調用方法。

invokestatic

indexbyte1

indexbyte2

調用靜態方法。

invokeinterface

indexbyte1

indexbyte2

count

0

調用接口方法。

 

方法返回指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

ireturn

 

返回int類型值。

lreturn

 

返回long類型值。

freturn

 

返回float類型值。

dreturn

 

返回double類型值。

areturn

 

返回引用類型值。

return

 

void函數返回。

 

線程同步指令

操作碼(助記符)

操作數

描述(棧指操作數棧)

monitorenter

 

進入並獲得對象監視器。

monitorexit

 

釋放並退出對象監視器。

作者“上善若水”
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *