Java 程式設計/位元組碼
外觀
Java 位元組碼是 Java 原始碼被編譯成的語言,也是 Java 虛擬機器可以理解的語言。與必須為每種不同型別的計算機專門編譯的編譯語言不同,Java 程式只需要轉換一次為位元組碼,之後它可以在任何存在 Java 虛擬機器的平臺上執行。
位元組碼是 Java 程式的編譯格式。一旦 Java 程式被轉換為位元組碼,它就可以透過網路傳輸並由 Java 虛擬機器 (JVM) 執行。位元組碼檔案通常具有 .class 副檔名。對於 Java 程式設計師來說,通常不需要了解位元組碼,但它可能很有用。
有一些激動人心的新語言正在被建立,它們也編譯成 Java 位元組碼,例如 Groovy。
- GNAT
- GNU Ada 編譯器,能夠將 Ada 編譯成 Java 風格的位元組碼。
- ftp://cs.nyu.edu/pub/gnat
- JPython
- 將 Python 編譯成 Java 風格的位元組碼。
- http://www.jpython.org/
- Kawa
- 將 Scheme 編譯成 Java 風格的位元組碼。
- http://www.gnu.org/software/kawa/
考慮以下 Java 程式碼。
outer:
for (int i = 2; i < 1000; i++) {
for (int j = 2; j < i; j++) {
if (i % j == 0)
continue outer;
}
System.out.println (i);
}
Java 編譯器可能會將上面的 Java 程式碼翻譯成以下位元組碼,假設上面的程式碼被放在一個方法中
Code:
0: iconst_2
1: istore_1
2: iload_1
3: sipush 1000
6: if_icmpge 44
9: iconst_2
10: istore_2
11: iload_2
12: iload_1
13: if_icmpge 31
16: iload_1
17: iload_2
18: irem # remainder
19: ifne 25
22: goto 38
25: iinc 2, 1
28: goto 11
31: getstatic #84; //Field java/lang/System.out:Ljava/io/PrintStream;
34: iload_1
35: invokevirtual #85; //Method java/io/PrintStream.println:(I)V
38: iinc 1, 1
41: goto 2
44: return
例如,我們可以編寫一個簡單的 Foo.java 原始檔
public class Foo {
public static void main(final String[] args) {
System.out.println("This is a simple example of decompilation using javap");
a();
b();
}
public static void a() {
System.out.println("Now we are calling a function...");
}
public static void b() {
System.out.println("...and now we are calling b");
}
}
編譯它,然後將 Foo.java 移動到另一個目錄,或者如果你願意,刪除它。我們可以用 javap 和 Foo.class 做什麼?
$javap Foo
產生以下結果
Compiled from "Foo.java"
public class Foo extends java.lang.Object {
public Foo();
public static void main(java.lang.String[]);
public static void a();
public static void b();
}
如你所見,javac 編譯器不會從 .class 檔案中剝離任何(公共)變數名。因此,函式的名稱、它們的引數和返回值的型別都暴露出來了。(這是為了讓其他類能夠訪問它們所必需的。)
讓我們再做一些,試試
$javap -c Foo
Compiled from "Foo.java"
public class Foo extends java.lang.Object{
public Foo();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String This is a simple example of decompilation using javap
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: invokestatic #5; //Method a:()V
11: invokestatic #6; //Method b:()V
14: return
public static void a();
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #7; //String Now we are calling a function...
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public static void b();
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #8; //String ...and now we are calling b
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
有關更詳細的描述,請參閱 Oracle 的 Java 虛擬機器規範[1]
運算元棧的操作表示為 [before]→[after],其中 [before] 是執行指令之前棧的狀態,[after] 是執行指令之後棧的狀態。一個棧,其頂部元素為 'b',其下一層元素為 'a',表示為 'a,b'。
| 助記符 | 操作碼 (以 十六進位制 表示) |
其他位元組 | 棧 [before]→[after] |
描述 |
|---|---|---|---|---|
| A | ||||
| aaload | 32 | arrayref, index → value | 從陣列中載入引用到堆疊 | |
| aastore | 53 | arrayref, index, value → | 將引用儲存到陣列中 | |
| aconst_null | 01 | → null | 將一個 null 引用推送到堆疊 | |
| aload | 19 | index | → objectref | 從本地變數 #index 中載入引用到堆疊 |
| aload_0 | 2a | → objectref | 從本地變數 0 中載入引用到堆疊 | |
| aload_1 | 2b | → objectref | 從本地變數 1 中載入引用到堆疊 | |
| aload_2 | 2c | → objectref | 從本地變數 2 中載入引用到堆疊 | |
| aload_3 | 2d | → objectref | 從本地變數 3 中載入引用到堆疊 | |
| anewarray | bd | indexbyte1, indexbyte2 | count → arrayref | 建立一個新的引用陣列,長度為 count,元件型別由常量池中 index (indexbyte1 << 8 + indexbyte2) 標識的類引用指定 |
| areturn | b0 | objectref → [empty] | 從方法中返回一個引用 | |
| arraylength | be | arrayref → length | 獲取陣列的長度 | |
| astore | 3a | index | objectref → | 將引用儲存到本地變數 #index 中 |
| astore_0 | 4b | objectref → | 將引用儲存到本地變數 0 中 | |
| astore_1 | 4c | objectref → | 將引用儲存到本地變數 1 中 | |
| astore_2 | 4d | objectref → | 將引用儲存到本地變數 2 中 | |
| astore_3 | 4e | objectref → | 將引用儲存到本地變數 3 中 | |
| athrow | bf | objectref → [empty], objectref | 丟擲錯誤或異常(注意,其餘堆疊會被清空,只留下對 Throwable 的引用) | |
| B | ||||
| baload | 33 | arrayref, index → value | 從陣列中載入一個位元組或布林值 | |
| bastore | 54 | arrayref, index, value → | 將一個位元組或布林值儲存到陣列中 | |
| bipush | 10 | byte | → value | 將一個 byte 推送到堆疊作為整數 value |
| C | ||||
| caload | 34 | arrayref, index → value | 從陣列中載入一個字元 | |
| castore | 55 | arrayref, index, value → | 將一個字元儲存到陣列中 | |
| checkcast | c0 | indexbyte1, indexbyte2 | objectref → objectref | 檢查一個 objectref 是否是某種型別,該型別的類引用位於常量池中的 index (indexbyte1 << 8 + indexbyte2) 位置 |
| D | ||||
| d2f | 90 | value → result | 將一個雙精度浮點數轉換為單精度浮點數 | |
| d2i | 8e | value → result | 將一個雙精度浮點數轉換為整數 | |
| d2l | 8f | value → result | 將一個雙精度浮點數轉換為長整型 | |
| dadd | 63 | value1, value2 → result | 將兩個雙精度浮點數相加 | |
| daload | 31 | arrayref, index → value | 從陣列中載入一個雙精度浮點數 | |
| dastore | 52 | arrayref, index, value → | 將一個雙精度浮點數儲存到陣列中 | |
| dcmpg | 98 | value1, value2 → result | 比較兩個雙精度浮點數 | |
| dcmpl | 97 | value1, value2 → result | 比較兩個雙精度浮點數 | |
| dconst_0 | 0e | → 0.0 | 將常量 0.0 推送到堆疊 | |
| dconst_1 | 0f | → 1.0 | 將常量 1.0 推送到堆疊 | |
| ddiv | 6f | value1, value2 → result | 將兩個雙精度浮點數相除 | |
| dload | 18 | index | → value | 從本地變數 #index 中載入一個雙精度浮點數 value |
| dload_0 | 26 | → value | 從本地變數 0 中載入一個雙精度浮點數 | |
| dload_1 | 27 | → value | 從本地變數 1 中載入一個雙精度浮點數 | |
| dload_2 | 28 | → value | 從本地變數 2 中載入一個雙精度浮點數 | |
| dload_3 | 29 | → value | 從本地變數 3 中載入一個雙精度浮點數 | |
| dmul | 6b | value1, value2 → result | 將兩個雙精度浮點數相乘 | |
| dneg | 77 | value → result | 對一個雙精度浮點數取負 | |
| drem | 73 | value1, value2 → result | 獲取兩個雙精度浮點數相除的餘數 | |
| dreturn | af | value → [empty] | 從方法中返回一個雙精度浮點數 | |
| dstore | 39 | index | value → | 將一個雙精度浮點數 value 儲存到本地變數 #index 中 |
| dstore_0 | 47 | value → | 將一個雙精度浮點數儲存到本地變數 0 中 | |
| dstore_1 | 48 | value → | 將一個雙精度浮點數儲存到本地變數 1 中 | |
| dstore_2 | 49 | value → | 將一個雙精度浮點數儲存到本地變數 2 中 | |
| dstore_3 | 4a | value → | 將一個雙精度浮點數儲存到本地變數 3 中 | |
| dsub | 67 | value1, value2 → result | 從另一個雙精度浮點數中減去一個雙精度浮點數 | |
| dup | 59 | value → value, value | 複製堆疊頂部的值 | |
| dup_x1 | 5a | value2, value1 → value1, value2, value1 | 將頂部值的副本插入到距離頂部兩個值的堆疊中 | |
| dup_x2 | 5b | value3, value2, value1 → value1, value3, value2, value1 | 將頂部值的副本插入到距離頂部兩個(如果 value2 是雙精度浮點數或長整型,它也會佔用 value3 的位置)或三個(如果 value2 既不是雙精度浮點數也不是長整型)值的堆疊中 | |
| dup2 | 5c | {value2, value1} → {value2, value1}, {value2, value1} | 複製堆疊頂部的兩個字(兩個值,如果 value1 既不是雙精度浮點數也不是長整型;一個值,如果 value1 是雙精度浮點數或長整型) | |
| dup2_x1 | 5d | value3, {value2, value1} → {value2, value1}, value3, {value2, value1} | 複製兩個字並將它們插入到第三個字的下方(見上文解釋) | |
| dup2_x2 | 5e | {value4, value3}, {value2, value1} → {value2, value1}, {value4, value3}, {value2, value1} | 複製兩個字並將它們插入到第四個字的下方 | |
| F | ||||
| f2d | 8d | value → result | 將一個單精度浮點數轉換為雙精度浮點數 | |
| f2i | 8b | value → result | 將一個單精度浮點數轉換為整數 | |
| f2l | 8c | value → result | 將一個單精度浮點數轉換為長整型 | |
| fadd | 62 | value1, value2 → result | 將兩個單精度浮點數相加 | |
| faload | 30 | arrayref, index → value | 從陣列中載入一個單精度浮點數 | |
| fastore | 51 | arreyref, index, value → | 將一個單精度浮點數儲存到陣列中 | |
| fcmpg | 96 | value1, value2 → result | 比較兩個浮點數 | |
| fcmpl | 95 | value1, value2 → result | 比較兩個浮點數 | |
| fconst_0 | 0b | → 0.0f | 將0.0f壓入堆疊 | |
| fconst_1 | 0c | → 1.0f | 將1.0f壓入堆疊 | |
| fconst_2 | 0d | → 2.0f | 將2.0f壓入堆疊 | |
| fdiv | 6e | value1, value2 → result | 除兩個浮點數 | |
| fload | 17 | index | → value | 從區域性變數#index載入浮點數value |
| fload_0 | 22 | → value | 從區域性變數0載入浮點數value | |
| fload_1 | 23 | → value | 從區域性變數1載入浮點數value | |
| fload_2 | 24 | → value | 從區域性變數2載入浮點數value | |
| fload_3 | 25 | → value | 從區域性變數3載入浮點數value | |
| fmul | 6a | value1, value2 → result | 乘兩個浮點數 | |
| fneg | 76 | value → result | 取浮點數的負值 | |
| frem | 72 | value1, value2 → result | 獲取兩個浮點數相除的餘數 | |
| freturn | ae | value → [empty] | 從方法返回一個浮點數 | |
| fstore | 38 | index | value → | 將浮點數value儲存到區域性變數#index |
| fstore_0 | 43 | value → | 將浮點數value儲存到區域性變數0 | |
| fstore_1 | 44 | value → | 將浮點數value儲存到區域性變數1 | |
| fstore_2 | 45 | value → | 將浮點數value儲存到區域性變數2 | |
| fstore_3 | 46 | value → | 將浮點數value儲存到區域性變數3 | |
| fsub | 66 | value1, value2 → result | 減去兩個浮點數 | |
| G | ||||
| getfield | b4 | index1, index2 | objectref → value | 獲取物件objectref的欄位value,其中欄位由常量池index中的欄位引用標識(index1 << 8 + index2) |
| getstatic | b2 | index1, index2 | → value | 獲取類的靜態欄位value,其中欄位由常量池index中的欄位引用標識(index1 << 8 + index2) |
| goto | a7 | branchbyte1, branchbyte2 | [無變化] | 轉到branchoffset處的另一個指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| goto_w | c8 | branchbyte1, branchbyte2, branchbyte3, branchbyte4 | [無變化] | 轉到branchoffset處的另一個指令(從無符號位元組branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4構造的帶符號整型) |
| I | ||||
| i2b | 91 | value → result | 將int轉換為位元組 | |
| i2c | 92 | value → result | 將int轉換為字元 | |
| i2d | 87 | value → result | 將int轉換為雙精度浮點數 | |
| i2f | 86 | value → result | 將int轉換為單精度浮點數 | |
| i2l | 85 | value → result | 將int轉換為長整型 | |
| i2s | 93 | value → result | 將int轉換為短整型 | |
| iadd | 60 | value1, value2 → result | 將兩個int加在一起 | |
| iaload | 2e | arrayref, index → value | 從陣列中載入一個int | |
| iand | 7e | value1, value2 → result | 對兩個整數執行邏輯與運算 | |
| iastore | 4f | arrayref, index, value → | 將一個int儲存到陣列中 | |
| iconst_m1 | 02 | → -1 | 將int值-1載入到堆疊中 | |
| iconst_0 | 03 | → 0 | 將int值0載入到堆疊中 | |
| iconst_1 | 04 | → 1 | 將int值1載入到堆疊中 | |
| iconst_2 | 05 | → 2 | 將int值2載入到堆疊中 | |
| iconst_3 | 06 | → 3 | 將int值3載入到堆疊中 | |
| iconst_4 | 07 | → 4 | 將int值4載入到堆疊中 | |
| iconst_5 | 08 | → 5 | 將int值5載入到堆疊中 | |
| idiv | 6c | value1, value2 → result | 除兩個整數 | |
| if_acmpeq | a5 | branchbyte1, branchbyte2 | value1, value2 → | 如果引用相等,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_acmpne | a6 | branchbyte1, branchbyte2 | value1, value2 → | 如果引用不相等,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_icmpeq | 9f | branchbyte1, branchbyte2 | value1, value2 → | 如果int相等,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_icmpne | a0 | branchbyte1, branchbyte2 | value1, value2 → | 如果int不相等,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_icmplt | a1 | branchbyte1, branchbyte2 | value1, value2 → | 如果value1小於value2,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_icmpge | a2 | branchbyte1, branchbyte2 | value1, value2 → | 如果value1大於或等於value2,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_icmpgt | a3 | branchbyte1, branchbyte2 | value1, value2 → | 如果value1大於value2,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| if_icmple | a4 | branchbyte1, branchbyte2 | value1, value2 → | 如果value1小於或等於value2,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifeq | 99 | branchbyte1, branchbyte2 | value → | 如果value為0,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifne | 9a | branchbyte1, branchbyte2 | value → | 如果value不為0,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| iflt | 9b | branchbyte1, branchbyte2 | value → | 如果value小於0,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifge | 9c | branchbyte1, branchbyte2 | value → | 如果value大於或等於0,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifgt | 9d | branchbyte1, branchbyte2 | value → | 如果value大於0,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifle | 9e | branchbyte1, branchbyte2 | value → | 如果value小於或等於0,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifnonnull | c7 | branchbyte1, branchbyte2 | value → | 如果value不為空,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| ifnull | c6 | branchbyte1, branchbyte2 | value → | 如果value為空,則跳轉到branchoffset處的指令(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| iinc | 84 | index, const | [無變化] | 將區域性變數#index增加帶符號位元組const |
| iload | 15 | index | → value | 從變數#index載入一個intvalue |
| iload_0 | 1a | → value | 從變數0載入一個intvalue | |
| iload_1 | 1b | → value | 從變數1載入一個intvalue | |
| iload_2 | 1c | → value | 從變數2載入一個intvalue | |
| iload_3 | 1d | → value | 從變數3載入一個intvalue | |
| imul | 68 | value1, value2 → result | 乘兩個整數 | |
| ineg | 74 | value → result | 取int的負值 | |
| instanceof | c1 | indexbyte1, indexbyte2 | objectref → result | 確定物件objectref是否為給定型別,由常量池(indexbyte1 << 8 + indexbyte2)中的類引用index標識 |
| invokedynamic | ba | indexbyte1, indexbyte2 | [arg1, arg2, ...] → result | 呼叫動態方法並將結果放到堆疊上(可能是void);該方法由常量池(indexbyte1 << 8 | indexbyte2)中的方法引用index標識 |
| invokeinterface | b9 | indexbyte1, indexbyte2, count, 0 | objectref, [arg1, arg2, ...] → | 在物件objectref上呼叫介面方法,其中介面方法由常量池(indexbyte1 << 8 + indexbyte2)中的方法引用index標識,count是從堆疊幀中彈出的引數數量,包括呼叫方法的物件,並且必須始終大於或等於1 |
| invokespecial | b7 | indexbyte1, indexbyte2 | objectref, [arg1, arg2, ...] → | 呼叫物件objectref上的例項方法,需要特殊處理(例項初始化方法、私有方法或超類方法),其中方法由常量池(indexbyte1 << 8 + indexbyte2)中的方法引用index標識 |
| invokestatic | b8 | indexbyte1, indexbyte2 | [arg1, arg2, ...] → | 呼叫靜態方法,其中方法由常量池(indexbyte1 << 8 + indexbyte2)中的方法引用index標識 |
| invokevirtual | b6 | indexbyte1, indexbyte2 | objectref, [arg1, arg2, ...] → | 呼叫物件objectref上的虛擬方法,其中方法由常量池(indexbyte1 << 8 + indexbyte2)中的方法引用index標識 |
| ior | 80 | value1, value2 → result | 邏輯int或 | |
| irem | 70 | value1, value2 → result | 邏輯int餘數 | |
| ireturn | ac | value → [empty] | 從方法返回一個整數 | |
| ishl | 78 | value1, value2 → result | int左移 | |
| ishr | 7a | value1, value2 → result | int右移 | |
| istore | 36 | index | value → | 將intvalue儲存到變數#index中 |
| istore_0 | 3b | value → | 將intvalue儲存到變數0中 | |
| istore_1 | 3c | value → | 將intvalue儲存到變數1中 | |
| istore_2 | 3d | value → | 將intvalue儲存到變數2中 | |
| istore_3 | 3e | value → | 將intvalue儲存到變數3中 | |
| isub | 64 | value1, value2 → result | int減法 | |
| iushr | 7c | value1, value2 → result | int右移 | |
| ixor | 82 | value1, value2 → result | int異或 | |
| J | ||||
| jsr | a8 | branchbyte1, branchbyte2 | → address | 跳轉到branchoffset處的子程式並把返回地址放到堆疊上(從無符號位元組branchbyte1 << 8 + branchbyte2構造的帶符號短整型) |
| jsr_w | c9 | branchbyte1, branchbyte2, branchbyte3, branchbyte4 | → address | 跳轉到branchoffset處的子程式並把返回地址放到堆疊上(從無符號位元組branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4構造的帶符號整型) |
| L | ||||
| l2d | 8a | value → result | 將長整型轉換為雙精度浮點數 | |
| l2f | 89 | value → result | 將長整型轉換為單精度浮點數 | |
| l2i | 88 | value → result | 將長整型轉換為整數 | |
| ladd | 61 | value1, value2 → result | 將兩個長整型加在一起 | |
| laload | 2f | arrayref, index → value | 從陣列中載入一個長整型 | |
| land | 7f | value1, value2 → result | 兩個長整型的按位與運算 | |
| lastore | 50 | arrayref, index, value → | 將一個長整型儲存到陣列中 | |
| lcmp | 94 | value1, value2 → result | 比較兩個長整型值 | |
| lconst_0 | 09 | → 0L | 將長整型0壓入堆疊 | |
| lconst_1 | 0a | → 1L | 將長整型1壓入堆疊 | |
| ldc | 12 | index | → value | 將常量池(字串、int、float 或類型別)中的常量#index壓入堆疊 |
| ldc_w | 13 | indexbyte1, indexbyte2 | → value | 將常量池(字串、int、float 或類型別)中的常量#index壓入堆疊(寬index構造為indexbyte1 << 8 + indexbyte2) |
| ldc2_w | 14 | indexbyte1, indexbyte2 | → value | 將常量池(雙精度浮點數或長整型)中的常量#index壓入堆疊(寬index構造為indexbyte1 << 8 + indexbyte2) |
| ldiv | 6d | value1, value2 → result | 將兩個長整型數相除 | |
| lload | 16 | index | → value | 從區域性變數 #index 中載入一個長整型值 |
| lload_0 | 1e | → value | 從區域性變數 0 中載入一個長整型值 | |
| lload_1 | 1f | → value | 從區域性變數 1 中載入一個長整型值 | |
| lload_2 | 20 | → value | 從區域性變數 2 中載入一個長整型值 | |
| lload_3 | 21 | → value | 從區域性變數 3 中載入一個長整型值 | |
| lmul | 69 | value1, value2 → result | 將兩個長整型數相乘 | |
| lneg | 75 | value → result | 對一個長整型數取反 | |
| lookupswitch | ab | <0-3 位元組填充>, defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, npairs1, npairs2, npairs3, npairs4, 匹配偏移對... | 鍵 → | 使用鍵從表中查詢目標地址,並從該地址處的指令開始繼續執行 |
| lor | 81 | value1, value2 → result | 兩個長整型數的按位或運算 | |
| lrem | 71 | value1, value2 → result | 兩個長整型數相除的餘數 | |
| lreturn | ad | value → [empty] | 返回一個長整型值 | |
| lshl | 79 | value1, value2 → result | 將長整型數 value1 按位左移 value2 位 | |
| lshr | 7b | value1, value2 → result | 將長整型數 value1 按位右移 value2 位 | |
| lstore | 37 | index | value → | 將長整型數 value 儲存到區域性變數 #index 中 |
| lstore_0 | 3f | value → | 將長整型數 value 儲存到區域性變數 0 中 | |
| lstore_1 | 40 | value → | 將長整型數 value 儲存到區域性變數 1 中 | |
| lstore_2 | 41 | value → | 將長整型數 value 儲存到區域性變數 2 中 | |
| lstore_3 | 42 | value → | 將長整型數 value 儲存到區域性變數 3 中 | |
| lsub | 65 | value1, value2 → result | 將兩個長整型數相減 | |
| lushr | 7d | value1, value2 → result | 將長整型數 value1 按位右移 value2 位,無符號 | |
| lxor | 83 | value1, value2 → result | 兩個長整型數的按位異或運算 | |
| M | ||||
| monitorenter | c2 | objectref → | 進入物件的監視器(“獲取鎖” - 同步化()部分的開始) | |
| monitorexit | c3 | objectref → | 退出物件的監視器(“釋放鎖” - 同步化()部分的結束) | |
| multianewarray | c5 | indexbyte1, indexbyte2, 維度 | count1, [count2,...] → arrayref | 建立一個新的陣列,該陣列具有 維度 維度,元素型別由常量池中的類引用 index(indexbyte1 << 8 + indexbyte2)標識;每個維度的尺寸由 count1, [count2, 等] 標識 |
| N | ||||
| new | bb | indexbyte1, indexbyte2 | → objectref | 建立一個型別為常量池中的類引用 index(indexbyte1 << 8 + indexbyte2)標識的新物件 |
| newarray | bc | atype | count → arrayref | 建立一個包含 count 個由 atype 標識的原始型別元素的新陣列 |
| nop | 00 | [無變化] | 不執行任何操作 | |
| P | ||||
| pop | 57 | value → | 丟棄堆疊頂部的值 | |
| pop2 | 58 | {value2, value1} → | 丟棄堆疊頂部的兩個值(如果它是雙精度或長整型,則丟棄一個值) | |
| putfield | b5 | indexbyte1, indexbyte2 | objectref, value → | 將 value 設定為物件 objectref 中的欄位,其中欄位由常量池中的欄位引用 index(indexbyte1 << 8 + indexbyte2)標識 |
| putstatic | b3 | indexbyte1, indexbyte2 | value → | 將 value 設定為類中的靜態欄位,其中欄位由常量池中的欄位引用 index(indexbyte1 << 8 + indexbyte2)標識 |
| R | ||||
| ret | a9 | index | [無變化] | 從區域性變數 #index 中獲取的地址處繼續執行(與 jsr 的不對稱性是故意的) |
| return | b1 | → [空] | 從方法中返回 void | |
| S | ||||
| saload | 35 | arrayref, index → value | 從陣列中載入短整型 | |
| sastore | 56 | arrayref, index, value → | 將短整型儲存到陣列中 | |
| sipush | 11 | byte1, byte2 | → value | 將一個帶符號的整型數(byte1 << 8 + byte2)壓入堆疊 |
| swap | 5f | value2, value1 → value1, value2 | 交換堆疊頂部的兩個字(注意 value1 和 value2 不能是雙精度或長整型) | |
| T | ||||
| W | ||||
| 未用 | ||||
| impdep1 | fe | 為偵錯程式中的實現相關操作保留;不應出現在任何類檔案中 | ||
| impdep2 | ff | 為偵錯程式中的實現相關操作保留;不應出現在任何類檔案中 | ||
| (無名稱) | cb-fd | 這些值目前未分配給操作碼,併為將來使用保留 | ||
| xxxunusedxxx | ba | 此操作碼“出於歷史原因”保留 | ||
- 位元組碼視覺化器 - 用於視覺化和除錯 Java 位元組碼的免費 Eclipse 外掛
- ObjectWeb 為 Eclipse 提供的位元組碼大綱外掛
- 填補 JVM、其目的以及與 JIT 編譯的優勢之間差距的簡單說明