一般設計
- 機器模型和呼叫慣例旨在模仿常見的實際架構和 C 樣式呼叫慣例:
- 機器是根據註冊建立,因此建立時會固定影格大小。每個影格都包含特定數量的註冊器 (由方法指定),以及執行方法所需的任何附加資料,例如 (但不限於) 程式計數器和包含方法的
.dex
檔案參照。 - 當用於位元值 (例如整數和浮點數) 時,寄存器的寬度會視為 32 位元。相鄰的註冊組合用於 64 位元值。註冊組不須對齊。
- 當用於物件參照時,註冊的寬度足以容納一項此類參照。
- 就位元表示法而言,
(Object) null == (int) 0
。 - 方法的 N 引數會依序放置在方法呼叫結構體的最後 N 暫存器中。寬引數會消耗兩個註冊。例項方法會傳遞
this
參照做為第一個引數。
- 機器是根據註冊建立,因此建立時會固定影格大小。每個影格都包含特定數量的註冊器 (由方法指定),以及執行方法所需的任何附加資料,例如 (但不限於) 程式計數器和包含方法的
- 指令串流中的儲存單位是 16 位元無符號數量。部分指令中的某些位元會遭到忽略 / 必須為零。
- 指令不會無故限制為特定類型。舉例來說,如果指令是移動 32 位元註冊值而無需解讀,則不必指定是否要移動 int 或浮點值。
- 針對字串、類型、欄位和方法的參照,會分別列舉並編入索引的常數集區。
- 位元值文字資料會在指令串流中內嵌表示。
- 因為在實際情況下,方法需要超過 16 個註冊的情況並不常見,而且需要超過八個註冊的情況相當常見,因此許多指令都只會處理前 16 個註冊。在合理可行情況下,指令可參照前 256 個寄存器。此外,部分指令具有可支援更大暫存器數量的變化版本,包括一組萬用
move
指令,可處理v0
至v65535
範圍內的暫存器。如果指令變化版本無法處理所需的暫存器,則暫存器內容會從原始暫存器移至低暫存器 (在作業前),以及/或者從低結果暫存器移至高暫存器 (在作業後)。 - 有幾個「偽指令」用於保存變長資料酬載,並由一般指令 (例如
fill-array-data
) 參照。在執行的正常流程中,絕對不會遇到這類指令。此外,指令必須位於偶數位元組碼偏移位置 (也就是 4 位元組對齊)。為了符合這項要求,如果這類指令無法對齊,則 dex 產生工具必須以間隔符號的形式發出額外的nop
指令。最後,雖然並非必要,但大多數工具都會選擇在方法結尾處發出這些指令,因為如果不這樣做,可能就需要額外指令來分支。 - 在執行中的系統上安裝時,部分指令可能會變更格式,以便進行安裝時的靜態連結最佳化。這樣一來,一旦連結關係明確,就能加快執行速度。如要查看建議的變化版本,請參閱相關的指示格式文件。我們謹慎使用「建議」一詞,因為這些做法並非強制規定。
- 人性化語法和助憶法:
- 引數的「Dest-then-source」排序。
- 部分 Opcode 具有可區分的名稱後置字元,用於指出其運算的類型:
- 類型通用 32 位元操作碼未標示。
- 類型一般 64 位元 Opcode 的後置字串為
-wide
。 - 類型專屬的 Opcode 會加上其類型 (或簡單的縮寫) 做為後置字元,包括:
-boolean
、-byte
、-char
、-short
、-int
、-long
、-float
、-double
、-object
、-string
、-class
和-void
。
- 部分 Opcode 會附上可區分的副檔名,以便區分具有不同指令版面配置或選項的相同運算。這些後置字串會以斜線 (「
/
」) 與主要名稱分隔,主要目的是讓產生及解讀可執行檔的程式碼中,靜態常數與一對一對應,以減少人為的模糊性。 - 在本說明中,每四位元寬度使用一個字元來強調值的寬度 (例如常數的範圍或可能位址的暫存器數量)。
- 例如在「
move-wide/from16 vAA, vBBBB
」指令中:- 「
move
」是基本運算碼,表示基本運算 (移動註冊值)。 - 「
wide
」是名稱後置字串,表示該函式會處理寬 (64 位元) 資料。 - 「
from16
」是運算碼後置字元,表示變體會將 16 位元註冊參照做為來源。 - 「
vAA
」是目的地暫存器 (由作業隱含;再次提醒,規則是目的地引數一律會先出現),必須位於v0
至v255
的範圍內。 - 「
vBBBB
」是來源登錄,必須位於v0
到v65535
的範圍內。
- 「
- 如要進一步瞭解各種指令格式 (列於「運算元式與格式」下方),以及運算碼語法的詳細資訊,請參閱指令格式說明文件。
- 如要進一步瞭解位元碼在整體架構中的適當位置,請參閱
.dex
檔案格式說明文件。
位元碼集摘要
作業與格式 | 助憶法 / 語法 | 引數 | 說明 |
---|---|---|---|
00 10x | nop | 浪費週期。 注意:含有資料的疑似指令會加上這個運算碼,在這種情況下,運算碼單位的高位元組會指出資料的性質。請參閱下方的「 |
|
01 12x | move vA, vB | A: 目的地暫存器 (4 位元)B: 來源暫存器 (4 位元) |
將一個非物件型註冊器的內容移至另一個註冊器。 |
02 22x | move/from16 vAA, vBBBB | A: 目的地暫存器 (8 位元)B: 來源暫存器 (16 位元) |
將一個非物件型註冊器的內容移至另一個註冊器。 |
03 32x | move/16 vAAAA, vBBBB | A: 目的地暫存器 (16 位元)B: 來源暫存器 (16 位元) |
將一個非物件型註冊器的內容移至另一個註冊器。 |
04 12x | move-wide vA, vB | A: 目的地暫存器組 (4 位元)B: 來源暫存器組 (4 位元) |
將一個註冊組合的內容移至另一個註冊組合。 注意:從 |
05 22x | move-wide/from16 vAA, vBBBB | A: 目的地暫存器組 (8 位元)B: 來源暫存器組 (16 位元) |
將一個註冊組合的內容移至另一個註冊組合。 注意:導入方面的注意事項與上述 |
06 32x | move-wide/16 vAAAA, vBBBB | A: 目的地暫存器組 (16 位元)B: 來源暫存器組 (16 位元) |
將一個註冊組合的內容移至另一個註冊組合。 注意:導入方面的注意事項與上述 |
07 12x | move-object vA, vB | A: 目的地暫存器 (4 位元)B: 來源暫存器 (4 位元) |
將一個含有物件的註冊表內容移至另一個註冊表。 |
08 22x | move-object/from16 vAA, vBBBB | A: 目的地暫存器 (8 位元)B: 來源暫存器 (16 位元) |
將一個含有物件的註冊表內容移至另一個註冊表。 |
09 32x | move-object/16 vAAAA, vBBBB | A: 目的地暫存器 (16 位元)B: 來源暫存器 (16 位元) |
將一個含有物件的註冊表內容移至另一個註冊表。 |
0a 11x | move-result vAA | A: 目的地暫存器 (8 位元) |
將最近一次 invoke-kind 的單字非物件結果移至指定的註冊表。這項操作必須在 invoke-kind 之後立即執行,且該 invoke-kind 的 (單字、非物件) 結果不得忽略;其他位置均無效。 |
0b 11x | move-result-wide vAA | A: 目的地暫存器組 (8 位元) |
將最近 invoke-kind 的雙字結果移至指定的註冊組。這項操作必須在 invoke-kind 之後立即執行,且該指令的 (雙字) 結果不得忽略;其他位置皆無效。 |
0c 11x | move-result-object vAA | A: 目的地暫存器 (8 位元) |
將最近一次 invoke-kind 的物件結果移至指定的註冊表。這項操作必須在 invoke-kind 或 filled-new-array 之後立即執行,且不應忽略其 (物件) 結果;否則其他位置均無效。 |
0d 11x | move-exception vAA | A: 目的地暫存器 (8 位元) |
將剛捕獲的例外狀況儲存到指定的註冊表中。這必須是任何例外狀況處理常式的首要指令,且所捕獲的例外狀況不得遭到忽略,且此指令「只能」以例外狀況處理常式的首要指令出現,其他位置皆無效。 |
0e 10x | return-void | 從 void 方法傳回。 |
|
0f 11x | return vAA | A: 傳回值登錄器 (8 位元) |
從單寬 (32 位元) 非物件值傳回方法傳回。 |
10 11x | return-wide vAA | A: 傳回值暫存器組 (8 位元) |
從傳回值的雙寬 (64 位元) 方法傳回。 |
11 11x | return-object vAA | A: 傳回值暫存器 (8 位元) |
從物件傳回方法傳回。 |
12 11n | const/4 vA, #+B | A: 目的地暫存器 (4 位元)B: 已簽署的 int (4 位元) |
將指定的字面值 (已延伸至 32 位元的符號) 移至指定的註冊器。 |
13 21 秒 | const/16 vAA, #+BBBB | A: 目的地暫存器 (8 位元)B: 已簽署的 int (16 位元) |
將指定的字面值 (已延伸至 32 位元的符號) 移至指定的註冊器。 |
14 31i | const vAA, #+BBBBBBBB | A: 目的地暫存器 (8 位元)B: 任意 32 位元常數 |
將指定的常值移至指定的註冊器。 |
15 21h | const/high16 vAA, #+BBBB0000 | A: 目的地暫存器 (8 位元)B: 已簽署的 int (16 位元) |
將指定的字面值 (右零擴展至 32 位元) 移至指定的註冊器。 |
16 21 秒 | const-wide/16 vAA, #+BBBB | A: 目的地暫存器 (8 位元)B: 已簽署的 int (16 位元) |
將指定的字面值 (已擴充至 64 位元的符號) 移至指定的寄存器組。 |
17 31i | const-wide/32 vAA, #+BBBBBBBB | A: 目的地暫存器 (8 位元)B: 已簽署的 int (32 位元) |
將指定的字面值 (已擴充至 64 位元的符號) 移至指定的寄存器組。 |
18 51l | const-wide vAA, #+BBBBBBBBBBBBBBBB | A: 目的地暫存器 (8 位元)B: 任意雙寬 (64 位元) 常數 |
將指定的常值移至指定的暫存器組。 |
19 21h | const-wide/high16 vAA, #+BBBB000000000000 | A: 目的地暫存器 (8 位元)B: 已簽署的 int (16 位元) |
將指定的字面值 (右零延伸至 64 位元) 移至指定的寄存器組。 |
1a 21c | const-string vAA, string@BBBB | A: 目的地暫存器 (8 位元)B: 字串索引 |
將參照由指定索引指定的字串移至指定的註冊器。 |
1b 31c | const-string/jumbo vAA, string@BBBBBBBB | A: 目的地暫存器 (8 位元)B: 字串索引 |
將參照由指定索引指定的字串移至指定的註冊器。 |
1c 21c | const-class vAA, type@BBBB | A: 目的地暫存器 (8 位元)B: 型別索引 |
將參照指定索引所指定類別的參照移至指定的註冊器。如果指定的類型為基本類型,這會儲存基本類型的退化類別參照。 |
1d 11x | monitor-enter vAA | A: 參照含有註冊 (8 位元) |
取得指定物件的監控器。 |
1e 11x | monitor-exit vAA | A: 參照含有註冊 (8 位元) |
釋出指定物件的監控器。 注意:如果這個指令需要擲回例外狀況,則必須以 PC 已進展到指令後的狀態擲回。您或許可以將這視為指令已成功執行 (在某種意義上),而例外狀況是在指令「後」,但在下一個指令有機會執行之前發生。這個定義可讓方法使用監控清理萬用字 (例如 |
1f 21c | check-cast vAA, type@BBBB | A: 參照含有登錄器 (8 位元)B: 型別索引 (16 位元) |
如果指定登錄表中的參照無法轉換為指定類型,則會擲回 ClassCastException 。注意:由於 |
20 22c | instance-of vA, vB, type@CCCC | A: 目的地暫存器 (4 位元)B: 參照暫存器 (4 位元)C: 類型索引 (16 位元) |
如果指定的參照是指定類型的例項,則儲存在指定目的地註冊 1 中;如果不是,則儲存在 0 中。注意:由於 |
21 12x | 陣列長度 vA、vB | A: 目的地暫存器 (4 位元)B: 陣列參照暫存器 (4 位元) |
在指定目的地註冊中儲存指定陣列的長度,以項目為單位 |
22 21c | new-instance vAA, type@BBBB | A: 目的地暫存器 (8 位元)B: 型別索引 |
建構指定類型的新例項,並在目的地儲存對該例項的參照。類型必須參照非陣列類別。 |
23 22c | new-array vA, vB, type@CCCC | A: 目的地暫存器 (4 位元)B: 大小暫存器C: 類型索引 |
建構指定類型和大小的新陣列。類型必須是陣列類型。 |
24 35c | 已填入的陣列 {vC, vD, vE, vF, vG},類型@BBBB |
A: 陣列大小和引數字詞數量 (4 位元)B: 型別索引 (16 位元)C..G: 引數註冊 (每個 4 位元)
|
建構指定類型和大小的陣列,並以提供的內容填入陣列。類型必須是陣列類型。陣列的內容必須是單字 (也就是沒有 long 或 double 的陣列,但參照類型是可接受的)。建構的例項會以「結果」的形式儲存,這與方法叫用指示的儲存結果方式相同,因此建構的例項必須透過後續的 move-result-object 指示 (如果要使用) 移至寄存器。 |
25 3rc | 已填入的陣列/範圍 {vCCCC .. vNNNN},型別@BBBB | A: 陣列大小和引數字節數 (8 位元)B: 型別索引 (16 位元)C: 第一個引數註冊 (16 位元)N = A + C - 1 |
建構指定類型和大小的陣列,並以提供的內容填入陣列。說明和限制與上述 filled-new-array 相同。 |
26 31t | fill-array-data vAA, +BBBBBBBB (附加資料,如下方「fill-array-data-payload 格式」所述) |
A: 陣列參照 (8 位元)B: 以表格資料虛擬指令為基準的帶正號「分支」偏移量 (32 位元)
|
使用指定資料填入指定陣列。參照項目必須是原始類型的陣列,且資料表格必須與其類型相符,且所含元素不得超過陣列可容納的數量。也就是說,陣列可能比資料表大,如果是這種情況,系統只會設定陣列的初始元素,而不會處理其餘元素。 |
27 11x | 擲回 vAA | A: 例外狀況含有暫存器 (8 位元) |
擲回指定的例外狀況。 |
28 10t | goto +AA | A: 有符號分支偏移量 (8 位元) |
無條件跳到指定的指令。 注意:分支偏移值不得為 |
29 20t | goto/16 +AAAA | A: 帶符號分支偏移量 (16 位元) |
無條件跳到指定的指令。 注意:分支偏移值不得為 |
2a 30t | goto/32 +AAAAAAAA | A: 已簽署的分支偏移 (32 位元) |
無條件跳到指定的指令。 |
2b 31t | packed-switch vAA, +BBBBBBBB (附加資料請參閱下方的「packed-switch-payload 格式」) |
A: 註冊以測試B: 已簽署的「分支」偏移至表格資料的疑似指令 (32 位元)
|
根據指定寄存器中的值,使用對應特定整數範圍中每個值的偏移量表格,跳至新的指令,或在沒有相符項目時,跳至下一個指令。 |
2c 31t | sparse-switch vAA, +BBBBBBBB (附加資料請參閱下方的「sparse-switch-payload 格式」) |
A: 註冊以測試B: 已簽署的「分支」偏移量,可用於表格資料的疑似指令
(32 位元)
|
根據指定登錄器中的值,使用值-偏移量組合的排序表跳至新指令,或在沒有相符項目時跳至下一個指令。 |
2d..31 23x | cmpkind vAA、vBB、vCC 2d: cmpl-float (lt bias) 2e: cmpg-float (gt bias) 2f: cmpl-double (lt bias) 30: cmpg-double (gt bias) 31: cmp-long |
A: 目的地暫存器 (8 位元)B: 第一個來源暫存器或組C: 第二個來源暫存器或組 |
執行指定的浮點或 long 比較作業,如果是 b == c ,請將 a 設為 0 ;如果是 b > c ,請設為 1 ;如果是 b < c ,請設為 -1 。浮點運算所列的「偏差」會指出 NaN 比較的處理方式:如果是「gt bias」,指令會針對 NaN 比較傳回 1 ;如果是「lt bias」,則會傳回 -1 。舉例來說,如要檢查浮點 |
32..37 22t | if-test vA, vB, +CCCC 32: if-eq 33: if-ne 34: if-lt 35: if-ge 36: if-gt 37: if-le |
A: 要測試的第一個暫存器 (4 位元)B: 要測試的第二個暫存器 (4 位元)C: 帶符號分支偏移量 (16 位元) |
如果指定的兩個註冊值符合指定的比較條件,則分支至指定的目的。 注意:分支偏移值不得為 |
38..3d 21t | if-testz vAA, +BBBB 38: if-eqz 39: if-nez 3a: if-ltz 3b: if-gez 3c: if-gtz 3d: if-lez |
A: 要測試的註冊 (8 位元)B: 有符號分支偏移量 (16 位元) |
如果指定的註冊器值與指定的 0 比較,則分支至指定的目的。 注意:分支偏移值不得為 |
3e..43 10x | (未使用) | (未使用) | |
44..51 23x | arrayop vAA、vBB、vCC 44: aget 45: aget-wide 46: aget-object 47: aget-boolean 48: aget-byte 49: aget-char 4a: aget-short 4b: aput 4c: aput-wide 4d: aput-object 4e: aput-boolean 4f: aput-byte 50: aput-char 51: aput-short |
A: 值登錄器或組合;可能是來源或目的地 (8 位元)B: 陣列登錄器 (8 位元)C: 索引登錄器 (8 位元) |
在指定陣列的指定索引處執行已識別的陣列運算,並將值載入或儲存至值登錄。 |
52..5f 22c | iinstanceop vA, vB, field@CCCC 52: iget 53: iget-wide 54: iget-object 55: iget-boolean 56: iget-byte 57: iget-char 58: iget-short 59: iput 5a: iput-wide 5b: iput-object 5c: iput-boolean 5d: iput-byte 5e: iput-char 5f: iput-short |
A: 值登錄或組合;可能是來源或目的地 (4 位元)B: 物件登錄 (4 位元)C: 例項欄位參照索引 (16 位元) |
使用已識別的欄位,執行已識別的物件執行個體欄位作業,並載入或儲存至值登錄。 注意:這些 Opcode 是靜態連結的合理候選項目,可將欄位引數改為更直接的偏移值。 |
60..6d 21c | sstaticop vAA, field@BBBB 60: sget 61: sget-wide 62: sget-object 63: sget-boolean 64: sget-byte 65: sget-char 66: sget-short 67: sput 68: sput-wide 69: sput-object 6a: sput-boolean 6b: sput-byte 6c: sput-char 6d: sput-short |
A: 值登錄或組合;可能是來源或目的地 (8 位元)B: 靜態欄位參照索引 (16 位元) |
使用已識別的靜態欄位,執行已識別的物件靜態欄位作業,並載入或儲存至值登錄。 注意:這些 Opcode 是靜態連結的合理候選項目,可將欄位引數改為更直接的偏移值。 |
6e..72 35c | invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB 6e: invoke-virtual 6f: invoke-super 70: invoke-direct 71: invoke-static 72: invoke-interface |
A: 引數字詞數量 (4 位元)B: 方法參照索引 (16 位元)C..G: 引數暫存器 (每個 4 位元)
|
呼叫指定的方法。結果 (如有) 可能會與適當的 move-result* 變體一併儲存,做為後續立即執行的指令。
當 在 DEX 檔案
注意:這些 Opcode 是靜態連結的合理候選項目,可將方法引數改為更直接的偏移值 (或其組合)。 |
73 10x | (未使用) | (未使用) | |
74..78 3rc | invoke-kind/range {vCCCC .. vNNNN}, meth@BBBB 74: invoke-virtual/range 75: invoke-super/range 76: invoke-direct/range 77: invoke-static/range 78: invoke-interface/range |
A: 引數字數 (8 位元)B: 方法參照索引 (16 位元)C: 第一個引數註冊 (16 位元)N = A + C - 1 |
呼叫指定的方法。如需詳細資訊、注意事項和建議,請參閱上述第一個 invoke-kind 說明。 |
79..7a 10x | (未使用) | (未使用) | |
7b..8f 12x | unop vA, vB 7b: neg-int 7c: not-int 7d: neg-long 7e: not-long 7f: neg-float 80: neg-double 81: int-to-long 82: int-to-float 83: int-to-double 84: long-to-int 85: long-to-float 86: long-to-double 87: float-to-int 88: float-to-long 89: float-to-double 8a: double-to-int 8b: double-to-long 8c: double-to-float 8d: int-to-byte 8e: int-to-char 8f: int-to-short |
A: 目的地暫存器或組合 (4 位元)B: 來源暫存器或組合 (4 位元) |
對來源暫存器執行已識別的單一運算,並將結果儲存在目的地暫存器中。 |
90..af 23x | binop vAA, vBB, vCC 90: add-int 91: sub-int 92: mul-int 93: div-int 94: rem-int 95: and-int 96: or-int 97: xor-int 98: shl-int 99: shr-int 9a: ushr-int 9b: add-long 9c: sub-long 9d: mul-long 9e: div-long 9f: rem-long a0: and-long a1: or-long a2: xor-long a3: shl-long a4: shr-long a5: ushr-long a6: add-float a7: sub-float a8: mul-float a9: div-float aa: rem-float ab: add-double ac: sub-double ad: mul-double ae: div-double af: rem-double |
A: 目的地暫存器或組 (8 位元)B: 第一個來源暫存器或組 (8 位元)C: 第二個來源暫存器或組 (8 位元) |
對兩個來源暫存器執行已識別的二進位運算,並將結果儲存在目的地暫存器中。 注意:與其他 |
b0..cf 12x | binop/2addr vA, vB b0: add-int/2addr b1: sub-int/2addr b2: mul-int/2addr b3: div-int/2addr b4: rem-int/2addr b5: and-int/2addr b6: or-int/2addr b7: xor-int/2addr b8: shl-int/2addr b9: shr-int/2addr ba: ushr-int/2addr bb: add-long/2addr bc: sub-long/2addr bd: mul-long/2addr be: div-long/2addr bf: rem-long/2addr c0: and-long/2addr c1: or-long/2addr c2: xor-long/2addr c3: shl-long/2addr c4: shr-long/2addr c5: ushr-long/2addr c6: add-float/2addr c7: sub-float/2addr c8: mul-float/2addr c9: div-float/2addr ca: rem-float/2addr cb: add-double/2addr cc: sub-double/2addr cd: mul-double/2addr ce: div-double/2addr cf: rem-double/2addr |
A: 目的地和第一個來源暫存器或組合 (4 位元)B: 第二個來源暫存器或組合 (4 位元) |
對兩個來源暫存器執行已識別的二進位運算,並將結果儲存在第一個來源暫存器中。 注意:與其他 |
d0..d7 22 秒 | binop/lit16 vA, vB, #+CCCC d0: add-int/lit16 d1: rsub-int (reverse subtract) d2: mul-int/lit16 d3: div-int/lit16 d4: rem-int/lit16 d5: and-int/lit16 d6: or-int/lit16 d7: xor-int/lit16 |
A: 目的地暫存器 (4 位元)B: 來源暫存器 (4 位元)C: 已簽署的 int 常數 (16 位元) |
在指定的登錄器 (第一個引數) 和文字值 (第二個引數) 上執行指定的二元運算,並將結果儲存在目的地登錄器中。 注意:
|
d8..e2 22b | binop/lit8 vAA, vBB, #+CC d8: add-int/lit8 d9: rsub-int/lit8 da: mul-int/lit8 db: div-int/lit8 dc: rem-int/lit8 dd: and-int/lit8 de: or-int/lit8 df: xor-int/lit8 e0: shl-int/lit8 e1: shr-int/lit8 e2: ushr-int/lit8 |
A: 目的地暫存器 (8 位元)B: 來源暫存器 (8 位元)C: 已簽署的 int 常數 (8 位元) |
在指定的登錄器 (第一個引數) 和文字值 (第二個引數) 上執行指定的二元運算,並將結果儲存在目的地登錄器中。 注意:如要進一步瞭解 |
e3..f9 10 倍 | (未使用) | (未使用) | |
fa 45cc | invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH |
A: 引數字節數 (4 位元) B: 方法參照索引 (16 位元) C: 接收器 (4 位元) D..G: 引數暫存器 (每個 4 位元) H: 原型參照索引 (16 位元)
|
叫用指定簽章多型別方法。結果 (如有) 可能會與適當的 move-result* 變化版本一併儲存,做為後續立即執行的指令。方法參照必須是簽章多型態方法,例如 java.lang.invoke.MethodHandle.invoke 或 java.lang.invoke.MethodHandle.invokeExact 。接收器必須是支援所要叫用的簽章多型態方法的物件。 原型參照會說明提供的引數類型和預期的傳回類型。 invoke-polymorphic 位元碼在執行時可能會發生例外狀況。針對所叫用的簽名多型別方法,API 說明文件會說明這些例外狀況。從 038 版起,會出現在 Dex 檔案中。 |
fb 4rcc | invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH |
A: 引數字數 (8 位元) B: 方法參照索引 (16 位元) C: 接收器 (16 位元) H: 原型參照索引 (16 位元) N = A + C - 1
|
叫用指定的方法句柄。詳情請參閱上方的invoke-polymorphic 說明。從 038 版起,會出現在 Dex 檔案中。 |
fc 35c | invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB |
A: 引數字詞數量 (4 位元) B: 呼叫網站參照索引 (16 位元) C..G: 引數暫存器 (每個 4 位元)
|
解析並叫用指定的呼叫網址。叫用作業的結果 (如有) 可能會與適當的 move-result* 變化版本一併儲存,做為後續指令。この命令會在兩個階段執行:呼叫網址解析和呼叫網址叫用。 呼叫端點解析會檢查指定的呼叫端點是否有相關聯的 java.lang.invoke.CallSite 例項。如果沒有,系統會使用 DEX 檔案中的引數,叫用指定呼叫網址的啟動連結器方法 (請參閱 call_site_item)。引導程式連結器方法會傳回 java.lang.invoke.CallSite 例項,如果沒有關聯,則會與指定的呼叫網址建立關聯。另一個執行緒可能已先建立關聯,如果是這樣,指令的執行作業會繼續使用第一個關聯的 java.lang.invoke.CallSite 例項。呼叫網站呼叫會在已解析 java.lang.invoke.CallSite 例項的 java.lang.invoke.MethodHandle 目標上執行。如果使用方法句柄和 invoke-custom 指令的引數,以確切方法句柄叫用方式執行 invoke-polymorphic (如上所述),系統就會叫用目標。引導程式連結器方法所產生的例外狀況會包裝在 java.lang.BootstrapMethodError 中。如果符合下列條件,系統也會擲回 BootstrapMethodError :
038 版起,會出現在 Dex 檔案中。 |
fd 3rc | invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB |
A: 引數字數 (8 位元) B: 呼叫網站參照索引 (16 位元) C: 第一個引數註冊 (16 位元) N = A + C - 1
|
解析並叫用呼叫位置。詳情請參閱上方的invoke-custom 說明。從 038 版起,會出現在 Dex 檔案中。 |
fe 21c | const-method-handle vAA, method_handle@BBBB | A: 目的地登錄 (8 位元)B: 方法句柄索引 (16 位元) |
將參照由指定索引指定的方法句柄移至指定的註冊器。 從 039 版起,會出現在 Dex 檔案中。 |
ff 21c | const-method-type vAA, proto@BBBB | A: 目的地註冊 (8 位元)B: 方法原型參考資料 (16 位元) |
將參照指定索引所指定方法原型的參照,移至指定的註冊器。 從 039 版起,會出現在 Dex 檔案中。 |
Packed-Switch-Payload 格式
名稱 | 格式 | 說明 |
---|---|---|
ident | ushort = 0x0100 | 辨識虛擬指令 |
size | ushort | 資料表中的項目數 |
first_key | int | 第一個 (也是最低) 切換案例值 |
目標 | int[] | size 相對分支目標的清單。目標是相對於切換 Opcode 的位址,而非這個表格的位址。 |
注意:這個資料表的執行個體程式碼單位總數為 (size * 2) + 4
。
稀疏切換酬載格式
名稱 | 格式 | 說明 |
---|---|---|
ident | ushort = 0x0200 | 辨識虛擬指令 |
size | ushort | 資料表中的項目數 |
金鑰 | int[] | size 鍵值清單,由低到高排序 |
目標 | int[] | size 相對分支目標清單,每個項目都對應至相同索引的鍵值。目標是相對於切換 Opcode 的位址,而非這個表格的位址。 |
注意:這個資料表的執行個體程式碼單位總數為 (size * 4) + 2
。
fill-array-data-payload 格式
名稱 | 格式 | 說明 |
---|---|---|
ident | ushort = 0x0300 | 辨識虛擬指令 |
element_width | ushort | 每個元素的位元組數 |
size | uint | 資料表中的元素數 |
data | ubyte[] | 資料值 |
注意:這個資料表的執行個體程式碼單位總數為 (size * element_width + 1) / 2 + 4
。
數學運算詳細資料
注意:浮點運算必須遵循 IEEE 754 規則,使用四捨五入和漸進性下溢,除非另有說明。
Opcode | C 語意 | 附註 |
---|---|---|
neg-int | int32 a; int32 result = -a; |
一元二補法。 |
not-int | int32 a; int32 result = ~a; |
一元一補。 |
neg-long | int64 a; int64 result = -a; |
一元二補法。 |
not-long | int64 a; int64 result = ~a; |
一元一補。 |
neg-float | float a; float result = -a; |
浮點值否定。 |
neg-double | double a; double result = -a; |
浮點值否定。 |
int-to-long | int32 a; int64 result = (int64) a; |
將 int32 的符號擴展至 int64 。 |
int 轉換為 float | int32 a; float result = (float) a; |
使用四捨五入法將 int32 轉換為 float 。這會導致部分值的精確度降低。 |
int 轉換為 double | int32 a; double result = (double) a; |
將 int32 轉換為 double 。 |
long-to-int | int64 a; int32 result = (int32) a; |
將 int64 截斷為 int32 。 |
long-to-float | int64 a; float result = (float) a; |
使用四捨五入法將 int64 轉換為 float 。這會導致部分值的精確度降低。 |
long-to-double | int64 a; double result = (double) a; |
使用四捨五入法將 int64 轉換為 double 。這會導致部分值的精確度降低。 |
浮點數轉整數 | float a; int32 result = (int32) a; |
使用捨入法將 float 轉換為 int32 。NaN 和 -0.0 (負零) 會轉換為整數 0 。無窮大和值的大小過大而無法表示時,會根據符號轉換為 0x7fffffff 或 -0x80000000 。 |
float-to-long | float a; int64 result = (int64) a; |
使用捨入法將 float 轉換為 int64 。此處適用與 float-to-int 相同的特殊情況規則,但超出範圍的值會根據符號轉換為 0x7fffffffffffffff 或 -0x8000000000000000 。 |
浮點轉換為雙精度 | float a; double result = (double) a; |
將 float 轉換為 double ,並確切保留該值。 |
double-to-int | double a; int32 result = (int32) a; |
使用捨入法將 double 轉換為 int32 。這裡適用的特殊案例規則與 float-to-int 相同。 |
double-to-long | double a; int64 result = (int64) a; |
使用捨入法將 double 轉換為 int64 。這裡適用的特殊案例規則與 float-to-long 相同。 |
double-to-float | double a; float result = (float) a; |
使用四捨五入法將 double 轉換為 float 。這會導致部分值的精確度降低。 |
int 到位元組 | int32 a; int32 result = (a << 24) >> 24; |
將 int32 截斷為 int8 ,延長結果的符號。 |
int 轉換為 char | int32 a; int32 result = a & 0xffff; |
將 int32 截斷為 uint16 ,但不延伸符號。 |
int-to-short | int32 a; int32 結果 = (a << 16) >> 16; |
將 int32 截斷為 int16 ,延長結果的符號。 |
add-int | int32 a, b; int32 result = a + b; |
二補加法。 |
子 int | int32 a, b; int32 result = a - b; |
二補減法。 |
rsub-int | int32 a, b; int32 result = b - a; |
二補法反向減法。 |
mul-int | int32 a, b; int32 result = a * b; |
二補乘法。 |
div-int | int32 a, b; int32 result = a / b; |
二補法除法,四捨五入 (也就是截斷為整數)。如果 b == 0 ,則會擲回 ArithmeticException 。 |
rem-int | int32 a, b; int32 result = a % b; |
除法後的二補餘數。結果的符號與 a 相同,更精確的定義為 result == a - (a / b) * b 。如果 b == 0 ,則會擲回 ArithmeticException 。 |
and-int | int32 a, b; int32 result = a & b; |
位元 AND。 |
or-int | int32 a, b; int32 result = a | b; |
位元 OR。 |
xor-int | int32 a, b; int32 result = a ^ b; |
位元 XOR。 |
shl-int | int32 a, b; int32 result = a << (b & 0x1f); |
位元左移 (帶有遮罩引數)。 |
shr-int | int32 a, b; int32 result = a >> (b & 0x1f); |
以位元為單位向右移位 (含遮罩引數)。 |
ushr-int | uint32 a, b; int32 result = a >> (b & 0x1f); |
位元位移右 (含遮罩引數)。 |
add-long | int64 a, b; int64 result = a + b; |
二補加法。 |
子長度 | int64 a, b; int64 result = a - b; |
二補減法。 |
mul-long | int64 a, b; int64 result = a * b; |
二補乘法。 |
div-long | int64 a, b; int64 result = a / b; |
二補法除法,四捨五入 (也就是截斷為整數)。如果 b == 0 ,則會擲回 ArithmeticException 。 |
rem-long | int64 a, b; int64 result = a % b; |
除法後的二補餘數。結果的符號與 a 相同,更精確的定義為 result == a - (a / b) * b 。如果 b == 0 ,則會擲回 ArithmeticException 。 |
and-long | int64 a, b; int64 result = a & b; |
位元 AND。 |
or-long | int64 a, b; int64 result = a | b; |
位元 OR。 |
xor-long | int64 a, b; int64 result = a ^ b; |
位元 XOR。 |
shl-long | int64 a; int32 b; int64 result = a << (b & 0x3f); |
位元左移 (帶有遮罩引數)。 |
shr-long | int64 a; int32 b; int64 result = a >> (b & 0x3f); |
位元有符號向右移位 (使用遮罩引數)。 |
ushr-long | uint64 a; int32 b; int64 result = a >> (b & 0x3f); |
位元位移右 (含遮罩引數)。 |
add-float | float a, b; float result = a + b; |
浮點加法。 |
子浮動 | float a, b; float result = a - b; |
浮點數減法。 |
mul-float | float a, b; float result = a * b; |
浮點乘法。 |
div-float | float a, b; float result = a / b; |
浮點除法。 |
rem-float | float a, b; float result = a % b; |
除法後的浮點餘數。這個函式與 IEEE 754 餘數不同,並定義為 result == a - roundTowardZero(a / b) * b 。 |
add-double | double a, b; double result = a + b; |
浮點加法。 |
子雙精度浮點數 | double a, b; double result = a - b; |
浮點數減法。 |
mul-double | double a, b; double result = a * b; |
浮點乘法。 |
div-double | double a, b; double result = a / b; |
浮點除法。 |
rem-double | double a, b; double result = a % b; |
除法後的浮點餘數。這個函式與 IEEE 754 餘數不同,並定義為 result == a - roundTowardZero(a / b) * b 。 |