位元組碼格式
位元組碼是JVM的機器語言。JVM加載類檔案時,對類中的每個方法,它都會得到一個位元組碼流。這些位元組碼流儲存在JVM的方法區中。在程式運作過程中,當一個方法被調用時,它的位元組碼流就會被執行。根據特定JVM設計者的選擇,它們可以通過解釋的方式,即時編譯(Just-in-time compilation)的方式或其他技術的方式被執行。
方法的位元組碼流就是JVM的指令(instruction)序列。每條指令包含一個單位元組的操作碼(opcode)和0個或多個操作數(operand)。操作碼指明要執行的操作。如果JVM在執行操作前,需要更多的資訊,這些資訊會以0個或多個操作數的方式,緊跟在操作碼的後面。
每種類型的操作碼都有一個助記符(mnemonic)。類似典型的彙編語言風格,Java位元組碼流可以用它們的助記符和緊跟在後面的操作數來表示。例如,下面的位元組碼流可以分解成多個助記符的形式。
-
03 3b
84
00
01 1a
05
68
- // 分解後:
- 03
- istore_0 // 3b
-
0,
1 //
84
00
01
- iload_0 // 1a
- 05
- 68
- istore_0 // 3b
-
goto
-7
位元組碼指令集被設計的很緊湊。除了處理跳表的2條指令以外,所有的指令都以位元組邊界對齊。操作碼的總數很少,一個位元組就能搞定。這最小化了JVM加載前,通過網絡傳輸的類檔案的大小;也使得JVM可以維持很小的實作。
JVM中,所有的計算都是圍繞棧(stack)而展開的。因為JVM沒有存儲任意數值的寄存器(register),所有的操作數在計算開始之前,都必須先壓入棧中。是以,位元組碼指令主要是用來操作棧的。例如,在上面的位元組碼序列中,通過iload_0先把本地變量(local variable)入棧,然後用iconst_2把數字2入棧的方式,來計算本地變量乘以2。兩個整數都入棧之後,imul指令有效的從棧中彈出它們,然後做乘法,最後把運算結果壓入棧中。istore_0指令把結果從棧頂彈出,儲存回本地變量。JVM被設計成基于棧,而不是寄存器的機器,這使得它在如80486寄存器架構不佳的處理器上,也能被高效的實作。
原始類型(primitive types)
JVM支援7種原始資料類型。Java程式員可以聲明和使用這些資料類型的變量,而Java位元組碼,處理這些資料類型。下表列出了這7種原始資料類型:
類型 | 定義 |
byte | 單位元組有符号二進制補碼整數 |
short | 2位元組有符号二進制補碼整數 |
int | 4位元組有符号二進制補碼整數 |
long | 8位元組有符号二進制補碼整數 |
float | 4位元組IEEE 754單精度浮點數 |
double | 8位元組IEEE 754雙精度浮點數 |
char | 2位元組無符号Unicode字元 |
原始資料類型以操作數的方式出現在位元組碼流中。所有長度超過1位元組的原始類型,都以大端(big-endian)的方式儲存在位元組碼流中,這意味着高位位元組出現在低位位元組之前。例如,為了把常量值256(0x0100)壓入棧中,你可以用sipush操作碼,後跟一個短操作數。短操作數會以“01 00”的方式出現在位元組碼流中,因為JVM是大端的。如果JVM是小端(little-endian)的,短操作數将會是“00 01”。
-
17
01
00
- // Dissassembly:
-
256; //
17
01
00
把常量(constants)壓入棧中
很多操作碼都可以把常量壓入棧中。操作碼以3中不同的方式指定入棧的常量值:由操作碼隐式指明,作為操作數跟在操作碼之後,或者從常量池(constant pool)中擷取。
有些操作碼本身就指明了要入棧的資料類型和常量數值。例如,iconst_1告訴JVM把整數1壓入棧中。這種操作碼,是為不同類型而經常入棧的數值而定義的。它們在位元組碼流中隻占用1個位元組,增進了位元組碼的執行效率,并減小了位元組碼流的大小。下表列出了int型和float型的操作碼:
操作碼 | 操作數 | 描述 |
iconst_m1 | (none) | pushes int -1 onto the stack |
iconst_0 | (none) | pushes int 0 onto the stack |
iconst_1 | (none) | pushes int 1 onto the stack |
iconst_2 | (none) | pushes int 2 onto the stack |
iconst_3 | (none) | pushes int 3 onto the stack |
iconst_4 | (none) | pushes int 4 onto the stack |
iconst_5 | (none) | pushes int 5 onto the stack |
fconst_0 | (none) | pushes float 0 onto the stack |
fconst_1 | (none) | pushes float 1 onto the stack |
fconst_2 | (none) | pushes float 2 onto the stack |
下面列出的操作碼處理的int型和float型都是32位的值。Java棧單元(slot)是32位寬的,是以,每次一個int數和float數入棧,它都占用一個單元。下表列出的操作碼處理long型和double型。long型和double型的數值占用64位。每次一個long數或double數被壓入棧中,它都占用2個棧單元。下面的表格,列出了隐含處理long型和double型的操作碼
操作碼 | 操作數 | 描述 |
lconst_0 | (none) | pushes long 0 onto the stack |
lconst_1 | (none) | pushes long 1 onto the stack |
dconst_0 | (none) | pushes double 0 onto the stack |
dconst_1 | (none) | pushes double 1 onto the stack |
另外還有一個隐含入棧常量值的操作碼,aconst_null,它把空對象(null object)的引用(reference)壓入棧中。對象引用的格式取決于JVM實作。對象引用指向垃圾收集堆(garbage-collected heap)中的對象。空對象引用,意味着一個變量目前沒有指向任何合法對象。aconst_null操作碼用在給引用變量賦null值的時候。
操作碼 | 操作數 | 描述 |
aconst_null | (none) | pushes a null object reference onto the stack |
有2個操作碼需要緊跟一個操作數來指明入棧的常量值。下表列出的操作碼,用來把合法的byte型和short型的常量值壓入棧中。byte型或short型的值在入棧之前,先被擴充成int型的值,因為棧單元是32位寬的。對byte型和short型的操作,實際上是基于它們擴充後的int型值的。
操作碼 | 操作數 | 描述 |
bipush | byte1 | expands byte1 (a byte type) to an int and pushes it onto the stack |
sipush | byte1, byte2 | expands byte1, byte2 (a short type) to an int and pushes it onto the stack |
有3個操作碼把常量池中的常量值壓入棧中。所有和類關聯的常量,如final變量,都被儲存在類的常量池中。把常量池中的常量壓入棧中的操作碼,都有一個操作數,它表示需要入棧的常量在常量池中的索引。JVM會根據索引查找常量,确定它的類型,并把它壓入棧中。
在位元組碼流中,常量池索引(constant pool index)是一個緊跟在操作碼後的無符号值。操作碼lcd1和lcd2把32位的項壓入棧中,如int或float。兩者的差別在于lcd1隻适用于1-255的常量池索引位,因為它的索引隻有1個位元組。(常量池0号位未被使用。)lcd2的索引有2個位元組,是以它可以适用于常量池的任意位置。lcd2w也有一個2位元組的索引,它被用來訓示任意含有64位的long或double型資料的常量池位置。下表列出了把常量池中的常量壓入棧中的操作碼:
操作碼 | 操作數 | 描述 |
ldc1 | indexbyte1 | pushes 32-bit constant_pool entry specified by indexbyte1 onto the stack |
ldc2 | indexbyte1, indexbyte2 | pushes 32-bit constant_pool entry specified by indexbyte1, indexbyte2 onto the stack |
ldc2w | indexbyte1, indexbyte2 | pushes 64-bit constant_pool entry specified by indexbyte1,indexbyte2 onto the stack |
把局部變量(local variables)壓入棧中
局部變量儲存在棧幀的一個特殊區域中。棧幀是目前執行方法正在使用的棧區。每個棧幀包含3個部分:本地變量區,執行環境和操作數棧區。把本地變量入棧實際上包含了把數值從棧幀的本地變量區移動到操作數棧區。操作數棧區總是在棧的頂部,是以,把一個值壓到目前棧幀的操作數棧區頂部,跟壓到整個JVM棧的頂部是一個意思。
Java棧是一個先進後出(LIFO)的32位寬的棧。所有的本地變量至少占用32位,因為棧中的每個單元都是32位寬的。像long和double類型的64位的本地變量會占用2個棧單元。byte和short型的本地變量會當做int型來存儲,但隻擁有較小類型的合法值。例如,表示byte型的int型本地變量取值範圍總是-128到127。
每個本地變量都有一個唯一索引。方法棧幀的本地變量區,可以當成是一個擁有32位寬的元素的數組,每個元素都可以用數組索引來尋址。long和double型的占用2個單元的本地變量,且用低位元素的索引尋址。例如,對一個占用2單元和3單元的double數值,會用索引2來引用。
有一些操作碼可以把int和float型本地變量壓入操作數棧。部分操作碼,定義成隐含常用本地變量位址的引用。例如,iload_0加載處在位置0的int型本地變量。其他本地變量,通過操作碼後跟一個位元組的本地變量索引的方式壓入棧中。iload指令就是這種操作碼類型的一個例子。iload後的一個位元組被解釋成指向本地變量的8位無符号索引。
類似iload所用的8位無符号本地變量索引,限制了一個方法最多隻能有256個本地變量。有一個單獨的wide指令可以把8位索引擴充為16位索引,則使得本地變量數的上限提高到64k個。操作碼wide隻有1個操作數。wide和它的操作數,出現在像iload之類的有一個8位無符号本地變量索引的指令之前。JVM會把wide的操作數和iload的操作數合并為一個16位的無符号本地變量索引。
下表列出了把int和float型本地變量壓入棧中的操作碼:
操作碼 | 操作數 | 描述 |
iload | vindex | pushes int from local variable position vindex |
iload_0 | (none) | pushes int from local variable position zero |
iload_1 | (none) | pushes int from local variable position one |
iload_2 | (none) | pushes int from local variable position two |
iload_3 | (none) | pushes int from local variable position three |
fload | vindex | pushes float from local variable position vindex |
fload_0 | (none) | pushes float from local variable position zero |
fload_1 | (none) | pushes float from local variable position one |
fload_2 | (none) | pushes float from local variable position two |
fload_3 | (none) | pushes float from local variable position three |
接下來的這張表,列出了把long和double型本地變量壓入棧中的指令。這些指令把64位的數從棧幀的本地變量區移動到操作數區。
操作碼 | 操作數 | 描述 |
lload | vindex | pushes long from local variable positions vindex and (vindex + 1) |
lload_0 | (none) | pushes long from local variable positions zero and one |
lload_1 | (none) | pushes long from local variable positions one and two |
lload_2 | (none) | pushes long from local variable positions two and three |
lload_3 | (none) | pushes long from local variable positions three and four |
dload | vindex | pushes double from local variable positions vindex and (vindex + 1) |
dload_0 | (none) | pushes double from local variable positions zero and one |
dload_1 | (none) | pushes double from local variable positions one and two |
dload_2 | (none) | pushes double from local variable positions two and three |
dload_3 | (none) | pushes double from local variable positions three and four |
最後一組操作碼,把32位的對象引用從棧幀的本地變量區移動到操作數區。如下表:
操作碼 | 操作數 | 描述 |
aload | vindex | pushes object reference from local variable position vindex |
aload_0 | (none) | pushes object reference from local variable position zero |
aload_1 | (none) | pushes object reference from local variable position one |
aload_2 | (none) | pushes object reference from local variable position two |
aload_3 | (none) | pushes object reference from local variable position three |
彈出到本地變量
每一個将局部變量壓入棧中的操作碼,都有一個對應的負責彈出棧頂元素到本地變量中的操作碼。這些操作碼的名字可以通過替換入棧操作碼名中的“load”為“store”得到。下表列出了将int和float型數值彈出操作數棧到本地變量中的操作碼。這些操作碼将一個32位的值從棧頂移動到本地變量中。
操作碼 | 操作數 | 描述 |
istore | vindex | pops int to local variable position vindex |
istore_0 | (none) | pops int to local variable position zero |
istore_1 | (none) | pops int to local variable position one |
istore_2 | (none) | pops int to local variable position two |
istore_3 | (none) | pops int to local variable position three |
fstore | vindex | pops float to local variable position vindex |
fstore_0 | (none) | pops float to local variable position zero |
fstore_1 | (none) | pops float to local variable position one |
fstore_2 | (none) | pops float to local variable position two |
fstore_3 | (none) | pops float to local variable position three |
下一張表中,展示了負責将long和double類型數值出棧并存到局部變量的位元組碼指令,這些指令将64位的值從操作數棧頂移動到本地變量中。
操作碼 | 操作數 | 描述 |
lstore | vindex | pops long to local variable positions vindex and (vindex + 1) |
lstore_0 | (none) | pops long to local variable positions zero and one |
lstore_1 | (none) | pops long to local variable positions one and two |
lstore_2 | (none) | pops long to local variable positions two and three |
lstore_3 | (none) | pops long to local variable positions three and four |
dstore | vindex | pops double to local variable positions vindex and (vindex + 1) |
dstore_0 | (none) | pops double to local variable positions zero and one |
dstore_1 | (none) | pops double to local variable positions one and two |
dstore_2 | (none) | pops double to local variable positions two and three |
dstore_3 | (none) | pops double to local variable positions three and four |
最後一組操作碼,負責将32位的對象引用從操作數棧頂移動到本地變量中。
操作碼 | 操作數 | 描述 |
astore | vindex | pops object reference to local variable position vindex |
astore_0 | (none) | pops object reference to local variable position zero |
astore_1 | (none) | pops object reference to local variable position one |
astore_2 | (none) | pops object reference to local variable position two |
astore_3 | (none) | pops object reference to local variable position three |
類型轉換
JVM中有一些操作碼用來将一種基本類型的數值轉換成另外一種。位元組碼流中的轉換操作碼後面不跟操作數,被轉換的值取自棧頂。JVM彈出棧頂的值,轉換後再将結果壓入棧中。下表列出了在int,long,float和double間轉換的操作碼。這四種類型組合的每一個可能的轉換,都有一個對應的操作碼。
操作碼 | 操作數 | 描述 |
i2l | (none) | converts int to long |
i2f | (none) | converts int to float |
i2d | (none) | converts int to double |
l2i | (none) | converts long to int |
l2f | (none) | converts long to float |
l2d | (none) | converts long to double |
f2i | (none) | converts float to int |
f2l | (none) | converts float to long |
f2d | (none) | converts float to double |
d2i | (none) | converts double to int |
d2l | (none) | converts double to long |
d2f | (none) | converts double to float |
下表列出了将int型轉換為更小類型的操作碼。不存在直接将long,float,double型轉換為比int型小的類型的操作碼。是以,像float到byte這樣的轉換,需要兩步。第一步,f2i将float轉換為int,第二步,int2byte操作碼将int轉換為byte。
操作碼 | 操作數 | 描述 |
int2byte | (none) | converts int to byte |
int2char | (none) | converts int to char |
int2short | (none) | converts int to short |
雖然存在将int轉換為更小類型(byte,short,char)的操作碼,但是不存在反向轉換的操作碼。這是因為byte,short和char型的數值在入棧之前會轉換成int型。byte,short和char型數值的算術運算,首先要将這些類型的值轉為int,然後執行算術運算,最後得到int型結果。也就是說,如果兩個byte型的數相加,會得到一個int型的結果,如果你想要byte型的結果,你必須顯式地将int類型的結果轉換為byte類型的值。例如,下面的代碼編譯出錯:
-
class BadArithmetic
{
-
byte addOneAndOne
(
)
{
-
byte a =
1
;
-
byte b =
1
;
-
byte c = a + b
;
-
return c
;
- }
- }
javac會對上面的代碼給出如下錯誤:
1. (
7
): Incompatible type
for
2. Explicit cast needed to convert int to byte.
3. byte c = a + b;
4. ^
Java程式員必須顯式的把a + b的結果轉換為byte,這樣才能通過編譯。
1. class GoodArithmetic
{
2. byte addOneAndOne
(
)
{
3. byte a =
1
;
4. byte b =
1
;
5. byte c =
(
byte
)
(a + b
)
;
6. return c
;
7. }
8. }
這樣,javac會很高興的生成GoodArithmetic.class檔案,它包含如下的addOneAndOne()方法的位元組碼序列:
1. 1.
2. 1, which is a: byte a =
1;
3. 1
4. 2, which is b: byte b =
1;
5. (a is already stored as an int
in local variable
1
).
6. (b is already stored as an int
in local variable
2
).
7. (a + b
), an int.
8. (result still occupies
32 bits
).
9. 3, which is byte c: byte c =
(byte
)
(a + b
);
10. iload_3 // Push the value of c so it can be returned.
11. ireturn // Proudly return the result of the addition: return c;
本文譯自:Bytecode basics
轉載自:http://iofree.cc/%E5%AD%97%E8%8A%82%E7%A0%81%E5%9F%BA%E7%A1%80%EF%BC%9Ajvm%E5%AD%97%E8%8A%82%E7%A0%81%E5%88%9D%E6%8E%A2/
Mnemonic | Opcode (in hex) | Other bytes | Stack [before]→[after] | Description |
aaload | 32 | arrayref, index → value | load onto the stack a reference from an array | |
aastore | 53 | arrayref, index, value → | store into a reference in an array | |
aconst_null | 01 | → null | push a null reference onto the stack | |
aload | 19 | 1: index | → objectref | load a reference onto the stack from a local variable #index |
aload_0 | 2a | → objectref | load a reference onto the stack from local variable 0 | |
aload_1 | 2b | → objectref | load a reference onto the stack from local variable 1 | |
aload_2 | 2c | → objectref | load a reference onto the stack from local variable 2 | |
aload_3 | 2d | → objectref | load a reference onto the stack from local variable 3 | |
anewarray | bd | 2: indexbyte1, indexbyte2 | count → arrayref | create a new array of references of length count and component type identified by the class referenceindex (indexbyte1 << 8 + indexbyte2) in the constant pool |
areturn | b0 | objectref → [empty] | return a reference from a method | |
arraylength | be | arrayref → length | get the length of an array | |
astore | 3a | 1: index | objectref → | store a reference into a local variable #index |
astore_0 | 4b | objectref → | store a reference into local variable 0 | |
astore_1 | 4c | objectref → | store a reference into local variable 1 | |
astore_2 | 4d | objectref → | store a reference into local variable 2 | |
astore_3 | 4e | objectref → | store a reference into local variable 3 | |
athrow | bf | objectref → [empty], objectref | throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable) | |
baload | 33 | arrayref, index → value | load a byte or Boolean value from an array | |
bastore | 54 | arrayref, index, value → | store a byte or Boolean value into an array | |
bipush | 10 | 1: byte | → value | push a byte onto the stack as an integer value |
breakpoint | ca | reserved for breakpoints in Java debuggers; should not appear in any class file | ||
caload | 34 | arrayref, index → value | load a char from an array | |
castore | 55 | arrayref, index, value → | store a char into an array | |
checkcast | c0 | 2: indexbyte1, indexbyte2 | objectref → objectref | checks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 + indexbyte2) |
d2f | 90 | value → result | convert a double to a float | |
d2i | 8e | value → result | convert a double to an int | |
d2l | 8f | value → result | convert a double to a long | |
dadd | 63 | value1, value2 → result | add two doubles | |
daload | 31 | arrayref, index → value | load a double from an array | |
dastore | 52 | arrayref, index, value → | store a double into an array | |
dcmpg | 98 | value1, value2 → result | compare two doubles | |
dcmpl | 97 | value1, value2 → result | compare two doubles | |
dconst_0 | 0e | → 0.0 | push the constant 0.0 onto the stack | |
dconst_1 | 0f | → 1.0 | push the constant 1.0 onto the stack | |
ddiv | 6f | value1, value2 → result | divide two doubles | |
dload | 18 | 1: index | → value | load a double value from a local variable #index |
dload_0 | 26 | → value | load a double from local variable 0 | |
dload_1 | 27 | → value | load a double from local variable 1 | |
dload_2 | 28 | → value | load a double from local variable 2 | |
dload_3 | 29 | → value | load a double from local variable 3 | |
dmul | 6b | value1, value2 → result | multiply two doubles | |
dneg | 77 | value → result | negate a double | |
drem | 73 | value1, value2 → result | get the remainder from a division between two doubles | |
dreturn | af | value → [empty] | return a double from a method | |
dstore | 39 | 1: index | value → | store a double value into a local variable #index |
dstore_0 | 47 | value → | store a double into local variable 0 | |
dstore_1 | 48 | value → | store a double into local variable 1 | |
dstore_2 | 49 | value → | store a double into local variable 2 | |
dstore_3 | 4a | value → | store a double into local variable 3 | |
dsub | 67 | value1, value2 → result | subtract a double from another | |
dup | 59 | value → value, value | duplicate the value on top of the stack | |
dup_x1 | 5a | value2, value1 → value1, value2, value1 | insert a copy of the top value into the stack two values from the top. value1 and value2 must not be of the type double or long. | |
dup_x2 | 5b | value3, value2, value1 → value1, value3, value2, value1 | insert a copy of the top value into the stack two (if value2 is double or long it takes up the entry of value3, too) or three values (if value2 is neither double nor long) from the top | |
dup2 | 5c | {value2, value1} → {value2, value1}, {value2, value1} | duplicate top two stack words (two values, if value1 is not double nor long; a single value, if value1 is double or long) | |
dup2_x1 | 5d | value3, {value2, value1} → {value2, value1}, value3, {value2, value1} | duplicate two words and insert beneath third word (see explanation above) | |
dup2_x2 | 5e | {value4, value3}, {value2, value1} → {value2, value1}, {value4, value3}, {value2, value1} | duplicate two words and insert beneath fourth word | |
f2d | 8d | value → result | convert a float to a double | |
f2i | 8b | value → result | convert a float to an int | |
f2l | 8c | value → result | convert a float to a long | |
fadd | 62 | value1, value2 → result | add two floats | |
faload | 30 | arrayref, index → value | load a float from an array | |
fastore | 51 | arrayref, index, value → | store a float in an array | |
fcmpg | 96 | value1, value2 → result | compare two floats | |
fcmpl | 95 | value1, value2 → result | compare two floats | |
fconst_0 | 0b | → 0.0f | push 0.0f on the stack | |
fconst_1 | 0c | → 1.0f | push 1.0f on the stack | |
fconst_2 | 0d | → 2.0f | push 2.0f on the stack | |
fdiv | 6e | value1, value2 → result | divide two floats | |
fload | 17 | 1: index | → value | load a float value from a local variable #index |
fload_0 | 22 | → value | load a float value from local variable 0 | |
fload_1 | 23 | → value | load a float value from local variable 1 | |
fload_2 | 24 | → value | load a float value from local variable 2 | |
fload_3 | 25 | → value | load a float value from local variable 3 | |
fmul | 6a | value1, value2 → result | multiply two floats | |
fneg | 76 | value → result | negate a float | |
frem | 72 | value1, value2 → result | get the remainder from a division between two floats | |
freturn | ae | value → [empty] | return a float | |
fstore | 38 | 1: index | value → | store a float value into a local variable #index |
fstore_0 | 43 | value → | store a float value into local variable 0 | |
fstore_1 | 44 | value → | store a float value into local variable 1 | |
fstore_2 | 45 | value → | store a float value into local variable 2 | |
fstore_3 | 46 | value → | store a float value into local variable 3 | |
fsub | 66 | value1, value2 → result | subtract two floats | |
getfield | b4 | 2: index1, index2 | objectref → value | get a field value of an object objectref, where the field is identified by field reference in the constant pool index (index1 << 8 + index2) |
getstatic | b2 | 2: index1, index2 | → value | get a static field value of a class, where the field is identified by field reference in the constant pool index (index1 << 8 + index2) |
goto | a7 | 2: branchbyte1, branchbyte2 | [no change] | goes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
goto_w | c8 | 4: branchbyte1, branchbyte2, branchbyte3, branchbyte4 | [no change] | goes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) |
i2b | 91 | value → result | convert an int into a byte | |
i2c | 92 | value → result | convert an int into a character | |
i2d | 87 | value → result | convert an int into a double | |
i2f | 86 | value → result | convert an int into a float | |
i2l | 85 | value → result | convert an int into a long | |
i2s | 93 | value → result | convert an int into a short | |
iadd | 60 | value1, value2 → result | add two ints | |
iaload | 2e | arrayref, index → value | load an int from an array | |
iand | 7e | value1, value2 → result | perform a bitwise and on two integers | |
iastore | 4f | arrayref, index, value → | store an int into an array | |
iconst_m1 | 02 | → -1 | load the int value -1 onto the stack | |
iconst_0 | 03 | → 0 | load the int value 0 onto the stack | |
iconst_1 | 04 | → 1 | load the int value 1 onto the stack | |
iconst_2 | 05 | → 2 | load the int value 2 onto the stack | |
iconst_3 | 06 | → 3 | load the int value 3 onto the stack | |
iconst_4 | 07 | → 4 | load the int value 4 onto the stack | |
iconst_5 | 08 | → 5 | load the int value 5 onto the stack | |
idiv | 6c | value1, value2 → result | divide two integers | |
if_acmpeq | a5 | 2: branchbyte1, branchbyte2 | value1, value2 → | if references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
if_acmpne | a6 | 2: branchbyte1, branchbyte2 | value1, value2 → | if references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
if_icmpeq | 9f | 2: branchbyte1, branchbyte2 | value1, value2 → | if ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytesbranchbyte1 << 8 + branchbyte2) |
if_icmpge | a2 | 2: branchbyte1, branchbyte2 | value1, value2 → | if value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
if_icmpgt | a3 | 2: branchbyte1, branchbyte2 | value1, value2 → | if value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
if_icmple | a4 | 2: branchbyte1, branchbyte2 | value1, value2 → | if value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
if_icmplt | a1 | 2: branchbyte1, branchbyte2 | value1, value2 → | if value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
if_icmpne | a0 | 2: branchbyte1, branchbyte2 | value1, value2 → | if ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
ifeq | 99 | 2: branchbyte1, branchbyte2 | value → | if value is 0, branch to instruction at branchoffset (signed short constructed from unsigned bytesbranchbyte1 << 8 + branchbyte2) |
ifge | 9c | 2: branchbyte1, branchbyte2 | value → | if value is greater than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
ifgt | 9d | 2: branchbyte1, branchbyte2 | value → | if value is greater than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
ifle | 9e | 2: branchbyte1, branchbyte2 | value → | if value is less than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
iflt | 9b | 2: branchbyte1, branchbyte2 | value → | if value is less than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
ifne | 9a | 2: branchbyte1, branchbyte2 | value → | if value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytesbranchbyte1 << 8 + branchbyte2) |
ifnonnull | c7 | 2: branchbyte1, branchbyte2 | value → | if value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) |
ifnull | c6 | 2: branchbyte1, branchbyte2 | value → | if value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytesbranchbyte1 << 8 + branchbyte2) |
iinc | 84 | 2: index, const | [No change] | increment local variable #index by signed byte const |
iload | 15 | 1: index | → value | load an int value from a local variable #index |
iload_0 | 1a | → value | load an int value from local variable 0 | |
iload_1 | 1b | → value | load an int value from local variable 1 | |
iload_2 | 1c | → value | load an int value from local variable 2 | |
iload_3 | 1d | → value | load an int value from local variable 3 | |
impdep1 | fe | reserved for implementation-dependent operations within debuggers; should not appear in any class file | ||
impdep2 | ff | reserved for implementation-dependent operations within debuggers; should not appear in any class file | ||
imul | 68 | value1, value2 → result | multiply two integers | |
ineg | 74 | value → result | negate int | |
instanceof | c1 | 2: indexbyte1, indexbyte2 | objectref → result | determines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
invokedynamic | ba | 4: indexbyte1, indexbyte2, 0, 0 | [arg1, [arg2 ...]] → | invokes a dynamic method identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
invokeinterface | b9 | 4: indexbyte1, indexbyte2, count, 0 | objectref, [arg1, arg2, ...] → | invokes an interface method on object objectref, where the interface method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
invokespecial | b7 | 2: indexbyte1, indexbyte2 | objectref, [arg1, arg2, ...] → | invoke instance method on object objectref, where the method is identified by method reference indexin constant pool (indexbyte1 << 8 + indexbyte2) |
invokestatic | b8 | 2: indexbyte1, indexbyte2 | [arg1, arg2, ...] → | invoke a static method, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
invokevirtual | b6 | 2: indexbyte1, indexbyte2 | objectref, [arg1, arg2, ...] → | invoke virtual method on object objectref, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
ior | 80 | value1, value2 → result | bitwise int or | |
irem | 70 | value1, value2 → result | logical int remainder | |
ireturn | ac | value → [empty] | return an integer from a method | |
ishl | 78 | value1, value2 → result | int shift left | |
ishr | 7a | value1, value2 → result | int arithmetic shift right | |
istore | 36 | 1: index | value → | store int value into variable #index |
istore_0 | 3b | value → | store int value into variable 0 | |
istore_1 | 3c | value → | store int value into variable 1 | |
istore_2 | 3d | value → | store int value into variable 2 | |
istore_3 | 3e | value → | store int value into variable 3 | |
isub | 64 | value1, value2 → result | int subtract | |
iushr | 7c | value1, value2 → result | int logical shift right | |
ixor | 82 | value1, value2 → result | int xor | |
jsr | a8 | 2: branchbyte1, branchbyte2 | → address | jump to subroutine at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) and place the return address on the stack |
jsr_w | c9 | 4: branchbyte1, branchbyte2, branchbyte3, branchbyte4 | → address | jump to subroutine at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) and place the return address on the stack |
l2d | 8a | value → result | convert a long to a double | |
l2f | 89 | value → result | convert a long to a float | |
l2i | 88 | value → result | convert a long to a int | |
ladd | 61 | value1, value2 → result | add two longs | |
laload | 2f | arrayref, index → value | load a long from an array | |
land | 7f | value1, value2 → result | bitwise and of two longs | |
lastore | 50 | arrayref, index, value → | store a long to an array | |
lcmp | 94 | value1, value2 → result | compare two longs values | |
lconst_0 | 09 | → 0L | push the long 0 onto the stack | |
lconst_1 | 0a | → 1L | push the long 1 onto the stack | |
ldc | 12 | 1: index | → value | push a constant #index from a constant pool (String, int or float) onto the stack |
ldc_w | 13 | 2: indexbyte1, indexbyte2 | → value | push a constant #index from a constant pool (String, int or float) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2) |
ldc2_w | 14 | 2: indexbyte1, indexbyte2 | → value | push a constant #index from a constant pool (double or long) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2) |
ldiv | 6d | value1, value2 → result | divide two longs | |
lload | 16 | 1: index | → value | load a long value from a local variable #index |
lload_0 | 1e | → value | load a long value from a local variable 0 | |
lload_1 | 1f | → value | load a long value from a local variable 1 | |
lload_2 | 20 | → value | load a long value from a local variable 2 | |
lload_3 | 21 | → value | load a long value from a local variable 3 | |
lmul | 69 | value1, value2 → result | multiply two longs | |
lneg | 75 | value → result | negate a long | |
lookupswitch | ab | 4+: <0-3 bytes padding>, defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, npairs1, npairs2, npairs3, npairs4, match-offset pairs... | key → | a target address is looked up from a table using a key and execution continues from the instruction at that address |
lor | 81 | value1, value2 → result | bitwise or of two longs | |
lrem | 71 | value1, value2 → result | remainder of division of two longs | |
lreturn | ad | value → [empty] | return a long value | |
lshl | 79 | value1, value2 → result | bitwise shift left of a long value1 by value2 positions | |
lshr | 7b | value1, value2 → result | bitwise shift right of a long value1 by value2 positions | |
lstore | 37 | 1: index | value → | store a long value in a local variable #index |
lstore_0 | 3f | value → | store a long value in a local variable 0 | |
lstore_1 | 40 | value → | store a long value in a local variable 1 | |
lstore_2 | 41 | value → | store a long value in a local variable 2 | |
lstore_3 | 42 | value → | store a long value in a local variable 3 | |
lsub | 65 | value1, value2 → result | subtract two longs | |
lushr | 7d | value1, value2 → result | bitwise shift right of a long value1 by value2 positions, unsigned | |
lxor | 83 | value1, value2 → result | bitwise exclusive or of two longs | |
monitorenter | c2 | objectref → | enter monitor for object ("grab the lock" - start of synchronized() section) | |
monitorexit | c3 | objectref → | exit monitor for object ("release the lock" - end of synchronized() section) | |
multianewarray | c5 | 3: indexbyte1, indexbyte2, dimensions | count1, [count2,...] → arrayref | create a new array of dimensions dimensions with elements of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2); the sizes of each dimension is identified bycount1, [count2, etc.] |
new | bb | 2: indexbyte1, indexbyte2 | → objectref | create new object of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2) |
newarray | bc | 1: atype | count → arrayref | create new array with count elements of primitive type identified by atype |
nop | 00 | [No change] | perform no operation | |
pop | 57 | value → | discard the top value on the stack | |
pop2 | 58 | {value2, value1} → | discard the top two values on the stack (or one value, if it is a double or long) | |
putfield | b5 | 2: indexbyte1, indexbyte2 | objectref, value → | set field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
putstatic | b3 | 2: indexbyte1, indexbyte2 | value → | set static field to value in a class, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2) |
ret | a9 | 1: index | [No change] | continue execution from address taken from a local variable #index (the asymmetry with jsr is intentional) |
return | b1 | → [empty] | return void from method | |
saload | 35 | arrayref, index → value | load short from array | |
sastore | 56 | arrayref, index, value → | store short to array | |
sipush | 11 | 2: byte1, byte2 | → value | push a short onto the stack |
swap | 5f | value2, value1 → value1, value2 | swaps two top words on the stack (note that value1 and value2 must not be double or long) | |
tableswitch | aa | 4+: [0-3 bytes padding], defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, lowbyte1, lowbyte2, lowbyte3, lowbyte4, highbyte1, highbyte2, highbyte3, highbyte4, jump offsets... | index → | continue execution from an address in the table at offset index |
wide | c4 | 3/5: opcode, indexbyte1, indexbyte2 or iinc, indexbyte1, indexbyte2, countbyte1, countbyte2 | [same as for corresponding instructions] | execute opcode, where opcode is either iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, or ret, but assume the index is 16 bit; or execute iinc, where the index is 16 bits and the constant to increment by is a signed 16 bit short |
(no name) | cb-fd | these values are currently unassigned for opcodes and are reserved for future use |