達爾維克字節碼

一般設計

  • 機器模型和調用約定旨在近似模仿常見的真實架構和 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 ”是目標寄存器(由操作暗示;同樣,規則是目標參數總是在前),它必須在v0v255範圍內。
      • vBBBB ”是源寄存器,必須在v0v65535範圍內。
  • 有關各種指令格式(在“操作和格式”下列出)以及操作碼語法的詳細信息,請參閱指令格式文檔
  • 有關字節碼適合大局的更多詳細信息,請參閱.dex文件格式文檔

字節碼集總結

操作和格式助記符/語法論據描述
00 10x廢物循環。

注意:承載數據的偽指令用此操作碼標記,在這種情況下,操作碼單元的高位字節指示數據的性質。請參閱下面的“ packed-switch-payload格式”、“ sparse-switch-payload格式”和“ fill-array-data-payload格式”。

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位)
將一個寄存器對的內容移動到另一個。

注意:v N移動到v N-1v N+1是合法的,因此實現必須安排在寫入任何內容之前讀取寄存器對的兩半。

05 22x move-wide/from16 vAA, vBBBB A:目標寄存器對(8 位)
B:源寄存器對(16 位)
將一個寄存器對的內容移動到另一個。

注意:實現注意事項與上面的move-wide相同。

06 32x移動範圍/16 vAAAA, vBBBB A:目標寄存器對(16 位)
B:源寄存器對(16 位)
將一個寄存器對的內容移動到另一個。

注意:實現注意事項與上面的move-wide相同。

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- kindfilled-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(例如finally )塊作為該塊本身的監視器清理,作為一種處理可能由於Thread.stop()的歷史實現而引發的任意異常的方法Thread.stop() ,同時仍然設法保持適當的監視器衛生。

1f 21c檢查鑄造 vAA,類型@BBBB A:參考軸承寄存器(8位)
B:類型索引(16位)
如果給定寄存器中的引用不能轉換為指定的類型,則拋出ClassCastException

注意:由於A必須始終是引用(而不是原始值),因此如果B引用原始類型,這必然會在運行時失敗(即,它將引發異常)。

20 22c vA、vB、類型@CCCC 的實例A:目的寄存器(4位)
B:參考軸承寄存器(4位)
C:類型索引(16位)
如果指示的引用是給定類型的實例,則存儲在給定的目標寄存器1 ,否則存儲0

注意:由於B必須始終是引用(而不是原始值),因此如果C引用原始類型,這將始終導致存儲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 位)
構造一個給定類型和大小的數組,用提供的內容填充它。類型必須是數組類型。數組的內容必須是單字的(也就是說,沒有longdouble的數組,但引用類型是可以接受的)。構造的實例以與方法調用指令存儲其結果的方式相同的方式存儲為“結果”,因此必須將構造的實例移動到帶有緊隨其後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 位)無條件跳轉到指定指令。

注意:分支偏移量不得為0 。 (可以使用goto/32或通過在分支之前包含一個nop作為目標來合法地構建自旋循環。)

29 20噸轉到/16 +AAAA A:符號分支偏移量(16 位)
無條件跳轉到指定指令。

注意:分支偏移量不得為0 。 (可以使用goto/32或通過在分支之前包含一個nop作為目標來合法地構建自旋循環。)

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 == ca設置為0 ,如果b > c設置為1 ,如果b < c設置-1 。為浮點運算列出的“偏差”指示如何處理NaN比較:“gt bias”指令返回1用於NaN比較,“lt bias”指令返回-1

例如,要檢查浮點x < y是否建議使用cmpg-float ;結果-1表示測試為真,其他值表示由於有效比較或其中一個值為NaN而為假。

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 位)
如果給定的兩個寄存器的值按指定進行比較,則跳轉到給定的目標。

注意:分支偏移量不得為0 。 (可以通過圍繞向後goto分支或在分支之前包含一個nop作為目標來合法地構建自旋循環。)

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 比較,則跳轉到給定目標。

注意:分支偏移量不得為0 。 (可以通過圍繞向後goto分支或在分支之前包含一個nop作為目標來合法地構建自旋循環。)

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*變體一起存儲為緊隨其後的指令。

invoke-virtual用於調用普通的虛擬方法(不是privatestaticfinal的方法,也不是構造函數)。

method_id引用非接口類的方法時, invoke-super用於調用最近的超類的虛方法(與調用類中具有相同method_id的方法相反)。與invoke-virtual相同的方法限制。

在 Dex 文件版本037或更高版本中,如果method_id引用接口方法, invoke-super用於調用在該接口上定義的該方法的最具體、非覆蓋版本。與invoke-virtual相同的方法限制。在版本037之前的 Dex 文件中,具有接口method_id是非法且未定義的。

invoke-direct用於調用非static直接方法(即本質上不可覆蓋的實例方法,即private實例方法或構造函數)。

invoke-static用於調用static方法(始終被認為是直接方法)。

invoke-interface用於調用interface方法,即在具體類未知的對像上,使用引用interfacemethod_id

注意:這些操作碼是靜態鏈接的合理候選者,將方法參數更改為更直接的偏移量(或其對)。

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 位)
對兩個源寄存器執行識別的二進制操作,將結果存儲在目標寄存器中。

注意:與其他-long數學運算(它們的第一個和第二個源都採用寄存器對)相反, shl-longshr-longushr-long採用一個寄存器對作為它們的第一個源(要移位的值),但它們的第二個來源(移動距離)只有一個寄存器。

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 位)
對兩個源寄存器執行識別的二進制運算,將結果存儲在第一個源寄存器中。

注意:與其他-long/2addr數學運算(其目標/第一個源和第二個源都採用寄存器對)相反, shl-long/2addrshr-long/2addrushr-long/2addr採用寄存器對它們的目標/第一個源(要移動的值),但對它們的第二個源(移動距離)有一個寄存器。

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 位)
對指定的寄存器(第一個參數)和文字值(第二個參數)執行指定的二進制操作,將結果存儲在目標寄存器中。

注意: rsub-int沒有後綴,因為此版本是其係列的主要操作碼。此外,有關其語義的詳細信息,請參見下文。

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 位)
對指定的寄存器(第一個參數)和文字值(第二個參數)執行指定的二進制操作,將結果存儲在目標寄存器中。

注意:有關rsub-int語義的詳細信息,請參見下文。

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.invokejava.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
  • 引導鏈接器方法無法返回java.lang.invoke.CallSite實例。
  • 返回的java.lang.invoke.CallSite有一個null方法句柄目標。
  • 方法句柄目標不是請求的類型。
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 .