Dalvik バイトコード

一般的な設計

  • マシンモデルと呼び出しに関する以下の規則は、一般的な実際のアーキテクチャと 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   浪費サイクル。

注: データを保持する擬似命令には、このオペコードがタグ付けされます。この場合、オペコード ユニットの上位バイトはデータの性質を示します。後述の「packed-switch-payload 形式」、「sparse-switch-payload 形式」、「fill-array-data-payload 形式」をご覧ください。

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 つのレジスタペアの内容を別のレジスタペアに移動します。

注: vN から vN-1 または vN+1 のいずれかに移動することは規則に抵触しないので、実装は、書き込みが行われる前に、レジスタペアを構成するレジスタが両方とも読み込まれるようにする必要があります。

05 22x move-wide/from16 vAA, vBBBB A: 宛先レジスタペア(8 ビット)
B: ソース レジスタペア(16 ビット)
1 つのレジスタペアの内容を別のレジスタペアに移動します。

注: 実装に関する考慮事項は、上記の move-wide と同様です。

06 32x move-wide/16 vAAAA, vBBBB A: 宛先レジスタペア(16 ビット)
B: ソース レジスタペア(16 ビット)
1 つのレジスタペアの内容を別のレジスタペアに移動します。

注: 実装に関する考慮事項は、上記の move-wide と同様です。

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 がすでにこの命令の次に進んだものとしてスローしてください。この命令が(ある意味で)正常に実行され、この命令の後、次の命令が実行される機会を得る前に例外がスローされたと見なすことが有用な場合があります。この定義により、メソッドがモニタ クリーンアップのキャッチオール式(たとえば、finally)ブロックを、そのブロック自体のモニタ クリーンアップとして使用することが可能になります。これは、Thread.stop() の過去の実装が原因でスローされる可能性がある任意の例外を処理しつつ、モニタの健全性も維持する手段です。

1f 21c check-cast vAA, type@BBBB A: 参照保持レジスタ(8 ビット)
B: 型インデックス(16 ビット)
与えられたレジスタ内の参照を指示された型にキャストできない場合、ClassCastException をスローします。

注: A は常に(プリミティブ値ではなく)参照でなければならないので、B がプリミティブ型を参照している場合は、実行時に必ず失敗します(つまり、例外がスローされます)。

20 22c instance-of vA, vB, type@CCCC A: 宛先レジスタ(4 ビット)
B: 参照保持レジスタ(4 ビット)
C: 型インデックス(16 ビット)
指示された参照が与えられた型のインスタンスである場合は、与えられた宛先レジスタに 1 を格納します。それ以外の場合は、0 を格納します。

注: B は常に(プリミティブ値ではなく)参照でなければならないので、C がプリミティブ型を参照している場合は、必ず 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 ビット) 指示された命令に無条件でジャンプします。

注: 分岐オフセットを 0 にすることはできません(スピンループは、goto/32 を使用するか、nop を分岐前のターゲットとして指定することにより、規則に抵触せずに作成できます)。

29 20t goto/16 +AAAA A: 符号付き分岐オフセット(16 ビット)
指示された命令に無条件でジャンプします。

注: 分岐オフセットを 0 にすることはできません(スピンループは、goto/32 を使用するか、nop を分岐前のターゲットとして指定することにより、規則に抵触せずに作成できます)。

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 の場合は 0b > c の場合は 1b < c の場合は -1 に設定します。浮動小数点演算に記載された「bias」は NaN 比較の処理方法を示します。NaN 比較に対して、「gt bias」命令は 1 を返し、「lt bias」命令は -1 を返します。

たとえば、浮動小数点数の x < y を確認するには、cmpg-float を使用することをおすすめします。その場合、結果が -1 であればテストが true であったことを示し、他の値であれば、比較が有効であるためか値の 1 つが NaN だったためにテストが false であったことを示します。

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 つのレジスタの値が指定された値と等しい場合、与えられた宛先に分岐します。

注: 分岐オフセットを 0 にすることはできません(スピンループは、後方への goto で分岐するか、分岐前のターゲットとして nop を指定することにより、規則に抵触せずに作成できます)。

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 と等しい場合、与えられた宛先に分岐します。

注: 分岐オフセットを 0 にすることはできません(スピンループは、後方への goto で分岐するか、分岐前のターゲットとして nop を指定することにより、規則に抵触せずに作成できます)。

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* バリアントとともに格納されます。

invoke-virtual は、通常の仮想メソッドを呼び出すために使用されます(メソッドは privatestaticfinal ではなく、コンストラクタでもありません)。

method_id がインターフェースでないクラスのメソッドを参照する際、invoke-super は、(呼び出し元クラス内の同じ method_id の場合とは対照的に)最も近いスーパークラスの仮想メソッドを呼び出すために使用されます。invoke-virtual にも同じメソッド制限が適用されます。

バージョン 037 以降の Dex ファイルでは、method_id がインターフェース メソッドを参照する場合、そのインターフェースで定義されたそのメソッドのオーバーライドされていない最も限定的なバージョンを呼び出すために、invoke-super が使用されます。invoke-virtual にも同じメソッド制限が適用されます。バージョン 037 より前の Dex ファイルでは、インターフェース method_id の使用は規則に抵触し、未定義です。

invoke-direct は、static でない直接メソッドを呼び出すために使用されます(つまり、本質的にオーバーライド不可能なインスタンス メソッドであり、具体的には private インスタンス メソッドまたはコンストラクタです)。

invoke-static は、static メソッド(常に直接メソッドと見なされます)を呼び出すために使用されます。

invoke-interfaceinterface メソッドを呼び出すために使用されます。つまり、具象クラスが不明なオブジェクトでは、interface を参照する method_id が使用されます。

注: これらのオペコードは静的リンクの妥当な候補であり、メソッドの引数をより直接的なオフセット(またはそのペア)に変更します。

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 つのソースレジスタで実行し、結果を宛先レジスタに格納します。

注: 他の -long 算術演算(第 1 ソースと第 2 ソースの両方についてレジスタペアを使用する)と異なり、shl-longshr-longushr-long は、第 1 ソース(シフトされる値)についてはレジスタペアを使用しますが、第 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 ソースレジスタに格納します。

注: 他の -long/2addr 算術演算(宛先 / 第 1 ソースと第 2 ソースの両方についてレジスタペアを使用する)と異なり、shl-long/2addrshr-long/2addrushr-long/2addr は、宛先 / 第 1 ソース(シフトされる値)についてはレジスタペアを使用しますが、第 2 ソース(シフトする距離)については単一のレジスタを使用します。

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 項演算を実行し、結果を宛先レジスタに格納します。

注: このバージョンは同種のオペコードの中核であるため、rsub-int にサフィックスは付きません。セマンティクスの詳細については、後述の説明もご覧ください。

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 項演算を実行し、結果を宛先レジスタに格納します。

注: rsub-int のセマンティクスの詳細については、後述の説明をご覧ください。

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.invokejava.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 も出力されます。
  • ブートストラップ リンカー メソッドが java.lang.invoke.CallSite インスタンスを返すのに失敗した。
  • 返された java.lang.invoke.CallSitenull メソッド ハンドル ターゲットがあった。
  • メソッド ハンドル ターゲットが求められる型ではなかった。
バージョン 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;
最近接丸めを使用して int32float に変換します。一部の値では精度が失われます。
int-to-double int32 a;
double result = (double) a;
int32double に変換します。
long-to-int int64 a;
int32 result = (int32) a;
int64 を切り捨てて int32 に変換します。
long-to-float int64 a;
float result = (float) a;
最近接丸めを使用して int64float に変換します。一部の値では精度が失われます。
long-to-double int64 a;
double result = (double) a;
最近接丸めを使用して int64double に変換します。一部の値では精度が失われます。
float-to-int float a;
int32 result = (int32) a;
ゼロへの丸めを使用して floatint32 に変換します。NaN-0.0(負のゼロ)を整数 0 に変換します。無限大と大きすぎて表現できない値は、符号に応じて 0x7fffffff または -0x80000000 のいずれかに変換されます。
float-to-long float a;
int64 result = (int64) a;
ゼロへの丸めを使用して floatint64 に変換します。float-to-int に関する同じ特殊ケースのルールがここでも適用されます。ただし、範囲外の値は、符号に応じて 0x7fffffffffffffff または -0x8000000000000000 のいずれかに変換されます。
float-to-double float a;
double result = (double) a;
値を正確に保持したまま、floatdouble に変換します。
double-to-int double a;
int32 result = (int32) a;
ゼロへの丸めを使用して doubleint32 に変換します。float-to-int に関する同じ特殊ケースのルールがここでも適用されます。
double-to-long double a;
int64 result = (int64) a;
ゼロへの丸めを使用して doubleint64 に変換します。float-to-long に関する同じ特殊ケースのルールがここでも適用されます。
double-to-float double a;
float result = (float) a;
最近接丸めを使用して doublefloat に変換します。一部の値では精度が失われます。
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 として定義されています。