一般設計
- 機器模型和調用約定旨在近似模仿常見的真實架構和 C 風格的調用約定:
- 該機器是基於寄存器的,並且幀在創建時的大小是固定的。每個幀由特定數量的寄存器(由方法指定)以及執行該方法所需的任何附加數據組成,例如(但不限於)程序計數器和對包含該方法的
.dex
文件的引用. - 當用於位值(例如整數和浮點數)時,寄存器被認為是 32 位寬。相鄰寄存器對用於 64 位值。寄存器對沒有對齊要求。
- 當用於對象引用時,寄存器被認為足夠寬以容納一個這樣的引用。
- 就按位表示而言,
(Object) null == (int) 0
。 - 方法的N個參數按順序位於方法調用幀的最後N個寄存器中。寬參數消耗兩個寄存器。實例方法通過
this
引用作為它們的第一個參數。
- 該機器是基於寄存器的,並且幀在創建時的大小是固定的。每個幀由特定數量的寄存器(由方法指定)以及執行該方法所需的任何附加數據組成,例如(但不限於)程序計數器和對包含該方法的
- 指令流中的存儲單元是一個 16 位的無符號數。某些指令中的某些位被忽略/必須為零。
- 說明不會無緣無故地限制在特定類型上。例如,移動 32 位寄存器值而不進行解釋的指令不必指定它們是移動整數還是浮點數。
- 對於字符串、類型、字段和方法的引用,有單獨的枚舉和索引常量池。
- 按位文字數據在指令流中以內聯方式表示。
- 因為,在實踐中,需要超過 16 個寄存器的方法並不常見,而且因為需要超過 8 個寄存器是相當普遍的,所以許多指令僅限於尋址前 16 個寄存器。在合理可能的情況下,指令最多允許引用前 256 個寄存器。此外,一些指令具有允許更大寄存器計數的變體,包括一對可以尋址範圍為
v0
-v65535
的寄存器的包羅萬象的move
指令。在指令變體無法尋址所需寄存器的情況下,期望寄存器內容從原始寄存器移動到低寄存器(在操作之前)和/或從低結果寄存器移動到高註冊(操作後)。 - 有幾個“偽指令”用於保存可變長度的數據有效負載,它們被常規指令引用(例如,
fill-array-data
)。在正常的執行流程中絕不能遇到此類指令。此外,指令必須位於偶數字節碼偏移量上(即 4 字節對齊)。為了滿足這個要求,dex 生成工具必鬚髮出一個額外的nop
指令作為間隔符,如果這樣的指令否則會不對齊。最後,雖然不是必需的,但預計大多數工具會選擇在方法結束時發出這些指令,否則可能需要額外的指令來圍繞它們進行分支。 - 當安裝在正在運行的系統上時,一些指令可能會被改變,改變它們的格式,作為安裝時的靜態鏈接優化。這是為了在已知鏈接後更快地執行。有關建議的變體,請參閱相關的說明格式文檔。謹慎使用“建議”一詞;實施這些不是強制性的。
- 人類語法和助記符:
- 參數的目標然後源排序。
- 一些操作碼有一個明確的名稱後綴來指示它們操作的類型:
- 類型通用 32 位操作碼未標記。
- 通用類型 64 位操作碼以
-wide
為後綴。 - 特定類型的操作碼以它們的類型(或簡單的縮寫)為後綴,是以下之一:
-boolean
-byte
-char
-short
-int
-void
-long
-float
-double
-string
-class
-object
- 一些操作碼具有消除歧義的後綴,以區分具有不同指令佈局或選項的其他相同操作。這些後綴用斜杠(“
/
”)與主名稱分開,主要是為了在生成和解釋可執行文件的代碼中與靜態常量進行一對一映射(即減少歧義)對於人類)。 - 在此處的描述中,通過使用每四位寬度的字符來強調值的寬度(例如,指示常數的範圍或可能尋址的寄存器的數量)。
- 例如,在指令“
move-wide/from16 vAA, vBBBB
”中:- “
move
”是基本操作碼,表示基本操作(移動寄存器的值)。 - “
wide
”是名稱後綴,表示它對寬(64 位)數據進行操作。 - “
from16
”是操作碼後綴,表示具有 16 位寄存器引用作為源的變體。 - “
vAA
”是目標寄存器(由操作暗示;同樣,規則是目標參數總是在前),它必須在v0
–v255
範圍內。 - “
vBBBB
”是源寄存器,必須在v0
–v65535
範圍內。
- “
- 有關各種指令格式(在“操作和格式”下列出)以及操作碼語法的詳細信息,請參閱指令格式文檔。
- 有關字節碼適合大局的更多詳細信息,請參閱
.dex
文件格式文檔。
字節碼集總結
操作和格式 | 助記符/語法 | 論據 | 描述 |
---|---|---|---|
00 10x | 無 | 廢物循環。 注意:承載數據的偽指令用此操作碼標記,在這種情況下,操作碼單元的高位字節指示數據的性質。請參閱下面的“ | |
01 12x | 移動 vA, vB | A: 目的寄存器(4位)B: 源寄存器(4位) | 將一個非對象寄存器的內容移動到另一個。 |
02 22x | move/from16 vAA, vBBBB | A: 目的寄存器(8位)B: 源寄存器(16位) | 將一個非對象寄存器的內容移動到另一個。 |
03 32x | 移動/16 vAAAA, vBBBB | A: 目的寄存器(16位)B: 源寄存器(16位) | 將一個非對象寄存器的內容移動到另一個。 |
04 12x | 移動範圍 vA, vB | A: 目標寄存器對(4 位)B: 源寄存器對(4位) | 將一個寄存器對的內容移動到另一個。 注意:從 |
05 22x | move-wide/from16 vAA, vBBBB | A: 目標寄存器對(8 位)B: 源寄存器對(16 位) | 將一個寄存器對的內容移動到另一個。 注意:實現注意事項與上面的 |
06 32x | 移動範圍/16 vAAAA, vBBBB | A: 目標寄存器對(16 位)B: 源寄存器對(16 位) | 將一個寄存器對的內容移動到另一個。 注意:實現注意事項與上面的 |
07 12x | 移動對象 vA, vB | A: 目的寄存器(4位)B: 源寄存器(4位) | 將一個對象承載寄存器的內容移動到另一個。 |
08 22x | 移動對象/from16 vAA, vBBBB | A: 目的寄存器(8位)B: 源寄存器(16位) | 將一個對象承載寄存器的內容移動到另一個。 |
09 32x | 移動對象/16 vAAAA, vBBBB | A: 目的寄存器(16位)B: 源寄存器(16位) | 將一個對象承載寄存器的內容移動到另一個。 |
0a 11x | 移動結果 vAA | A: 目的寄存器(8位) | 將最近invoke- kind 的單字非對象結果移動到指定的寄存器中。這必須作為在其(單字,非對象)結果不應被忽略的invoke- kind 之後立即執行的指令;其他任何地方都是無效的。 |
0b 11x | 移動結果範圍的 vAA | A: 目標寄存器對(8 位) | 將最近invoke- kind 的雙字結果移動到指定的寄存器對中。這必須作為在其(雙字)結果不可忽略的invoke- kind 之後立即執行的指令;其他任何地方都是無效的。 |
0c 11x | 移動結果對象 vAA | A: 目的寄存器(8位) | 將最近invoke- kind 的對象結果移動到指定的寄存器中。這必須作為在其(對象)結果不可忽略的invoke- kind 或filled-new-array 之後立即執行的指令;其他任何地方都是無效的。 |
0d 11x | 移動異常 vAA | A: 目的寄存器(8位) | 將剛剛捕獲的異常保存到給定的寄存器中。這必須是其捕獲的異常不會被忽略的任何異常處理程序的第一條指令,並且該指令只能作為異常處理程序的第一條指令出現;其他任何地方都是無效的。 |
0e 10x | 返回無效 | 從void 方法返回。 | |
0f 11x | 返回 vAA | A: 返回值寄存器(8位) | 從單寬度(32 位)非對象值返回方法返回。 |
10 11 倍 | 回報範圍的 vAA | A: 返回值寄存器對(8位) | 從雙寬度(64 位)值返回方法返回。 |
11 11x | 返回對象 vAA | A: 返回值寄存器(8位) | 從對象返回方法返回。 |
12 11n | 常數/4 伏安,#+B | A: 目的寄存器(4位)B: 有符號整數(4 位) | 將給定的文字值(符號擴展為 32 位)移動到指定的寄存器中。 |
13 21秒 | const/16 vAA, #+BBBB | A: 目的寄存器(8位)B: 有符號整數(16 位) | 將給定的文字值(符號擴展為 32 位)移動到指定的寄存器中。 |
14 31i | 常量 vAA, #+BBBBBBBB | A: 目的寄存器(8位)B: 任意 32 位常數 | 將給定的文字值移動到指定的寄存器中。 |
15 21 小時 | const/high16 vAA, #+BBBB0000 | A: 目的寄存器(8位)B: 有符號整數(16 位) | 將給定的文字值(右零擴展為 32 位)移動到指定的寄存器中。 |
16 21s | const-wide/16 vAA, #+BBBB | A: 目的寄存器(8位)B: 有符號整數(16 位) | 將給定的文字值(符號擴展為 64 位)移動到指定的寄存器對中。 |
17 31i | const-wide/32 vAA, #+BBBBBBBB | A: 目的寄存器(8位)B: 有符號整數(32 位) | 將給定的文字值(符號擴展為 64 位)移動到指定的寄存器對中。 |
18 51升 | 常量範圍的 vAA,#+BBBBBBBBBBBBBBBB | A: 目的寄存器(8位)B: 任意雙寬度(64 位)常量 | 將給定的文字值移動到指定的寄存器對中。 |
19 21 小時 | const-wide/high16 vAA, #+BBBB000000000000 | A: 目的寄存器(8位)B: 有符號整數(16 位) | 將給定的文字值(右零擴展為 64 位)移動到指定的寄存器對中。 |
1a 21c | 常量字符串 vAA,字符串@BBBB | A: 目的寄存器(8位)B: 字符串索引 | 將對給定索引指定的字符串的引用移動到指定的寄存器中。 |
1b 31c | 常量字符串/巨型 vAA,字符串@BBBBBBBB | A: 目的寄存器(8位)B: 字符串索引 | 將對給定索引指定的字符串的引用移動到指定的寄存器中。 |
1c 21c | 常量類 vAA,類型@BBBB | A: 目的寄存器(8位)B: 類型索引 | 將給定索引指定的類的引用移動到指定的寄存器中。在指示類型是原始類型的情況下,這將存儲對原始類型的退化類的引用。 |
1d 11x | 監控輸入 vAA | A: 參考軸承寄存器(8位) | 獲取指示對象的監視器。 |
1e 11x | 監視器退出 vAA | A: 參考軸承寄存器(8位) | 釋放指示對象的監視器。 注意:如果這條指令需要拋出一個異常,它必須這樣做,就好像 pc 已經超越了這條指令。將其視為指令成功執行(在某種意義上)以及在指令之後但在下一條指令有機會運行之前拋出異常可能很有用。這個定義使得一個方法可以使用一個監視器清理 catch-all(例如 |
1f 21c | 檢查鑄造 vAA,類型@BBBB | A: 參考軸承寄存器(8位)B: 類型索引(16位) | 如果給定寄存器中的引用不能轉換為指定的類型,則拋出ClassCastException 。注意:由於 |
20 22c | vA、vB、類型@CCCC 的實例 | A: 目的寄存器(4位)B: 參考軸承寄存器(4位)C: 類型索引(16位) | 如果指示的引用是給定類型的實例,則存儲在給定的目標寄存器1 ,否則存儲0 。注意:由於 |
21 12 倍 | 數組長度 vA, vB | A: 目的寄存器(4位)B: 數組引用承載寄存器(4位) | 將指定數組的長度存儲在給定的目標寄存器中,以條目為單位 |
22 21c | 新實例 vAA,類型@BBBB | A: 目的寄存器(8位)B: 類型索引 | 構造指定類型的新實例,並將對它的引用存儲在目標中。該類型必須引用非數組類。 |
23 22c | 新數組 vA, vB, type@CCCC | A: 目的寄存器(4位)B: 大小寄存器C: 類型索引 | 構造一個指定類型和大小的新數組。類型必須是數組類型。 |
24 35分 | 填充新數組 {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 31噸 | fill-array-data vAA, +BBBBBBBB (在“ fill-array-data-payload Format”中指定的補充數據) | A: 數組引用(8位)B: 表數據偽指令的帶符號“分支”偏移量(32 位) | 用指定的數據填充給定的數組。引用必須是一個基元數組,並且數據表必須在類型上匹配它,並且包含的元素不能超過數組的大小。也就是說,數組可能比表格大,如果是這樣,則只設置數組的初始元素,其餘部分不做。 |
27 11 倍 | 投擲 vAA | A: 異常承載寄存器(8位) | 拋出指示的異常。 |
28 10噸 | 轉到+AA | A: 符號分支偏移量(8 位) | 無條件跳轉到指定指令。 注意:分支偏移量不得為 |
29 20噸 | 轉到/16 +AAAA | A: 符號分支偏移量(16 位) | 無條件跳轉到指定指令。 注意:分支偏移量不得為 |
2a 30t | 轉到/32 +AAAAAAAAA | A: 符號分支偏移量(32 位) | 無條件跳轉到指定指令。 |
2b 31噸 | packed-switch vAA, +BBBBBBBB (帶有補充數據,如下面“ packed-switch-payload Format”中指定的) | A: 註冊測試B: 表數據偽指令的帶符號“分支”偏移量(32 位) | 根據給定寄存器中的值跳轉到一條新指令,使用與特定整數範圍內的每個值對應的偏移量表,如果沒有匹配,則跳到下一條指令。 |
2c 31噸 | sparse-switch vAA, +BBBBBBBB (在“ sparse-switch-payload Format”中指定的補充數據) | A: 註冊測試B: 表數據偽指令的帶符號“分支”偏移量(32 位) | 根據給定寄存器中的值跳轉到一條新指令,使用值偏移對的有序表,如果沒有匹配,則跳轉到下一條指令。 |
2d..31 23x | cmp種類vAA、vBB、vCC 2d: cmpl-float (lt 偏差) 2e: cmpg-float (gt 偏差) 2f: cmpl-double (lt 偏差) 30: cmpg-double (gt 偏差) 31:cmp-long | A: 目的寄存器(8位)B: 第一個源寄存器或對C: 第二個源寄存器或對 | 執行指示的浮點或long 比較,如果b == c 將a 設置為0 ,如果b > c 設置為1 ,如果b < c 設置-1 。為浮點運算列出的“偏差”指示如何處理NaN 比較:“gt bias”指令返回1 用於NaN 比較,“lt bias”指令返回-1 。例如,要檢查浮點 |
32..37 22噸 | if-測試vA、vB、+CCCC 32: if-eq 33:如果-ne 34:如果-lt 35:如果-格 36:如果-gt 37:如果-le | A: 要測試的第一個寄存器(4 位)B: 要測試的第二個寄存器(4 位)C: 有符號分支偏移量(16 位) | 如果給定的兩個寄存器的值按指定進行比較,則跳轉到給定的目標。 注意:分支偏移量不得為 |
38..3d 21t | if-測試z vAA, +BBBB 38:如果-eqz 39:如果-內茲 3a:如果-ltz 3b: if-gez 3c:如果-gtz 3d: if-lez | A: 要測試的寄存器(8位)B: 有符號分支偏移量(16 位) | 如果給定寄存器的值與指定的 0 比較,則跳轉到給定目標。 注意:分支偏移量不得為 |
3e..43 10x | (沒用過) | (沒用過) | |
44..51 23 倍 | arrayop vAA、vBB、vCC 44:得到 45:全年齡 46:獲取對象 47:aget-布爾值 48:獲取字節 49:get-char 4a: 做空 4b:輸入 4c:全範圍 4d: aput-object 4e: aput-布爾值 4f:輸入字節 50:輸入字符 51:做空 | A: 值寄存器或對;可以是源或目標(8 位)B: 數組寄存器(8位)C: 變址寄存器(8位) | 在給定數組的標識索引處執行標識的數組操作,加載或存儲到值寄存器中。 |
52..5f 22c | i instanceop vA, vB, field@CCCC 52:我得到 53:整個 iget 54:iget對象 55:iget-布爾值 56:iget字節 57:iget-char 58:iget-short 59:輸入 5a:輸入範圍 5b:輸入對象 5c:輸入布爾值 5d:輸入字節 5e: 輸入字符 5f:輸入短路 | A: 值寄存器或對;可以是源或目標(4 位)B: 對象寄存器(4位)C: 實例字段引用索引(16位) | 對標識的字段執行標識的對象實例字段操作,加載或存儲到值寄存器中。 注意:這些操作碼是靜態鏈接的合理候選者,將字段參數更改為更直接的偏移量。 |
60..6d 21c | s staticop vAA,字段@BBBB 60:算了 61:全段 62: 目標對象 63:sget-布爾值 64:sget字節 65:sget-char 66:sget-short 67:吐痰 68:全口 69:sput-object 6a:sput-布爾值 6b: 輸出字節 6c:噴炭 6d:sput-short | A: 值寄存器或對;可以是源或目標(8 位)B: 靜態字段引用索引(16位) | 對已識別的靜態字段執行已識別的對象靜態字段操作,加載或存儲到值寄存器中。 注意:這些操作碼是靜態鏈接的合理候選者,將字段參數更改為更直接的偏移量。 |
6e..72 35c | 調用類型{vC, vD, vE, vF, vG}, meth@BBBB 6e:調用虛擬 6f:調用超級 70:直接調用 71:調用靜態 72:調用接口 | A: 參數字數(4位)B: 方法參考索引(16位)C..G: 參數寄存器(每個 4 位) | 調用指定的方法。結果(如果有的話)可以與適當的move-result* 變體一起存儲為緊隨其後的指令。 當 在 Dex 文件版本 注意:這些操作碼是靜態鏈接的合理候選者,將方法參數更改為更直接的偏移量(或其對)。 |
73 10 倍 | (沒用過) | (沒用過) | |
74..78 3rc | 調用種類/範圍 {vCCCC .. vNNNN},meth@BBBB 74:調用-虛擬/範圍 75:調用超級/範圍 76:直接調用/範圍 77:調用靜態/範圍 78:調用接口/範圍 | A: 參數字數(8位)B: 方法參考索引(16位)C: 第一個參數寄存器(16 位)N = A + C - 1 | 調用指定的方法。有關詳細信息、注意事項和建議,請參見上面的第一個invoke- kind 描述。 |
79..7a 10 倍 | (沒用過) | (沒用過) | |
7b..8f 12x | unop vA, vB 7b: 負整數 7c:非整數 7d:負長 7e:不長 7f: 負浮動 80:負加倍 81:整數到長 82:整數到浮點數 83:整數到雙倍 84:長整型 85:長期浮動 86:長到雙倍 87:浮點到整數 88:浮動到長 89:浮動到雙倍 8a:雙整數 8b:雙倍長 8c:雙浮動 8d:整數到字節 8e:整數到字符 8f: int-to-short | A: 目標寄存器或對(4 位)B: 源寄存器或對(4位) | 對源寄存器執行識別的一元運算,將結果存儲在目標寄存器中。 |
90..af 23x | binop vAA、vBB、vCC 90:加法 91:子整數 92:多整數 93:div-int 94:rem-int 95:和整數 96:或整數 97:異或整數 98:shl-int 99:shr-int 9a:ushr-int 9b:加長 9c:亞長 9d:多長 9e:div-long 9f:rem-long a0: and-long a1: or-long a2:異或長 a3: shl-long a4: shr-long a5: ushr-long a6: 加浮點數 a7:子浮動 a8: 多浮點數 a9: div-浮點數 aa: rem-浮點數 ab:加倍 ac:亞雙 廣告:多倍雙倍 ae:div-double af: rem-雙倍 | A: 目標寄存器或對(8 位)B: 第一個源寄存器或對(8 位)C: 第二個源寄存器或對(8 位) | 對兩個源寄存器執行識別的二進制操作,將結果存儲在目標寄存器中。 注意:與其他 |
b0..cf 12x | binop /2addr vA, vB b0: 添加整數/2addr b1: 子整數/2addr b2: 多整數/2地址 b3: div-int/2addr b4: rem-int/2addr b5: 和-int/2addr b6: 或-int/2addr b7: xor-int/2addr b8: shl-int/2addr b9: shr-int/2addr 巴: ushr-int/2addr bb: 加長/2addr bc: sub-long/2addr bd: 多長/2addr 是:div-long/2addr bf: rem-long/2addr c0: 和-long/2addr c1: or-long/2addr c2: xor-long/2addr c3: shl-long/2addr c4: shr-long/2addr c5: usr-long/2addr c6: 添加浮點數/2addr c7: 子浮點數/2addr c8: 多浮點數/2addr c9: div-float/2addr ca: rem-float/2addr cb: 加雙/2addr cc: sub-double/2addr cd: 多雙/2addr ce: div-double/2addr cf: rem-double/2addr | A: 目標和第一個源寄存器或對(4 位)B: 第二個源寄存器或對(4 位) | 對兩個源寄存器執行識別的二進制運算,將結果存儲在第一個源寄存器中。 注意:與其他 |
d0..d7 22s | binop /lit16 vA, vB, #+CCCC d0: 添加-int/lit16 d1:rsub-int(反向減法) d2: 多整數/lit16 d3:div-int/lit16 d4: rem-int/lit16 d5: 和-int/lit16 d6: 或-int/lit16 d7: xor-int/lit16 | A: 目的寄存器(4位)B: 源寄存器(4位)C: 有符號整數常量(16 位) | 對指定的寄存器(第一個參數)和文字值(第二個參數)執行指定的二進制操作,將結果存儲在目標寄存器中。 注意: |
d8..e2 22b | binop /lit8 vAA, vBB, #+CC d8: 添加整數/lit8 d9: rsub-int/lit8 da: 多整數/lit8 分貝:div-int/lit8 直流:rem-int/lit8 dd:和-int/lit8 de: or-int/lit8 df: xor-int/lit8 e0: shl-int/lit8 e1: shr-int/lit8 e2: usr-int/lit8 | A: 目的寄存器(8位)B: 源寄存器(8位)C: 有符號整數常量(8 位) | 對指定的寄存器(第一個參數)和文字值(第二個參數)執行指定的二進制操作,將結果存儲在目標寄存器中。 注意:有關 |
e3..f9 10x | (沒用過) | (沒用過) | |
發 45cc | 調用多態 {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 | 調用多態/範圍 {vCCCC .. vNNNN},meth@BBBB,proto@HHHH | A: 參數字數(8位)B: 方法參考索引(16位)C: 接收器(16 位)H: 原型參考索引(16位)N = A + C - 1 | 調用指示的方法句柄。有關詳細信息,請參閱上面的invoke-polymorphic 描述。從 038 版開始出現在 Dex 文件中。 |
fc 35c | 調用自定義 {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 | 調用自定義/範圍 {vCCCC .. vNNNN},call_site@BBBB | A: 參數字數(8位)B: 調用站點參考索引(16位)C: 第一個參數寄存器(16 位)N = A + C - 1 | 解決並調用呼叫站點。有關詳細信息,請參閱上面的invoke-custom 描述。從 038 版開始出現在 Dex 文件中。 |
鐵 21c | const-method-handle vAA, method_handle@BBBB | A: 目的寄存器(8位)B: 方法句柄索引(16位) | 將對給定索引指定的方法句柄的引用移動到指定的寄存器中。 從 039 版開始出現在 Dex 文件中。 |
ff 21c | const 方法類型 vAA,proto@BBBB | A: 目的寄存器(8位)B: 方法原型參考(16位) | 將給定索引指定的方法原型的引用移動到指定的寄存器中。 從 039 版開始出現在 Dex 文件中。 |
打包開關有效載荷格式
姓名 | 格式 | 描述 |
---|---|---|
識別 | ushort = 0x0100 | 識別偽操作碼 |
尺寸 | 超短 | 表中的條目數 |
first_key | 整數 | 第一個(也是最低的)switch case 值 |
目標 | 整數[] | size 相對分支目標列表。目標是相對於開關操作碼的地址,而不是這個表。 |
注意:此表實例的代碼單元總數為(size * 2) + 4
。
稀疏開關有效載荷格式
姓名 | 格式 | 描述 |
---|---|---|
識別 | ushort = 0x0200 | 識別偽操作碼 |
尺寸 | 超短 | 表中的條目數 |
鑰匙 | 整數[] | size 鍵值列表,從低到高排序 |
目標 | 整數[] | size 相對分支目標列表,每個目標對應於同一索引處的鍵值。目標是相對於開關操作碼的地址,而不是這個表。 |
注意:此表實例的代碼單元總數為(size * 4) + 2
。
填充數組數據有效載荷格式
姓名 | 格式 | 描述 |
---|---|---|
識別 | ushort = 0x0300 | 識別偽操作碼 |
元素寬度 | 超短 | 每個元素中的字節數 |
尺寸 | 單位 | 表格中的元素數量 |
數據 | 優字節[] | 數據值 |
注意:此表實例的代碼單元總數為(size * element_width + 1) / 2 + 4
。
數學運算細節
注意:除非另有說明,否則浮點運算必須遵循 IEEE 754 規則,使用四捨五入和逐漸下溢。
操作碼 | C語義 | 筆記 |
---|---|---|
負整數 | int32 一個; int32 結果 = -a; | 一元補碼。 |
非整數 | int32 一個; int32 結果 = ~a; | 一元補碼。 |
內長 | int64 一個; int64 結果 = -a; | 一元補碼。 |
不久 | int64 一個; int64 結果 = ~a; | 一元補碼。 |
負浮動 | 浮動一個; float result = -a; | Floating point negation. |
neg-double | double a; double result = -a; | Floating point negation. |
int-to-long | int32 a; int64 result = (int64) a; | Sign extension of int32 into int64 . |
int-to-float | int32 a; float result = (float) a; | Conversion of int32 to float , using round-to-nearest. This loses precision for some values. |
int-to-double | int32 a; double result = (double) a; | Conversion of int32 to double . |
long-to-int | int64 a; int32 result = (int32) a; | Truncation of int64 into int32 . |
long-to-float | int64 a; float result = (float) a; | Conversion of int64 to float , using round-to-nearest. This loses precision for some values. |
long-to-double | int64 a; double result = (double) a; | Conversion of int64 to double , using round-to-nearest. This loses precision for some values. |
float-to-int | float a; int32 result = (int32) a; | Conversion of float to int32 , using round-toward-zero. NaN and -0.0 (negative zero) convert to the integer 0 . Infinities and values with too large a magnitude to be represented get converted to either 0x7fffffff or -0x80000000 depending on sign. |
float-to-long | float a; int64 result = (int64) a; | Conversion of float to int64 , using round-toward-zero. The same special case rules as for float-to-int apply here, except that out-of-range values get converted to either 0x7fffffffffffffff or -0x8000000000000000 depending on sign. |
float-to-double | float a; double result = (double) a; | Conversion of float to double , preserving the value exactly. |
double-to-int | double a; int32 result = (int32) a; | Conversion of double to int32 , using round-toward-zero. The same special case rules as for float-to-int apply here. |
double-to-long | double a; int64 result = (int64) a; | Conversion of double to int64 , using round-toward-zero. The same special case rules as for float-to-long apply here. |
double-to-float | double a; float result = (float) a; | Conversion of double to float , using round-to-nearest. This loses precision for some values. |
int-to-byte | int32 a; int32 result = (a << 24) >> 24; | Truncation of int32 to int8 , sign extending the result. |
int-to-char | int32 a; int32 result = a & 0xffff; | Truncation of int32 to uint16 , without sign extension. |
int-to-short | int32 a; int32 result = (a << 16) >> 16; | Truncation of int32 to int16 , sign extending the result. |
add-int | int32 a, b; int32 result = a + b; | Twos-complement addition. |
sub-int | int32 a, b; int32 result = a - b; | Twos-complement subtraction. |
rsub-int | int32 a, b; int32 result = b - a; | Twos-complement reverse subtraction. |
mul-int | int32 a, b; int32 result = a * b; | Twos-complement multiplication. |
div-int | int32 a, b; int32 result = a / b; | Twos-complement division, rounded towards zero (that is, truncated to integer). This throws ArithmeticException if b == 0 . |
rem-int | int32 a, b; int32 result = a % b; | Twos-complement remainder after division. The sign of the result is the same as that of a , and it is more precisely defined as result == a - (a / b) * b . This throws ArithmeticException if b == 0 . |
and-int | int32 a, b; int32 result = a & b; | Bitwise AND. |
or-int | int32 a, b; int32 result = a | b; | Bitwise OR. |
xor-int | int32 a, b; int32 result = a ^ b; | Bitwise XOR. |
shl-int | int32 a, b; int32 result = a << (b & 0x1f); | Bitwise shift left (with masked argument). |
shr-int | int32 a, b; int32 result = a >> (b & 0x1f); | Bitwise signed shift right (with masked argument). |
ushr-int | uint32 a, b; int32 result = a >> (b & 0x1f); | Bitwise unsigned shift right (with masked argument). |
add-long | int64 a, b; int64 result = a + b; | Twos-complement addition. |
sub-long | int64 a, b; int64 result = a - b; | Twos-complement subtraction. |
mul-long | int64 a, b; int64 result = a * b; | Twos-complement multiplication. |
div-long | int64 a, b; int64 result = a / b; | Twos-complement division, rounded towards zero (that is, truncated to integer). This throws ArithmeticException if b == 0 . |
rem-long | int64 a, b; int64 result = a % b; | Twos-complement remainder after division. The sign of the result is the same as that of a , and it is more precisely defined as result == a - (a / b) * b . This throws ArithmeticException if b == 0 . |
and-long | int64 a, b; int64 result = a & b; | Bitwise AND. |
or-long | int64 a, b; int64 result = a | b; | Bitwise OR. |
xor-long | int64 a, b; int64 result = a ^ b; | Bitwise XOR. |
shl-long | int64 a; int32 b; int64 result = a << (b & 0x3f); | Bitwise shift left (with masked argument). |
shr-long | int64 a; int32 b; int64 result = a >> (b & 0x3f); | Bitwise signed shift right (with masked argument). |
ushr-long | uint64 a; int32 b; int64 result = a >> (b & 0x3f); | Bitwise unsigned shift right (with masked argument). |
add-float | float a, b; float result = a + b; | Floating point addition. |
sub-float | float a, b; float result = a - b; | Floating point subtraction. |
mul-float | float a, b; float result = a * b; | Floating point multiplication. |
div-float | float a, b; float result = a / b; | Floating point division. |
rem-float | float a, b; float result = a % b; | Floating point remainder after division. This function is different than IEEE 754 remainder and is defined as result == a - roundTowardZero(a / b) * b . |
add-double | double a, b; double result = a + b; | Floating point addition. |
sub-double | double a, b; double result = a - b; | Floating point subtraction. |
mul-double | double a, b; double result = a * b; | Floating point multiplication. |
div-double | double a, b; double result = a / b; | Floating point division. |
rem-double | double a, b; double result = a % b; | Floating point remainder after division. This function is different than IEEE 754 remainder and is defined as result == a - roundTowardZero(a / b) * b . |