一般的な設計
- マシンモデルと呼び出しに関する以下の規則は、一般的な実際のアーキテクチャと C スタイルの呼び出しの規則をほぼそのままなぞることを意図して設計されています。
- マシンはレジスタベースで、フレームは作成時にサイズが固定されます。各フレームは、(メソッドによって指定される)特定の数のレジスタと、メソッドの実行に必要な補助データ(プログラム カウンタや、メソッドを格納する
.dex
ファイルへの参照など)で構成されます。 - ビット値(整数や浮動小数点数など)に使用する場合、レジスタは 32 ビット幅を持つと見なされます。64 ビット値には、隣接するレジスタのペアが使用されます。レジスタペアに対する整列要件はありません。
- オブジェクト参照に使用する場合、レジスタはそのような参照を 1 つだけ保持するのに十分な幅を持つと見なされます。
- ビット単位の表現では、
(Object) null == (int) 0
となります。 - メソッドの N 個の引数は、メソッドの呼び出しフレームの最後の N 個のレジスタに、順番に配置されます。ワイドな引数は 2 つのレジスタを消費します。インスタンス メソッドは最初の引数として
this
参照を渡されます。
- マシンはレジスタベースで、フレームは作成時にサイズが固定されます。各フレームは、(メソッドによって指定される)特定の数のレジスタと、メソッドの実行に必要な補助データ(プログラム カウンタや、メソッドを格納する
- 命令ストリーム内のストレージ ユニットは 16 ビットの符号なしの量です。一部の命令に含まれる一部のビットは無視されるか、ゼロであることを求められます。
- 命令は、不必要に特定の型に限定されることはありません。たとえば、32 ビットのレジスタ値を解釈なしで移動する命令では、int 型で移動するか float 型で移動するかの指定は不要です。
- 文字列、型、フィールド、メソッドへの参照には、列挙型とインデックス付きの定数プールがそれぞれあります。
- ビット単位のリテラルデータは、命令ストリームではインラインで表現されます。
- 実際には、メソッドが 16 個を超えるレジスタを必要とする場合はまれであり、8 個を超えるレジスタを必要とする場合が一般的であるため、多くの命令は最初の 16 個のレジスタのみをアドレス指定するように制限されています。合理的に可能であれば、命令は最大で最初の 256 個のレジスタを参照できます。さらに、一部の命令には、レジスタの数を大幅に増やすことができるバリアントがあります。たとえば、キャッチオール式の
move
命令のペアは、v0
からv65535
の範囲のレジスタをアドレス指定できます。命令のバリアントで目的のレジスタをアドレス指定できない場合、レジスタの内容が(演算の前に)元のレジスタから下位のレジスタに移動されるか、(演算の後に)下位の結果レジスタから上位のレジスタに移動される(または、演算の前後にその両方が行われる)ことが期待されます。 - 標準的な命令で参照される、可変長データ ペイロードを保持するために使用される「擬似命令」がいくつかあります(
fill-array-data
など)。このような命令は、通常の実行フロー内で使用するべきではありません。また、命令は偶数番号のバイトコード オフセット(つまり、4 バイトに揃えたオフセット)に配置する必要があります。この要件を満たすには、命令がそのように配置されない場合に、dex 生成ツールで追加のnop
命令をスペーサーとして発行する必要があります。最後に、必須ではありませんが、ほとんどのツールは、メソッドの最後にそれらの命令の発行を選択することを期待されます。そうしないと、メソッドの最後で分岐するための追加の命令が必要になる可能性が高いからです。 - 一部の命令は、実行中のシステムにインストールすると、インストール時の静的リンクを最適化するために、修正されて形式が変更される場合があります。これは、リンク関係が判明したら高速で実行できるようにするためです。おすすめのバリアントについては、関連する命令形式のドキュメントをご覧ください。「おすすめ」という表現にご注意ください。それらを実装することは必須ではありません。
- 人間にわかりやすい構文とニーモニック:
- 引数の順序は Dest-then-source(宛先に次いでソース)です。
- 一部のオペコードには、演算の種類を明確に示す名前サフィックスが付いています:
- 汎用的な型に対応する 32 ビットのオペコードにはサフィックスが付きません。
- 汎用的な型に対応する 64 ビットのオペコードには
-wide
サフィックスが付きます。 - 特定の型に対応するオペコードには、次のいずれかの型(または単純な略語)がサフィックスとして付きます:
-boolean
-byte
-char
-short
-int
-long
-float
-double
-object
-string
-class
-void
。
- 一部のオペコードには、命令のレイアウトまたはオプションが異なる類似した演算を明確に区別するためのサフィックスが付きます。この種のサフィックスはスラッシュ(
/
)で語幹と区切られます。その主な目的は、実行可能ファイルを生成して解釈するコード内で静的定数と 1 対 1 でマッピングできるようにすることです(言い換えれば、人間にとっての曖昧さを減らすことです)。 - ここでの説明では、値(たとえば、定数の範囲やアドレス指定される可能性があるレジスタの数を示す値)の幅は、4 ビットの幅ごとに特定の文字を 1 つ使用することで強調しています。
- 例: 命令 "
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 ビット) |
1 つの非オブジェクト レジスタの内容を別のレジスタに移動します。 |
02 22x | move/from16 vAA, vBBBB | A: 宛先レジスタ(8 ビット)B: ソースレジスタ(16 ビット) |
1 つの非オブジェクト レジスタの内容を別のレジスタに移動します。 |
03 32x | move/16 vAAAA, vBBBB | A: 宛先レジスタ(16 ビット)B: ソースレジスタ(16 ビット) |
1 つの非オブジェクト レジスタの内容を別のレジスタに移動します。 |
04 12x | move-wide vA, vB | A: 宛先レジスタペア(4 ビット)B: ソース レジスタペア(4 ビット) |
1 つのレジスタペアの内容を別のレジスタペアに移動します。
注: |
05 22x | move-wide/from16 vAA, vBBBB | A: 宛先レジスタペア(8 ビット)B: ソース レジスタペア(16 ビット) |
1 つのレジスタペアの内容を別のレジスタペアに移動します。
注: 実装に関する考慮事項は、上記の |
06 32x | move-wide/16 vAAAA, vBBBB | A: 宛先レジスタペア(16 ビット)B: ソース レジスタペア(16 ビット) |
1 つのレジスタペアの内容を別のレジスタペアに移動します。
注: 実装に関する考慮事項は、上記の |
07 12x | move-object vA, vB | A: 宛先レジスタ(4 ビット)B: ソースレジスタ(4 ビット) |
1 つのオブジェクト保持レジスタの内容を別のレジスタに移動します。 |
08 22x | move-object/from16 vAA, vBBBB | A: 宛先レジスタ(8 ビット)B: ソースレジスタ(16 ビット) |
1 つのオブジェクト保持レジスタの内容を別のレジスタに移動します。 |
09 32x | move-object/16 vAAAA, vBBBB | A: 宛先レジスタ(16 ビット)B: ソースレジスタ(16 ビット) |
1 つのオブジェクト保持レジスタの内容を別のレジスタに移動します。 |
0a 11x | move-result vAA | A: 宛先レジスタ(8 ビット) |
最新の 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: 符号付き整数(4 ビット) |
与えられたリテラル値(32 ビットに符号付き拡張される)を指定されたレジスタに移動します。 |
13 21s | const/16 vAA, #+BBBB | A: 宛先レジスタ(8 ビット)B: 符号付き整数(16 ビット) |
与えられたリテラル値(32 ビットに符号付き拡張される)を指定されたレジスタに移動します。 |
14 31i | const vAA, #+BBBBBBBB | A: 宛先レジスタ(8 ビット)B: 任意の 32 ビット定数 |
与えられたリテラル値を指定されたレジスタに移動します。 |
15 21h | 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 51l | const-wide vAA, #+BBBBBBBBBBBBBBBB | A: 宛先レジスタ(8 ビット)B: 任意のダブル幅(64 ビット)定数 |
与えられたリテラル値を指定されたレジスタペアに移動します。 |
19 21h | const-wide/high16 vAA, #+BBBB000000000000 | A: 宛先レジスタ(8 ビット)B: 符号付き整数(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 | array-length 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 | filled-new-array {vC, vD, vE, vF, vG}, type@BBBB |
A: 配列サイズと引数ワード数(4 ビット)B: 型インデックス(16 ビット)C..G: 引数レジスタ(各 4 ビット)
|
与えられた型とサイズの配列を作成し、渡されたコンテンツで埋めます。型は配列型でなければなりません。配列のコンテンツはシングルワードでなければなりません(つまり、long または double の配列は使用できませんが、参照型は使用できます)。作成されたインスタンスは、メソッド呼び出し命令が結果を格納するのと同様に「結果」として格納されます。したがって、作成されたインスタンスは、直後に実行される move-result-object 命令を(使用可能であれば)使用してレジスタに移動する必要があります。 |
25 3rc | filled-new-array/range {vCCCC .. vNNNN}, type@BBBB | A: 配列サイズと引数ワード数(8 ビット)B: 型インデックス(16 ビット)C: 第 1 引数レジスタ(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 | throw 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: 第 1 ソースレジスタまたはペアC: 第 2 ソースレジスタまたはペア |
指示された浮動小数点数または long の比較を実行し、a を、b == c の場合は 0 、b > c の場合は 1 、b < c の場合は -1 に設定します。浮動小数点演算に記載された「bias」は NaN 比較の処理方法を示します。NaN 比較に対して、「gt bias」命令は 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: 第 1 のテスト対象レジスタ(4 ビット)B: 第 2 のテスト対象レジスタ(4 ビット)C: 符号付き分岐オフセット(16 ビット) |
与えられた 2 つのレジスタの値が指定された値と等しい場合、与えられた宛先に分岐します。
注: 分岐オフセットを |
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 ビット) |
指定されたフィールドを使用して、指定されたオブジェクト インスタンス フィールド演算を実行し、結果を値レジスタに読み込むか、格納します。
注: これらのオペコードは静的リンクの妥当な候補であり、フィールド引数をより直接的なオフセットに変更します。 |
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 ビット) |
指定された静的フィールドを使用して、指定されたオブジェクト静的フィールド演算を実行し、結果を値レジスタに読み込むか、格納します。
注: これらのオペコードは静的リンクの妥当な候補であり、フィールド引数をより直接的なオフセットに変更します。 |
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* バリアントとともに格納されます。
バージョン
注: これらのオペコードは静的リンクの妥当な候補であり、メソッドの引数をより直接的なオフセット(またはそのペア)に変更します。 |
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: 第 1 引数レジスタ(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: 第 1 ソースレジスタまたはペア(8 ビット)C: 第 2 ソースレジスタまたはペア(8 ビット) |
指定された 2 項演算を 2 つのソースレジスタで実行し、結果を宛先レジスタに格納します。
注: 他の |
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: 宛先レジスタおよび第 1 ソースレジスタまたはペア(4 ビット)B: 第 2 ソースレジスタまたはペア(4 ビット) |
指定された 2 項演算を 2 つのソースレジスタで実行し、結果を第 1 ソースレジスタに格納します。
注: 他の |
d0..d7 22s | 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 ビット) |
指示されたレジスタ(第 1 引数)とリテラル値(第 2 引数)で、指示された 2 項演算を実行し、結果を宛先レジスタに格納します。
注: このバージョンは同種のオペコードの中核であるため、 |
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 ビット) |
指示されたレジスタ(第 1 引数)とリテラル値(第 2 引数)で、指示された 2 項演算を実行し、結果を宛先レジスタに格納します。
注: |
e3..f9 10x | (未使用) | (未使用) | |
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* バリアントとともに格納されます。この命令は、2 つのフェーズ(コールサイトの解決とコールサイトの呼び出し)で実行されます。 コールサイトの解決では、指示されたコールサイトに、関連する 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: 第 1 引数レジスタ(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 | 最初の(最小の)switch case 値。 |
targets | int[] | size 相対分岐ターゲットのリスト。targets は、このテーブルのアドレスではなく switch オペコードのアドレスに対する相対値です。
|
注: このテーブルのインスタンスに対するコードユニットの合計数は、(size * 2) + 4
です。
sparse-switch-payload 形式
名前 | 形式 | 説明 |
---|---|---|
ident | ushort = 0x0200 | 擬似オペコードの識別情報 |
size | ushort | テーブル内のエントリ数 |
keys | int[] | size キー値のリスト(低い順)。 |
targets | int[] | size 相対分岐ターゲットのリスト。各ターゲットは同じインデックスのキー値に対応します。targets は、このテーブルのアドレスではなく switch オペコードのアドレスに対する相対値です。
|
注: このテーブルのインスタンスに対するコードユニットの合計数は、(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 規則に従って、最近接丸めと段階的アンダーフローを使用します。
オペコード | C セマンティクス | メモ |
---|---|---|
neg-int | int32 a; int32 result = -a; |
単項の 2 の補数。 |
not-int | int32 a; int32 result = ~a; |
単項の 1 の補数。 |
neg-long | int64 a; int64 result = -a; |
単項の 2 の補数。 |
not-long | int64 a; int64 result = ~a; |
単項の 1 の補数。 |
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-to-float | int32 a; float result = (float) a; |
最近接丸めを使用して int32 を float に変換します。一部の値では精度が失われます。
|
int-to-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-to-int | 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-to-double | 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-to-byte | int32 a; int32 result = (a << 24) >> 24; |
int32 を切り捨てて int8 に変換し、結果を符号付き拡張します。
|
int-to-char | int32 a; int32 result = a & 0xffff; |
int32 を切り捨てて uint16 に変換し、符号付き拡張は行いません。
|
int-to-short | int32 a; int32 result = (a << 16) >> 16; |
int32 を切り捨てて int16 に変換し、結果を符号付き拡張します。
|
add-int | int32 a, b; int32 result = a + b; |
2 の補数の加算。 |
sub-int | int32 a, b; int32 result = a - b; |
2 の補数の減算。 |
rsub-int | int32 a, b; int32 result = b - a; |
2 の補数の逆減算。 |
mul-int | int32 a, b; int32 result = a * b; |
2 の補数の乗算。 |
div-int | int32 a, b; int32 result = a / b; |
2 の補数の除算の後、ゼロへの丸め(つまり、整数への切り捨て)を行います。b == 0 の場合、ArithmeticException をスローします。
|
rem-int | int32 a, b; int32 result = a % b; |
2 の補数の除算後の余り。結果の符号は 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; |
2 の補数の加算。 |
sub-long | int64 a, b; int64 result = a - b; |
2 の補数の減算。 |
mul-long | int64 a, b; int64 result = a * b; |
2 の補数の乗算。 |
div-long | int64 a, b; int64 result = a / b; |
2 の補数の除算の後、ゼロへの丸め(つまり、整数への切り捨て)を行います。b == 0 の場合、ArithmeticException をスローします。
|
rem-long | int64 a, b; int64 result = a % b; |
2 の補数の除算後の余り。結果の符号は 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; |
浮動小数点数の加算。 |
sub-float | 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; |
浮動小数点数の加算。 |
sub-double | 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 として定義されています。
|