1. 程式人生 > >Java二進制指令代碼解析

Java二進制指令代碼解析

pos 無法 兩個 ade ceo default val center 時間

http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html

http://blog.csdn.net/sum_rain/article/details/39892219

http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html

Java二進制指令代碼解析

小註:去年在看《深入解析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類型數相乘,結果入棧。

idiv

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

irem

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

ineg

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

ladd

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

lsub

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

lmul

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

ldiv

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

lrem

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

lneg

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

(wide)iinc

indexbyte

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

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

釋放並退出對象監視器。

參考《深入解析JVM》 2010年10月6日

Java二進制指令代碼解析