目次
Java Virtual Machine命令は、実行する操作を指定するopcodeと、操作する値を表す0個以上のオペランドで構成されます。 この章では、各Java Virtual Machine命令の形式とそれが実行する操作について詳しく説明します。
各命令の説明は、§4 (classファイル形式)の静的制約および構造的制約を満たすJava Virtual Machineコードのコンテキストで常に示されます。 個々のJava Virtual Machine命令の説明では、「value2はint型である必要があります」という状況が「必須」または「必須ではない」と頻繁に述べています。 §4 (The class File Format)の制約により、そのようなすべての期待が実際に満たされることを保証します。 実行時に命令記述の一部の制約(必須または不可)が満たされない場合、Java Virtual Machineの動作は未定義です。
Java Virtual Machineでは、classファイル・ベリファイア(§4.10)を使用して、リンク時にJava Virtual Machineコードが静的制約および構造的制約を満たしているかどうかがチェックされます。 したがって、Java Virtual Machineでは、有効なclassファイルからのみコードの実行が試行されます。 リンク時に検証を実行することは、チェックが1回のみ実行され、実行時に実行する必要がある作業量が大幅に削減されるという点で魅力的です。 その他の実装戦略は、The Java Language Specification、 Java SE 26 EditionおよびThe Java Virtual Machine Specification、 Java SE 26 Editionに準拠していれば可能です。
classファイル(§4 (classファイル形式))で使用される、この章で後述する命令のopコードに加えて、3つのopコードは、Java Virtual Machine実装で内部的に使用するために予約されています。 Java Virtual Machineの命令セットが将来拡張された場合、これらの予約されたopコードは使用されないことが保証されます。
予約されているopコードの2つ(254 (0xfe)と255 (0xff)は、ニーモニックimpdep1とimpdep2をそれぞれ持っています。 これらの手順は、それぞれソフトウェアおよびハードウェアで実装される実装固有の機能に「バックドア」またはトラップを提供することを目的としています。 3番目の予約済opcode、番号202 (0xca)にはニーモニック・ブレークポイントがあり、デバッガがブレークポイントを実装するために使用することを目的としています。
これらのopコードは予約されていますが、Java Virtual Machine実装内でのみ使用できます。 有効なclassファイルには使用できません。 すでにロードおよび実行されているJava Virtual Machineコードと直接相互作用する可能性のあるデバッガやJITコード・ジェネレータ(§2.13)などのツールでは、これらのopコードが発生することがあります。 このようなツールは、これらの予約された命令のいずれかが発生した場合に、正常に動作するようにしてください。
Java Virtual Machine実装では、内部エラーまたはリソース制限により、この章で説明するセマンティクスの実装が妨げられている場合に、クラスVirtualMachineErrorのサブクラスのインスタンスであるオブジェクトがスローされます。 この仕様では、内部エラーまたはリソース制限が発生する可能性がある場所を予測できず、レポート可能な場合は正確に指示されません。 したがって、次に定義するVirtualMachineErrorサブクラスは、Java Virtual Machineの操作中にいつでもスローされます。
InternalError: 仮想マシンを実装するソフトウェアの障害、基礎となるホスト・システム・ソフトウェアの障害、またはハードウェアの障害が原因で、Java Virtual Machine実装で内部エラーが発生しました。 このエラーは、検出時に非同期に配信され(§2.10)、プログラムのどの時点でも発生する可能性があります。
OutOfMemoryError: Java Virtual Machine実装で仮想メモリーまたは物理メモリーが不足しており、自動ストレージ・マネージャはオブジェクト作成リクエストを満たすために十分なメモリーを再利用できませんでした。
StackOverflowError: Java Virtual Machine実装は、スレッドのスタック領域を使い果たしました。これは通常、スレッドが実行プログラムの障害の結果として無制限の再帰的呼出しを行っているためです。
UnknownError: 例外またはエラーが発生しましたが、Java Virtual Machine実装で実際の例外またはエラーをレポートできません。
Java Virtual Machineの手順は、この章で、次に示す形式のエントリ、アルファベット順、およびそれぞれが新しいページで開始されることによって表されます。
命令の簡単な説明
mnemonic
operand1
operand2
...
mnemonic = opcode
...、 value1、 value2 →
..., value3
オペランド・スタック・コンテンツまたは定数プール・エントリの制約、実行された操作、結果のタイプなどの詳細を示す長い説明。
この命令の実行によってリンク例外がスローされる可能性がある場合、それらの例外は、スローされる順序で1行に設定されます。
命令の実行によって実行時例外がスローされる場合、それらの例外は、スローされる順序で1行に設定されます。
リンク例外および実行時例外(ある場合)以外に、その命令は、VirtualMachineErrorまたはそのサブクラスのインスタンスを除き、実行時例外をスローしてはなりません。
命令の指定に厳密には含まれないコメントは、説明の最後にノートとして確保されます。
命令形式図の各セルは、単一の8ビットバイトを表します。 命令のmnemonicはその名前です。 opcodeは数値表現であり、10進形式と16進形式の両方で指定されます。 classファイルのJava Virtual Machineコードには、数値表現のみが実際に存在します。
コンパイル時に生成され、Java Virtual Machine命令内に埋め込まれるオペランドや、実行時に計算され、オペランド・スタックに提供されるオペランドがあることに注意してください。 これらは複数の異なる領域から提供されますが、これらのオペランドはすべて同じことを表します。つまり、実行されるJava Virtual Machine命令によって操作される値です。 Java Virtual Machineのコードは、オペランド・スタックから多くのオペランドを暗黙的に取得し、コンパイルされたコードで追加のオペランド・バイト、レジスタ番号などとして明示的に表すのではなく、コンパクトに保たれます。
一部の命令は、単一の記述、形式、およびオペランドスタック図を共有する関連命令ファミリのメンバーとして示されます。 したがって、命令のファミリには、いくつかのopcodesとopcodeニーモニックが含まれています。命令の書式図にはファミリニーモニックのみが表示され、別のform行にはすべてのメンバーニーモニックとopcodesが一覧表示されます。 たとえば、lconst_<l>ファミリの命令のForms行で、そのファミリ(lconst_0およびlconst_1)の2つの命令のニーモニックおよびopcode情報を指定します。
lconst_0 = 9 (0x9)
lconst_1 = 10 (0xa)
Java Virtual Machineの命令の説明では、現在のフレーム(§2.6)のオペランド・スタック(§2.6.2)に対する命令の実行の効果がテキストで表され、スタックは左から右に増加し、各値は個別に表されます。 このため、
...、 value1、 value2 →
..., result
は、オペランドスタックの上に value2があり、その下に value1があることから始まる操作を示しています。 命令の実行結果として、value1およびvalue2がオペランド・スタックからポップされ、命令によって計算されたresult値に置き換えられます。 省略記号(...)で表されるオペランドスタックの残りの部分は、命令の実行の影響を受けません。
long型とdouble型の値は、オペランド・スタック上の単一のエントリで表されます。
Java®仮想マシン仕様の最初のエディションでは、long型とdouble型のオペランド・スタックの値が、それぞれ2つのエントリによってスタック・ダイアグラムに示されました。
配列からのreferenceのロード
アロード
aaload = 50 (0x32)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがreference型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネント内のreferencevalueが取得され、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、aaloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、aaload命令はArrayIndexOutOfBoundsExceptionをスローします。
reference配列に格納
アストア
aastore = 83 (0x53)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがreference型である配列を参照する必要があります。 索引はint型で、値はreference型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。
valueがnullの場合、valueは配列のコンポーネントとしてindexに格納されます。
それ以外の場合、valueはnull以外です。 valueがarrayrefによって参照される配列のコンポーネント・タイプの値である場合、valueはindexに配列のコンポーネントとして格納されます。
valueが配列コンポーネント・タイプの値かどうかは、§checkcastに指定されたルールに従って決定されます。
arrayrefがnullの場合、aastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、aastore命令はArrayIndexOutOfBoundsExceptionをスローします。
それ以外の場合、null以外の値が配列コンポーネント・タイプの値でない場合、aastoreはArrayStoreExceptionをスローします。
プッシュnull
aconst_null
aconst_null = 1 (0x1)
... →
..., null
nullオブジェクトreferenceをオペランド・スタックにプッシュします。
Java Virtual Machineでは、nullの具体的な値は要求されません。
ローカル変数からreferenceをロードします
aload
index
aload = 25 (0x19)
... →
..., objectref
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 indexのローカル変数には、referenceが含まれている必要があります。 indexのローカル変数内のobjectrefは、オペランド・スタックにプッシュされます。
ローカル変数からreferenceをロードします
aload_<n>
aload_0 = 42 (0x2a)
aload_1 = 43 (0x2b)
aload_2 = 44 (0x2c)
aload_3 = 45 (0x2d)
... →
..., objectref
<n>は、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 <n>のローカル変数には、referenceが含まれている必要があります。 <n>のローカル変数のobjectrefがオペランド・スタックにプッシュされます。
aload_<n>命令は、ローカル変数からオペランド・スタックにreturnAddress型の値をロードするために使用できません。 この非対称性は、対応するastore_<n>命令(§astore_<n>)によって意図的に行われます。
aload_<n>の各命令は、<n>の索引を持つaloadと同じですが、オペランド<n>が暗黙的に指定されています。
referenceの新しい配列を作成します。
anewarray
indexbyte1
indexbyte2
anewarray = 189 (0xbd)
...、 count →
..., arrayref
countはint型である必要があります。 オペランド・スタックからポップされます。 countは、作成する配列のコンポーネントの数を表します。 符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、クラス、配列またはインタフェース・タイプへのシンボリック参照である必要があります。 指定されたクラス、配列、またはインタフェース型が解決されます(§5.4.3.1)。 その型のコンポーネント(長さがcount)を持つ新しい配列は、ガベージ・コレクション・ヒープから割り当てられ、この新しい配列オブジェクトにreference arrayrefがオペランド・スタックにプッシュされます。 新しい配列のすべてのコンポーネントは、reference型のデフォルト値であるnullに初期化されます(§2.4)。
クラス、配列またはインタフェース型へのシンボリック参照の解決中に、§5.4.3.1に記載されている例外をスローできます。
それ以外の場合、countが0より小さい場合、anewarray命令はNegativeArraySizeExceptionをスローします。
anewarray命令は、オブジェクト参照の配列または多次元配列の一部の単一ディメンションを作成するために使用されます。
メソッドからreferenceを返します
アレット
areturn = 176 (0xb0)
...、 objectref →
[空]
objectrefは、reference型である必要があり、現在のメソッドの戻り記述子(§4.3.3)で表される型と代入互換(JLS§5.2)の型のオブジェクトを参照する必要があります。 現在のメソッドがsynchronizedメソッドの場合、メソッドの起動時に入力または再入力されたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。 例外がスローされない場合、objectrefは現在のフレームのオペランド・スタック(§2.6)からポップされ、実行者のフレームのオペランド・スタックにプッシュされます。 現在のメソッドのオペランド・スタック上のその他の値はすべて破棄されます。
その後、インタプリタは実行者のフレームを修復し、実行者に制御を戻します。
Java Virtual Machineの実装で、§2.11.10で説明されている構造化ロックのルールが強制されない場合は、現在のメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、areturnはIllegalMonitorStateExceptionをスローします。 これは、たとえば、synchronizedメソッドにmonitorexit命令が含まれているが、メソッドが同期されているオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックにルールが適用され、現在のメソッドの起動中にそれらのルールの最初のルールに違反した場合、areturnはIllegalMonitorStateExceptionをスローします。
配列の長さを取得
arraylength
arraylength = 190 (0xbe)
...、 arrayref →
..., length
arrayrefはreference型である必要があり、配列を参照する必要があります。 オペランド・スタックからポップされます。 参照する配列の長さが決定されます。 その長さは、オペランド・スタックにintとしてプッシュされます。
arrayrefがnullの場合、arraylength命令はNullPointerExceptionをスローします。
referenceをローカル変数に格納します
astore
index
astore = 58 (0x3a)
...、 objectref →
...
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 オペランド・スタックの先頭にあるobjectrefは、returnAddress型またはreference型である必要があります。 オペランド・スタックからポップされ、indexのローカル変数の値がobjectrefに設定されます。
referenceをローカル変数に格納します
astore_<n>
astore_0 = 75 (0x4b)
astore_1 = 76 (0x4c)
astore_2 = 77 (0x4d)
astore_3 = 78 (0x4e)
...、 objectref →
...
<n>は、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 オペランド・スタックの先頭にあるobjectrefは、returnAddress型またはreference型である必要があります。 オペランド・スタックからポップされ、<n>のローカル変数の値がobjectrefに設定されます。
astore_<n>命令は、Javaプログラミング言語(§3.13)のfinally句を実装するときに、returnAddress型のobjectrefとともに使用されます。
aload_<n>命令(§aload_<n>)は、ローカル変数からオペランド・スタックにreturnAddress型の値をロードするために使用できません。 対応するastore_<n>命令とのこの非対称性は意図的です。
各astore_<n>命令は、<n>のindexを持つastoreと同じです。ただし、オペランド<n>は暗黙的です。
例外またはエラーのスロー
スロー
athrow = 191 (0xbf)
...、 objectref →
objectref
objectrefはreference型である必要があり、ThrowableクラスまたはThrowableのサブクラスのインスタンスであるオブジェクトを参照する必要があります。 オペランド・スタックからポップされます。 次に、objectrefは、§2.10のアルゴリズムで指定されているように、objectrefのクラスと一致する最初の例外ハンドラについて現在のメソッド(§2.6)を検索することによってスローされます。
objectrefに一致する例外ハンドラが見つかった場合は、この例外を処理するためのコードの場所が含まれます。 pcレジスタは、その場所にリセットされ、現在のフレームのオペランド・スタックがクリアされ、objectrefがオペランド・スタックにプッシュバックされ、実行が続行されます。
現在のフレームに一致する例外ハンドラが見つからない場合は、そのフレームがポップされます。 現在のフレームがsynchronizedメソッドの起動を表す場合、メソッドの起動時に入力または再入力されたモニターは、monitorexit命令(§monitorexit)を実行した場合と同様に終了します。 最後に、そのようなフレームが存在し、objectrefが再スローされた場合、その実行者のフレームは回復されます。 そのようなフレームが存在しない場合は、現在のスレッドが終了します。
objectrefがnullの場合、athrowはobjectrefのかわりにNullPointerExceptionをスローします。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックにルールが適用されない場合、現在のフレームのメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、スローは、以前にスローされたオブジェクトではなくIllegalMonitorStateExceptionをスローします。 これは、たとえば、突然完了するsynchronizedメソッドにmonitorexit命令が含まれているが、メソッドが同期されるオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックにルールが適用され、現在のメソッドの起動中にそれらのルールの最初のルールに違反した場合、スローは以前にスローされたオブジェクトではなくIllegalMonitorStateExceptionをスローします。
athrow命令のオペランド・スタック・ダイアグラムは誤解を招く可能性があります。この例外のハンドラが現在のメソッドで一致した場合、athrow命令はオペランド・スタック上のすべての値を破棄し、スローされたオブジェクトをオペランド・スタックにプッシュします。 ただし、現在のメソッドで一致するハンドラがなく、例外がメソッド呼出しチェーンより先にスローされた場合、例外を処理するメソッドのオペランド・スタック(ある場合)はクリアされ、objectrefはその空のオペランド・スタックにプッシュされます。 例外を処理するメソッドまで(含まない)例外をスローしたメソッドからのすべての介在フレームは破棄されます。
配列からbyteまたはbooleanをロードします
バルロード
baload = 51 (0x33)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがbyte型またはboolean型の配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネント内のbytevalueが取得され、intvalueに符号が拡張されて、オペランド・スタックの上部にプッシュされます。
arrayrefがnullの場合、baloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、baload命令はArrayIndexOutOfBoundsExceptionをスローします。
byteまたはboolean配列に格納します。
bastore
bastore = 84 (0x54)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがbyte型またはboolean型の配列を参照する必要があります。 索引と値は両方ともint型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。
arrayrefがbyte型のコンポーネントの配列を参照する場合、int valueはbyteに切り捨てられ、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがboolean型のコンポーネントの配列を参照する場合、int valueは、valueおよび1のビット単位ANDを使用して絞り込まれます。結果は、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、bastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、bastore命令はArrayIndexOutOfBoundsExceptionをスローします。
プッシュbyte
bipush
byte
bipush = 16 (0x10)
... →
..., value
直近のバイトは、int値に符号拡張されます。 その値は、オペランド・スタックにプッシュされます。
配列からのcharのロード
caload
caload = 52 (0x34)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがchar型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネントが取得され、intvalueにゼロ拡張されます。 その値は、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、caloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の範囲内にない場合、caload命令はArrayIndexOutOfBoundsExceptionをスローします。
char配列に格納
キャスト
castore = 85 (0x55)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがchar型である配列を参照する必要があります。 索引と値は両方ともint型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。 int valueは、charに切り捨てられ、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、castoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の範囲内にない場合、castore命令はArrayIndexOutOfBoundsExceptionをスローします。
オブジェクトが指定されたタイプかどうかを確認します
チェックキャスト
indexbyte1
indexbyte2
checkcast = 192 (0xc0)
...、 objectref →
..., objectref
objectrefはreference型である必要があります。 符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、クラス、配列またはインタフェース・タイプへのシンボリック参照である必要があります。
objectrefがnullの場合、オペランド・スタックは変更されません。
それ以外の場合は、名前付きクラス、配列、またはインタフェース型が解決されます(§5.4.3.1)。 objectrefが解決されたクラス、配列またはインタフェース・タイプによって指定された型の値である場合、オペランド・スタックは変更されません。
次のルールを使用して、オブジェクトへのnull以外の参照が参照型Tの値であるかどうかを判断します。
参照がクラスCのインスタンスに対する場合は、次のようになります。
TがクラスDのタイプである場合、CがDの場合、またはDのサブクラスの場合、参照はTの値になります。
Tがインタフェース Iのタイプである場合、Cが Iを実装する場合、参照は Tの値です。
コンポーネント・タイプがSCの配列に対する参照の場合は、次のようになります。
Tがクラス型の場合、TがObjectの場合、参照はTの値になります。
Tがインタフェース型の場合、TがCloneableまたはjava.io.Serializableで、ブートストラップ・クラス・ローダー(§5.3)で定義されているように、参照はTの値になります。
Tが配列型 TC[]、つまり TC型のコンポーネントの配列である場合、次のいずれかが当てはまる場合、参照は Tの値です。
TCと SCは同じタイプです。
TCは、クラス型Objectです。
TCはクラスまたはインタフェース型で、SCはクラスまたはインタフェース型で、SCによって指定されたクラスまたはインタフェースは、TCによって指定されたクラスまたはインタフェースを拡張または実装します。
SCは配列型SCC[]で、コンポーネント型SCCの配列への参照はTC型の値です(これらのルールを再帰的に適用します)。
クラス、配列またはインタフェース型へのシンボリック参照の解決中に、§5.4.3.1に記載されている例外をスローできます。
それ以外の場合、objectrefがnullでなく、解決されたクラス、配列またはインタフェース・タイプによって指定された型の値ではない場合、checkcast命令はClassCastExceptionをスローします。
checkcast命令は、instanceof命令(§instanceof)とよく似ています。 nullの処理、テストが失敗した場合の動作(checkcastは例外をスローし、instanceofは結果コードをプッシュ)、オペランド・スタックへの影響は異なります。
doubleをfloatに変換します。
d2f
d2f = 144 (0x90)
...、 value →
..., result
オペランド・スタックの先頭にある値は、double型である必要があります。 オペランド・スタックからポップされ、最も近い丸めポリシー(§2.8)を使用してfloat結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
floatとして表すには小さすぎる有限値は、同じ符号のゼロに変換されます。floatとして表すには大きすぎる有限値は、同じ符号の無限大に変換されます。 double NaNは、float NaNに変換されます。
d2f命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われ、精度も失われる可能性があります。
doubleをintに変換します。
d2i
d2i = 142 (0x8e)
...、 value →
..., result
オペランド・スタックの先頭にある値は、double型である必要があります。 オペランド・スタックからポップされ、int結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
valueがNaNの場合、変換の結果はint 0になります。
それ以外の場合、valueが無限大でない場合、丸めゼロの丸めポリシー(§2.8)を使用して整数値 Vに丸められます。 この整数値Vをintとして表すことができる場合、結果はint値Vになります。
それ以外の場合、valueは小さすぎる(大きい大きさまたは負の無限大の負の値)必要があり、結果がint型の表現可能な最小値であるか、valueが大きすぎる(大きい大きさまたは正の無限大の正の値)必要があり、その結果がint型の表現可能な最大値になります。
d2i命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われ、精度も失われる可能性があります。
doubleをlongに変換します。
d2l
d2l = 143 (0x8f)
...、 value →
..., result
オペランド・スタックの先頭にある値は、double型である必要があります。 オペランド・スタックからポップされ、longに変換されます。 resultは、オペランド・スタックにプッシュされます。
valueがNaNの場合、変換の結果はlong 0になります。
それ以外の場合、valueが無限大でない場合、丸めゼロの丸めポリシー(§2.8)を使用して整数値 Vに丸められます。 この整数値Vをlongとして表すことができる場合、結果はlong値Vになります。
それ以外の場合、valueは小さすぎる(大きい大きさまたは負の無限大の負の値)必要があり、結果がlong型の表現可能な最小値であるか、valueが大きすぎる(大きい大きさまたは正の無限大の正の値)必要があり、その結果がlong型の表現可能な最大値になります。
d2l命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われ、精度も失われる可能性があります。
doubleを追加します。
dadd
dadd = 99 (0x63)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもdouble型である必要があります。 値はオペランド・スタックからポップされます。 double resultは、value1 + value2です。 resultは、オペランド・スタックにプッシュされます。
dadd命令の結果は、IEEE 754演算の規則によって管理されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
反対符号の2つの無限度の合計は NaNです。
同じ符号の2つの無限度の合計は、その符号の無限大です。
無限大と有限値の合計は無限大と等しくなります。
反対符号の2つのゼロの合計は正のゼロです。
同じ符号の2つのゼロの合計は、その符号の0です。
ゼロとゼロ以外の有限値の合計は、ゼロ以外の値と同じです。
同じ大きさおよび反対符号の2つのゼロ以外の有限値の合計は正のゼロです。
オペランドが無限大、ゼロ、または NaNでなく、値が同じ符号を持つか、または異なる大きさを持つ残りのケースでは、丸めから最も近い丸めポリシー(§2.8)を使用して、合計が計算され、最も近い表現可能な値に丸められます。 大きさが大きすぎてdoubleとして表せない場合、操作はオーバーフローします。その結果は適切な符号の無限大になります。 マグニチュードが小さすぎてdoubleとして表せない場合、操作はアンダーフローし、その結果は適切な符号のゼロになります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、または精度の損失が発生する可能性があるにもかかわらず、dadd命令の実行によって実行時例外がスローされることはありません。
配列からのdoubleのロード
daload
daload = 49 (0x31)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがdouble型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネント内のdoublevalueが取得され、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、daloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、daload命令はArrayIndexOutOfBoundsExceptionをスローします。
double配列に格納
dastore
dastore = 82 (0x52)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがdouble型である配列を参照する必要があります。 索引はint型で、値はdouble型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。 double valueは、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、dastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、dastore命令はArrayIndexOutOfBoundsExceptionをスローします。
比較 double
dcmp<op>
dcmpg = 152 (0x98)
dcmpl = 151 (0x97)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもdouble型である必要があります。 値はオペランドスタックからポップされ、浮動小数点比較が実行されます。
value1がvalue2より大きい場合、int値1はオペランド・スタックにプッシュされます。
それ以外の場合、value1がvalue2と等しい場合、int値0はオペランド・スタックにプッシュされます。
それ以外の場合、value1がvalue2より小さい場合、int値-1はオペランド・スタックにプッシュされます。
それ以外の場合、value1またはvalue2の少なくとも1つがNaNです。 dcmpg命令はint値1をオペランド・スタックにプッシュし、dcmpl命令はint値-1をオペランド・スタックにプッシュします。
浮動小数点比較は、IEEE 754に従って実行されます。 NaN以外のすべての値が順序付けされ、負の無限大がすべての有限値より小さく、正の無限大がすべての有限値よりも大きくなります。 正のゼロと負のゼロは等しいとみなされます。
dcmpgおよびdcmpl命令は、NaNを含む比較の処理のみが異なります。 NaNは順序付けられていないため、オペランドのいずれかまたは両方がNaNの場合、double比較は失敗します。 dcmpgとdcmplの両方が使用可能な場合は、double比較をコンパイルして、非NaN値で比較が失敗するか、NaNが検出されたために失敗するかに関係なく、同じresultをオペランド・スタックにプッシュできます。 詳細は、§3.5を参照してください。
プッシュdouble
dconst_<d>
dconst_0 = 14 (0xe)
dconst_1 = 15 (0xf)
... →
...、<d>
double定数<d> (0.0または1.0)をオペランド・スタックにプッシュします。
doubleの除算
ddiv
ddiv = 111 (0x6f)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもdouble型である必要があります。 値はオペランド・スタックからポップされます。 double resultは、value1 / value2です。 resultは、オペランド・スタックにプッシュされます。
ddiv命令の結果は、IEEE 754演算のルールによって制御されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
value1もvalue2もNaNでない場合、両方の値が同じ符号を持つと結果の符号は正になり、値が異なる符号を持つと負になります。
無限大による無限大の除算はNaNになります。
有限値による無限大の除算は、符号付き無限大となり、符号生成規則が与えられた。
無限大による有限値を除算すると、符号付きゼロになり、符号生成ルールが指定されます。
ゼロをゼロで除算すると NaNになります。ゼロを他の有限値で除算すると、符号付きゼロになり、符号生成ルールが指定されただけです。
ゼロ以外の有限値をゼロで除算すると、符号付き無限大になり、符号生成ルールが指定されます。
オペランドが無限大、ゼロまたはNaNでない残りのケースでは、四捨五入を使用して四捨五入が計算され、最も近い丸めポリシー(§2.8)を使用して最も近いdoubleに丸められます。 大きさが大きすぎてdoubleとして表せない場合、操作はオーバーフローします。その結果は適切な符号の無限大になります。 マグニチュードが小さすぎてdoubleとして表せない場合、操作はアンダーフローし、その結果は適切な符号のゼロになります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、ゼロによる除算、または精度の損失が発生する可能性があるにもかかわらず、ddiv命令を実行すると実行時例外がスローされることはありません。
ローカル変数からdoubleをロードします
dload
インデックス
dload = 24 (0x18)
... →
..., value
索引は符号なしバイトです。 indexと index+1はどちらも、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければなりません。 indexのローカル変数には、doubleが含まれている必要があります。 indexのローカル変数のvalueは、オペランド・スタックにプッシュされます。
dload opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
ローカル変数からdoubleをロードします
dload_<n>
dload_0 = 38 (0x26)
dload_1 = 39 (0x27)
dload_2 = 40 (0x28)
dload_3 = 41 (0x29)
... →
..., value
<n>と<n>+1の両方が、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 <n>のローカル変数には、doubleが含まれている必要があります。 <n>のローカル変数の値がオペランド・スタックにプッシュされます。
各dload_<n>命令は、<n>の索引を持つdloadと同じです。ただし、オペランド<n>は暗黙的です。
doubleの乗算
dmul
dmul = 107 (0x6b)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもdouble型である必要があります。 値はオペランド・スタックからポップされます。 double resultは、value1 * value2です。 resultは、オペランド・スタックにプッシュされます。
dmul命令の結果は、IEEE 754演算の規則によって制御されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
value1もvalue2もNaNでない場合、値に異なる符号がある場合は、両方の値に同じ符号と負の符号がある場合、結果の符号は正になります。
無限大をゼロで乗算すると、NaNになります。
無限大を有限値で乗算すると、符号付き無限大になり、符号生成ルールが指定されます。
無限大もNaNも関係しない残りのケースでは、丸めから最も近い丸めポリシー(§2.8)を使用して、プロダクトが計算され、最も近い表現可能な値に丸められます。 大きさが大きすぎてdoubleとして表せない場合、操作はオーバーフローします。その結果は適切な符号の無限大になります。 マグニチュードが小さすぎてdoubleとして表せない場合、操作はアンダーフローし、その結果は適切な符号のゼロになります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、または精度の損失が発生する可能性があるにもかかわらず、dmul命令の実行によって実行時例外がスローされることはありません。
否定double
dneg
dneg = 119 (0x77)
...、 value →
..., result
値はdouble型である必要があります。 オペランド・スタックからポップされます。 double resultは、valueの算術否定です。 resultは、オペランド・スタックにプッシュされます。
double値の場合、否定はゼロからの減算と同じではありません。 xが+0.0の場合、0.0-xは+0.0と等しくなりますが、-xは-0.0と等しくなります。 単項マイナスは、doubleの符号を反転するだけです。
特別な関心事:
オペランドがNaNの場合、結果はNaNになります(NaNには符号がないことを思い出してください)。
Java Virtual Machineは、NaNを含むすべての入力の符号ビットを否定が反転する2019バージョンのIEEE 754 Standardのより強力な要件を採用していません。
オペランドが無限大の場合、結果は反対符号の無限大になります。
オペランドがゼロの場合、結果は反対符号のゼロになります。
剰余double
drem
drem = 115 (0x73)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもdouble型である必要があります。 値はオペランド・スタックからポップされます。 doubleresultが計算され、オペランド・スタックにプッシュされます。
drem命令の結果は、Java Virtual Machine (§2.8)で丸めポリシーを選択したため、IEEE 754で定義された残りの操作の結果と同じではありません。 IEEE 754剰余演算は、切り捨て除算ではなく端数処理除算からの剰余を計算するため、その動作は通常の整数剰余演算子の動作と似ていません。 かわりに、Java Virtual Machineでは、整数剰余命令iremおよびlremと同様の方法で動作するようにdremを定義し、丸めゼロの丸めポリシーを使用する暗黙の除算を使用します。これは、Cライブラリ関数fmodと比較できます。
drem命令の結果は、暗黙の除算の計算方法を除き、IEEE 754算術と一致する次のルールによって制御されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
value1もvalue2もNaNでない場合、結果の符号は配当の符号と等しくなります。
配当が無限大または除数がゼロまたは両方の場合、結果はNaNになります。
配当が有限で、除数が無限である場合、結果は配当と等しくなります。
配当がゼロで、除数が有限の場合、結果は配当と等しくなります。
オペランドが無限大、ゼロ、または NaNのいずれでもない残りの場合、浮動小数点の残り resultは配当 value1から、除数 value2は数学的な関係 result = value1 - (value2 * q)によって定義されます。qは、value1 / value2が負の場合にのみ負の整数で、value1 / value2が正の場合にのみ正の整数で、その大きさは、value1およびvalue2の真の数学的商の大きさを超えずに可能なかぎり大きくなります。
ゼロによる除算が発生する可能性はありますが、drem命令の評価では実行時例外はスローされません。 オーバーフロー、アンダーフロー、または精度の損失は発生しません。
IEEE 754残り操作は、ライブラリルーチン Math.IEEEremainderまたは StrictMath.IEEEremainderによって計算できます。
メソッドからdoubleを返します
dreturn
dreturn = 175 (0xaf)
...、 value →
[空]
現在のメソッドには、戻り型doubleが必要です。 valueはdouble型である必要があります。 現在のメソッドがsynchronizedメソッドの場合、メソッドの起動時に入力または再入力されたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。 例外がスローされない場合、valueは現在のフレームのオペランドスタック(§2.6)からポップされ、呼び出し元のフレームのオペランドスタックにプッシュされます。 現在のメソッドのオペランド・スタック上のその他の値はすべて破棄されます。
インタプリタは、メソッドの起動元に制御を戻し、起動元のフレームを元に戻します。
Java Virtual Machineの実装で、§2.11.10で説明されている構造化ロックのルールが適用されない場合、現在のメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、dreturnはIllegalMonitorStateExceptionをスローします。 これは、たとえば、synchronizedメソッドにmonitorexit命令が含まれているが、メソッドが同期されているオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で、§2.11.10で説明されている構造化ロックにルールが適用され、現在のメソッドの呼出し中にそれらのルールの最初のルールに違反した場合、dreturnはIllegalMonitorStateExceptionをスローします。
doubleをローカル変数に格納します
dstore
索引
dstore = 57 (0x39)
...、 value →
...
索引は符号なしバイトです。 indexと index+1はどちらも、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければなりません。 オペランド・スタックの先頭にある値は、double型である必要があります。 オペランド・スタックからポップされます。 indexおよびindex+1のローカル変数は、valueに設定されます。
dstore opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
doubleをローカル変数に格納します
dstore_<n>
dstore_0 = 71 (0x47)
dstore_1 = 72 (0x48)
dstore_2 = 73 (0x49)
dstore_3 = 74 (0x4a)
...、 value →
...
<n>と<n>+1の両方が、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 オペランド・スタックの先頭にある値は、double型である必要があります。 オペランド・スタックからポップされます。 <n>および<n>+1のローカル変数は、valueに設定されます。
dstore_<n>の各命令は、<n>の索引を持つdstoreと同じですが、オペランド<n>が暗黙的に指定されている点が異なります。
doubleを減算
dsub
dsub = 103 (0x67)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもdouble型である必要があります。 値はオペランド・スタックからポップされます。 double resultは、value1 - value2です。 resultは、オペランド・スタックにプッシュされます。
doubleの減算では、a-bがa+(-b)と同じ結果を生成するのは常に同じです。 ただし、dsub命令の場合、xが+0.0の場合、0.0-xは+0.0と等しくなりますが、-xは-0.0と等しいため、ゼロからの減算は否定とは異なります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、または精度の損失が発生する可能性があるにもかかわらず、dsub命令の実行によって実行時例外がスローされることはありません。
上部のオペランド・スタック値の複製
dup
dup = 89 (0x59)
...、 value →
..., value, value
上部のオペランド・スタック値を複製し、2つの値を下に挿入します。
dup_x1
dup_x1 = 90 (0x5a)
...、 value2、 value1 →
..., value1, value2, value1
オペランド・スタックで最上位の値を複製し、重複した値をオペランド・スタックで2つ下に挿入します。
dup_x1命令は、value1と value2の両方がカテゴリ1の計算タイプ(§2.11.1)の値でないかぎり、使用してはいけません。
上部のオペランド・スタック値を複製し、2つまたは3つの値を下に挿入します。
dup_x2
dup_x2 = 91 (0x5b)
フォーム 1:
...、 value3、 value2、 value1 →
..., value1, value3, value2, value1
ここで、value1、value2およびvalue3は、カテゴリ1の計算型(§2.11.1)のすべての値です。
フォーム 2:
...、 value2、 value1 →
..., value1, value2, value1
ここで、value1はカテゴリ1の計算型の値で、value2はカテゴリ2の計算型の値です(§2.11.1)。
オペランドスタックで最上位の値を複製し、重複した値をオペランドスタックで2つまたは3つ下に挿入します。
上位1つまたは2つのオペランド・スタック値の複製
dup2
dup2 = 92 (0x5c)
フォーム 1:
...、 value2、 value1 →
..., value2, value1, value2, value1
ここで、value1とvalue2は、カテゴリ1の計算型の値です(§2.11.1)。
フォーム 2:
...、 value →
..., value, value
ここで、valueは、カテゴリ2の計算型の値です(§2.11.1)。
オペランドスタックの上位1つまたは2つの値を複製し、重複した値を元の順序でオペランドスタックに戻します。
上位1つまたは2つのオペランド・スタック値を複製し、2つまたは3つの値を下に挿入します。
dup2_x1
dup2_x1 = 93 (0x5d)
フォーム 1:
...、 value3、 value2、 value1 →
..., value2, value1, value3, value2, value1
ここで、value1、value2およびvalue3は、カテゴリ1の計算型(§2.11.1)のすべての値です。
フォーム 2:
...、 value2、 value1 →
..., value1, value2, value1
ここで、value1はカテゴリ2の計算型の値で、value2はカテゴリ1の計算型の値です(§2.11.1)。
オペランドスタック上の上部の1つまたは2つの値を複製し、複製された値を元の順序で、元の値またはオペランドスタック内の値の下に1つの値を挿入します。
上位1つまたは2つのオペランド・スタック値を複製し、2、3または4つの値を下に挿入します。
dup2_x2
dup2_x2 = 94 (0x5e)
フォーム 1:
...、 value4、 value3、 value2、 value1 →
..., value2, value1, value4, value3, value2, value1
ここで、value1、value2、value3およびvalue4は、カテゴリ1の計算型(§2.11.1)のすべての値です。
フォーム 2:
...、 value3、 value2、 value1 →
..., value1, value3, value2, value1
ここで、value1はカテゴリ2の計算型の値で、value2とvalue3はいずれもカテゴリ1の計算型の値です(§2.11.1)。
フォーム 3:
...、 value3、 value2、 value1 →
..., value2, value1, value3, value2, value1
ここで、value1およびvalue2は、カテゴリ1の計算型の値であり、value3はカテゴリ2の計算型の値です(§2.11.1)。
フォーム 4:
...、 value2、 value1 →
..., value1, value2, value1
ここで、value1とvalue2はいずれも、カテゴリ2の計算型の値です(§2.11.1)。
オペランドスタックの上位1つまたは2つの値を複製し、複製された値を元の順序でオペランドスタックに挿入します。
floatをdoubleに変換します。
f2d
f2d = 141 (0x8d)
...、 value →
..., result
オペランド・スタックの先頭にある値は、float型である必要があります。 オペランド・スタックからポップされ、double結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
f2d命令は、拡張プリミティブ変換(JLS§5.1.2)を実行します。
floatをintに変換します。
f22i
f2i = 139 (0x8b)
...、 value →
..., result
オペランド・スタックの先頭にある値は、float型である必要があります。 オペランド・スタックからポップされ、int結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
値がNaNの場合、変換の結果はint 0です。
それ以外の場合、valueが無限大でない場合、丸めゼロの丸めポリシー(§2.8)を使用して整数値 Vに丸められます。 この整数値Vをintとして表すことができる場合、resultはint値Vです。
そうでない場合は、valueが小さすぎる(大きい大きさまたは負の無限大の負の値)必要があり、resultがint型の最小表現可能な値であるか、valueが大きすぎる(大きい大きさまたは正の無限大の正の値)必要があり、resultがint型の最大表現可能な値です。
f2i命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われ、精度も失われる可能性があります。
floatをlongに変換します。
f2l
f2l = 140 (0x8c)
...、 value →
..., result
オペランド・スタックの先頭にある値は、float型である必要があります。 オペランド・スタックからポップされ、long結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
valueがNaNの場合、変換の結果はlong 0になります。
それ以外の場合、valueが無限大でない場合、丸めゼロの丸めポリシー(§2.8)を使用して整数値 Vに丸められます。 この整数値Vをlongとして表すことができる場合、resultはlong値Vです。
そうでない場合は、valueが小さすぎる(大きい大きさまたは負の無限大の負の値)必要があり、resultがlong型の最小表現可能な値であるか、valueが大きすぎる(大きい大きさまたは正の無限大の正の値)必要があり、resultがlong型の最大表現可能な値です。
f2l命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われ、精度も失われる可能性があります。
floatを追加します。
fadd
fadd = 98 (0x62)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもfloat型である必要があります。 値はオペランド・スタックからポップされます。 float resultは、value1 + value2です。 resultは、オペランド・スタックにプッシュされます。
fadd命令の結果は、IEEE 754演算の規則によって管理されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
反対符号の2つの無限度の合計は NaNです。
同じ符号の2つの無限度の合計は、その符号の無限大です。
無限大と有限値の合計は無限大と等しくなります。
反対符号の2つのゼロの合計は正のゼロです。
同じ符号の2つのゼロの合計は、その符号の0です。
ゼロとゼロ以外の有限値の合計は、ゼロ以外の値と同じです。
同じ大きさおよび反対符号の2つのゼロ以外の有限値の合計は正のゼロです。
オペランドが無限大、ゼロ、または NaNでなく、値が同じ符号を持つか、または異なる大きさを持つ残りのケースでは、丸めから最も近い丸めポリシー(§2.8)を使用して、合計が計算され、最も近い表現可能な値に丸められます。 大きさが大きすぎてfloatとして表せない場合、操作はオーバーフローします。その結果は適切な符号の無限大になります。 マグニチュードが小さすぎてfloatとして表せない場合、操作はアンダーフローし、その結果は適切な符号のゼロになります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、または精度の損失が発生する可能性があるにもかかわらず、fadd命令の実行によって実行時例外がスローされることはありません。
配列からのfloatのロード
faload
faload = 48 (0x30)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがfloat型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネント内のfloat値が取得され、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、faloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、faload命令はArrayIndexOutOfBoundsExceptionをスローします。
float配列に格納
fastore
fastore = 81 (0x51)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがfloat型である配列を参照する必要があります。 索引はint型で、値はfloat型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。 float valueは、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、fastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、fastore命令はArrayIndexOutOfBoundsExceptionをスローします。
比較 float
fcmp<op>
fcmpg = 150 (0x96)
fcmpl = 149 (0x95)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもfloat型である必要があります。 値はオペランドスタックからポップされ、浮動小数点比較が実行されます。
value1がvalue2より大きい場合、int値1はオペランド・スタックにプッシュされます。
それ以外の場合、value1がvalue2と等しい場合、int値0はオペランド・スタックにプッシュされます。
それ以外の場合、value1がvalue2より小さい場合、int値-1はオペランド・スタックにプッシュされます。
それ以外の場合、value1またはvalue2の少なくとも1つがNaNです。 fcmpg命令はint値1をオペランド・スタックにプッシュし、fcmpl命令はint値-1をオペランド・スタックにプッシュします。
浮動小数点比較は、IEEE 754に従って実行されます。 NaN以外のすべての値が順序付けされ、負の無限大がすべての有限値より小さく、正の無限大がすべての有限値よりも大きくなります。 正のゼロと負のゼロは等しいとみなされます。
fcmpgおよびfcmpl命令は、NaNを含む比較の処理のみが異なります。 NaNは順序付けられていないため、オペランドのいずれかまたは両方がNaNの場合、float比較は失敗します。 fcmpgとfcmplの両方が使用可能な場合は、float比較をコンパイルして、NaN以外の値で比較が失敗するか、NaNが検出されたために失敗するかに関係なく、同じresultをオペランド・スタックにプッシュできます。 詳細は、§3.5を参照してください。
プッシュfloat
fconst_<f>
fconst_0 = 11 (0xb)
fconst_1 = 12 (0xc)
fconst_2 = 13 (0xd)
... →
...、<f>
float定数<f> (0.0、1.0または2.0)をオペランド・スタックにプッシュします。
floatの除算
fdiv
fdiv = 110 (0x6e)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもfloat型である必要があります。 値はオペランド・スタックからポップされます。 float resultは、value1 / value2です。 resultは、オペランド・スタックにプッシュされます。
fdiv命令の結果は、IEEE 754演算の規則によって制御されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
value1もvalue2もNaNでない場合、両方の値が同じ符号を持つと結果の符号は正になり、値が異なる符号を持つと負になります。
無限大による無限大の除算はNaNになります。
有限値による無限大の除算は、符号付き無限大となり、符号生成規則が与えられた。
無限大による有限値を除算すると、符号付きゼロになり、符号生成ルールが指定されます。
ゼロをゼロで除算すると NaNになります。ゼロを他の有限値で除算すると、符号付きゼロになり、符号生成ルールが指定されただけです。
ゼロ以外の有限値をゼロで除算すると、符号付き無限大になり、符号生成ルールが指定されます。
オペランドが無限大、ゼロまたはNaNでない残りのケースでは、四捨五入を使用して四捨五入が計算され、最も近い丸めポリシー(§2.8)を使用して最も近いfloatに丸められます。 大きさが大きすぎてfloatとして表せない場合、操作はオーバーフローします。その結果は適切な符号の無限大になります。 マグニチュードが小さすぎてfloatとして表せない場合、操作はアンダーフローし、その結果は適切な符号のゼロになります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、ゼロによる除算、または精度の損失が発生する可能性があるにもかかわらず、fdiv命令の実行によって実行時例外がスローされることはありません。
ローカル変数からfloatをロードします
fload
インデックス
fload = 23 (0x17)
... →
..., value
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 indexのローカル変数には、floatが含まれている必要があります。 indexのローカル変数のvalueは、オペランド・スタックにプッシュされます。
fload opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
ローカル変数からfloatをロードします
fload_<n>
fload_0 = 34 (0x22)
fload_1 = 35 (0x23)
fload_2 = 36 (0x24)
fload_3 = 37 (0x25)
... →
..., value
<n>は、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 <n>のローカル変数には、floatが含まれている必要があります。 <n>のローカル変数の値がオペランド・スタックにプッシュされます。
fload_<n>の各命令は、<n>の索引を持つfloadと同じですが、オペランド<n>が暗黙的に指定されています。
floatの乗算
fmul
fmul = 106 (0x6a)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもfloat型である必要があります。 値はオペランド・スタックからポップされます。 float resultは、value1 * value2です。 resultは、オペランド・スタックにプッシュされます。
fmul命令の結果は、IEEE 754演算の規則によって管理されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
value1もvalue2もNaNでない場合は、両方の値が同じ符号を持つ場合は結果の符号が正になり、値が異なる符号を持つ場合は負になります。
無限大をゼロで乗算すると、NaNになります。
無限大を有限値で乗算すると、符号付き無限大になり、符号生成ルールが指定されます。
無限大もNaNも関係しない残りのケースでは、丸めから最も近い丸めポリシー(§2.8)を使用して、プロダクトが計算され、最も近い表現可能な値に丸められます。 大きさが大きすぎてfloatとして表せない場合、操作はオーバーフローします。その結果は適切な符号の無限大になります。 マグニチュードが小さすぎてfloatとして表せない場合、操作はアンダーフローし、その結果は適切な符号のゼロになります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、または精度の損失が発生する可能性があるにもかかわらず、fmul命令の実行によって実行時例外がスローされることはありません。
否定float
fneg
fneg = 118 (0x76)
...、 value →
..., result
valueはfloat型である必要があります。 オペランド・スタックからポップされます。 float resultは、valueの算術否定です。 resultは、オペランド・スタックにプッシュされます。
float値の場合、否定はゼロからの減算と同じではありません。 xが+0.0の場合、0.0-xは+0.0と等しくなりますが、-xは-0.0と等しくなります。 単項マイナスは、floatの符号を反転するだけです。
特別な関心事:
オペランドがNaNの場合、結果はNaNになります(NaNには符号がないことを思い出してください)。
Java Virtual Machineは、NaNを含むすべての入力の符号ビットを否定が反転する2019バージョンのIEEE 754 Standardのより強力な要件を採用していません。
オペランドが無限大の場合、結果は反対符号の無限大になります。
オペランドがゼロの場合、結果は反対符号のゼロになります。
剰余float
frem
frem = 114 (0x72)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもfloat型である必要があります。 値はオペランド・スタックからポップされます。 floatresultが計算され、オペランド・スタックにプッシュされます。
frem命令の結果は、Java Virtual Machine (§2.8)で端数処理ポリシーを選択したため、IEEE 754で定義された残りの操作の結果とは異なります。 IEEE 754剰余演算は、切り捨て除算ではなく端数処理除算からの剰余を計算するため、その動作は通常の整数剰余演算子の動作と似ていません。 かわりに、Java Virtual Machineでは、整数剰余命令iremおよびlremと同様の方法で動作するようにfremを定義し、丸めゼロの丸めポリシーを使用する暗黙の除算を使用します。これは、Cライブラリ関数fmodと比較できます。
frem命令の結果は、暗黙の除算の計算方法を除き、IEEE 754算術と一致する次のルールによって制御されます。
value1またはvalue2のいずれかがNaNの場合、結果はNaNになります。
value1もvalue2もNaNでない場合、結果の符号は配当の符号と等しくなります。
配当が無限大または除数がゼロまたは両方の場合、結果はNaNになります。
配当が有限で、除数が無限である場合、結果は配当と等しくなります。
配当がゼロで、除数が有限の場合、結果は配当と等しくなります。
オペランドが無限大、ゼロ、または NaNのいずれでもない残りの場合、浮動小数点の残り resultは配当 value1から、除数 value2は数学的な関係 result = value1 - (value2 * q)によって定義されます。qは、value1 / value2が負の場合にのみ負の整数で、value1 / value2が正の場合にのみ正の整数で、その大きさは、value1およびvalue2の真の数学的商の大きさを超えずに可能なかぎり大きくなります。
ゼロによる除算が発生する可能性はありますが、frem命令の評価では実行時例外はスローされません。 オーバーフロー、アンダーフロー、または精度の損失は発生しません。
IEEE 754残り操作は、ライブラリルーチン Math.IEEEremainderまたは StrictMath.IEEEremainderによって計算できます。
メソッドからfloatを返します
freturn
freturn = 174 (0xae)
...、 value →
[空]
現在のメソッドには、戻り型floatが必要です。 valueはfloat型である必要があります。 現在のメソッドがsynchronizedメソッドの場合、メソッドの起動時に入力または再入力されたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。 例外がスローされない場合、valueは現在のフレームのオペランドスタック(§2.6)からポップされ、呼び出し元のフレームのオペランドスタックにプッシュされます。 現在のメソッドのオペランド・スタック上のその他の値はすべて破棄されます。
インタプリタは、メソッドの起動元に制御を戻し、起動元のフレームを元に戻します。
Java Virtual Machineの実装で、§2.11.10で説明されている構造化ロックのルールが強制されない場合は、現在のメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、freturnはIllegalMonitorStateExceptionをスローします。 これは、たとえば、synchronizedメソッドにmonitorexit命令が含まれているが、メソッドが同期されているオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックのルールが適用され、現在のメソッドの呼出し中にそれらのルールの最初のルールに違反すると、freturnはIllegalMonitorStateExceptionをスローします。
floatをローカル変数に格納します
fstore
index
fstore = 56 (0x38)
...、 value →
...
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 オペランド・スタックの先頭にある値は、float型である必要があります。 オペランド・スタックからポップされ、indexのローカル変数の値がvalueに設定されます。
fstore opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
floatをローカル変数に格納します
fstore_<n>
fstore_0 = 67 (0x43)
fstore_1 = 68 (0x44)
fstore_2 = 69 (0x45)
fstore_3 = 70 (0x46)
...、 value →
...
<n>は、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 オペランド・スタックの先頭にある値は、float型である必要があります。 オペランド・スタックからポップされ、<n>のローカル変数の値がvalueに設定されます。
fstore_<n>の各命令は、<n>の索引を持つfstoreと同じですが、オペランド<n>が暗黙的に指定されている点が異なります。
floatを減算
fsub
fsub = 102 (0x66)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもfloat型である必要があります。 値はオペランド・スタックからポップされます。 float resultは、value1 - value2です。 resultは、オペランド・スタックにプッシュされます。
floatの減算では、a-bがa+(-b)と同じ結果を生成するのは常に同じです。 ただし、fsub命令の場合、xが+0.0の場合、0.0-xは+0.0と等しくなりますが、-xは-0.0と等しいため、ゼロからの減算は否定とは異なります。
Java Virtual Machineでは、段階的なアンダーフローのサポートが必要です。 オーバーフロー、アンダーフロー、または精度の損失が発生する可能性があるにもかかわらず、fsub命令の実行によって実行時例外がスローされることはありません。
オブジェクトからフィールドをフェッチ
getfield
indexbyte1
indexbyte2
getfield = 180 (0xb4)
...、 objectref →
..., value
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、フィールド(§5.1)へのシンボリック参照である必要があります。この参照では、フィールドの名前と記述子、およびフィールドが見つかるクラスのシンボリック参照が示されます。 参照フィールドは解決されます(§5.4.3.2)。
objectrefは、reference型である必要がありますが、配列型ではないため、オペランド・スタックからポップされます。 objectref内の参照フィールドの値がフェッチされ、オペランド・スタックにプッシュされます。
フィールドへのシンボリック参照の解決中に、フィールド解決に関するエラー(§5.4.3.2)をスローできます。
それ以外の場合、解決されたフィールドがstaticフィールドの場合、getfieldはIncompatibleClassChangeErrorをスローします。
それ以外の場合、objectrefがnullの場合、getfield命令はNullPointerExceptionをスローします。
getfield命令は、配列のlengthフィールドへのアクセスには使用できません。 かわりに、arraylength命令(§arraylength)が使用されます。
クラスからstaticフィールドを取得します
getstatic
indexbyte1
indexbyte2
getstatic = 178 (0xb2)
..., →
..., value
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、フィールド(§5.1)へのシンボリック参照である必要があります。この参照では、フィールドの名前と記述子、およびフィールドが見つかるクラスまたはインタフェースへのシンボリック参照が示されます。 参照フィールドは解決されます(§5.4.3.2)。
フィールドが正常に解決されると、解決されたフィールドを宣言したクラスまたはインタフェースは、そのクラスまたはインタフェースがまだ初期化されていない場合に初期化されます(§5.5)。
クラス・フィールドまたはインタフェース・フィールドの値がフェッチされ、オペランド・スタックにプッシュされます。
クラスまたはインタフェース・フィールドへのシンボリック参照の解決時に、フィールド解決に関する例外(§5.4.3.2)をスローできます。
それ以外の場合、解決されたフィールドがstatic (クラス)フィールドまたはインタフェース・フィールドでない場合、getstaticはIncompatibleClassChangeErrorをスローします。
それ以外の場合、このgetstatic命令の実行によって参照されるクラスまたはインタフェースの初期化が発生すると、getstaticは§5.5の説明に従ってErrorをスローすることがあります。
常に分岐
goto
branchbyte1
branchbyte2
goto = 167 (0xa7)
変更なし
符号なしバイトbranchbyte1およびbranchbyte2を使用して、符号付き16ビットbranchoffsetを構築します。ここで、branchoffsetは(branchbyte1 << 8) | branchbyte2です。 実行は、このgoto命令のopcodeのアドレスからそのオフセットで続行されます。 ターゲットアドレスは、この goto命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
ブランチは常に(ワイド・インデックス)
goto_w
branchbyte1
branchbyte2
branchbyte3
branchbyte4
goto_w = 200 (0xc8)
変更なし
符号なしバイトbranchbyte1、branchbyte2、branchbyte3およびbranchbyte4を使用して、符号付き32ビットbranchoffsetを構築します。ここで、branchoffsetは(branchbyte1 << 24) | (branchbyte2 << 16) | (branchbyte3 << 8) | branchbyte4です。 実行は、この goto_w命令のopcodeのアドレスからそのオフセットで続行されます。 ターゲットアドレスは、この goto_w命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
goto_w命令は4バイトの分岐オフセットを取りますが、ほかの要因はメソッドのサイズを65535バイトに制限します(§4.11)。 この制限は、Java Virtual Machineの将来のリリースで発生する可能性があります。
intをbyteに変換します。
i2b
i2b = 145 (0x91)
...、 value →
..., result
オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、byteに切り捨てられ、int結果に符号拡張されます。 resultは、オペランド・スタックにプッシュされます。
i2b命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われる可能性があります。 resultには、valueと同じ符号がないこともあります。
intをcharに変換します。
i2c
i2c = 146 (0x92)
...、 value →
..., result
オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、charに切り捨てられてから、int結果にゼロ拡張されます。 resultは、オペランド・スタックにプッシュされます。
i2c命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われる可能性があります。 result (常に正)には、valueと同じ符号がないこともあります。
intをdoubleに変換します。
i2d
i2d = 135 (0x87)
...、 value →
..., result
オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、double結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
i2d命令は、拡張プリミティブ変換(JLS§5.1.2)を実行します。 int型のすべての値はdouble型で正確に表現できるため、変換は正確です。
intをfloatに変換します。
i2f
i2f = 134 (0x86)
...、 value →
..., result
オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、最も近い丸めポリシー(§2.8)を使用してfloat結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
i2f命令は拡張プリミティブ変換(JLS§5.1.2)を実行しますが、float型の値には24個の符号ビットしかないため、精度が失われる可能性があります。
intをlongに変換します。
i2l
i2l = 133 (0x85)
...、 value →
..., result
オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、long結果に符号拡張されます。 resultは、オペランド・スタックにプッシュされます。
i2l命令は、拡張プリミティブ変換(JLS§5.1.2)を実行します。 int型のすべての値はlong型で正確に表現できるため、変換は正確です。
intをshortに変換します。
i2s
i2s = 147 (0x93)
...、 value →
..., result
オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、shortに切り捨てられ、int結果に符号拡張されます。 resultは、オペランド・スタックにプッシュされます。
i2s命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われる可能性があります。 resultには、valueと同じ符号がないこともあります。
intを追加します。
iadd
iadd = 96 (0x60)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int resultは、value1 + value2です。 resultは、オペランド・スタックにプッシュされます。
結果は、真の数学的結果の32ビットの下位ビットであり、int型の値として表される、十分に幅の広い2の補完形式になります。 オーバーフローが発生した場合、結果の符号は、2つの値の数学的合計の符号と同じでない可能性があります。
オーバーフローが発生する可能性があるにもかかわらず、iadd命令を実行すると、実行時例外がスローされることはありません。
配列からのintのロード
iaload
iaload = 46 (0x2e)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがint型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネント内のintvalueが取得され、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、ialoadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、iaload命令はArrayIndexOutOfBoundsExceptionをスローします。
ビット単位AND int
および
iand = 126 (0x7e)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 オペランド・スタックからポップされます。 int結果は、value1およびvalue2のビット単位AND (結合)を使用して計算されます。 resultは、オペランド・スタックにプッシュされます。
int配列に格納
iastore社
iastore = 79 (0x4f)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがint型である配列を参照する必要があります。 indexとvalueはどちらもint型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。 int valueは、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、iastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、iastore命令はArrayIndexOutOfBoundsExceptionをスローします。
int定数のプッシュ
iconst_<i>
iconst_m1 = 2 (0x2)
iconst_0 = 3 (0x3)
iconst_1 = 4 (0x4)
iconst_2 = 5 (0x5)
iconst_3 = 6 (0x6)
iconst_4 = 7 (0x7)
iconst_5 = 8 (0x8)
... →
...、<i>
int定数<i>(-1、0、1、2、3、4または5)をオペランド・スタックにプッシュします。
この命令の各ファミリは、<i>の各値に対するbipush <i>と同等ですが、オペランド<i>が暗黙的であることを除きます。
intの除算
idiv
idiv = 108 (0x6c)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int resultは、Javaプログラミング言語式value1 / value2 (JLS§15.17.2)の値です。 resultは、オペランド・スタックにプッシュされます。
int除算は0に丸められます。つまり、n/dのint値に対して生成される商はint値qで、その大きさは|d ⋅ q| ≤ |n|を満たしている間はできるだけ大きくなります。 また、qは、|n| ≥ |d|とnとdが同じ符号を持つ場合に正ですが、|n| ≥ |d|とnとdに逆の符号がある場合、負の値になります。
このルールを満たさない特殊なケースが1つあります。つまり、int型で可能な最大の大きさの負の整数で、除数が-1の場合、オーバーフローが発生し、結果は除算と等しくなります。 オーバーフローにもかかわらず、この場合は例外はスローされません。
int除数の値が0の場合、idivはArithmeticExceptionをスローします。
reference比較が成功した場合のブランチ
if_acmp<cond>
branchbyte1
branchbyte2
if_acmpeq = 165 (0xa5)
if_acmpne = 166 (0xa6)
...、 value1、 value2 →
...
value1とvalue2はどちらもreference型である必要があります。 これらはどちらもオペランド・スタックからポップされ、比較されます。 比較の結果は次のとおりです。
if_acmpeqは、value1 = value2の場合にのみ成功します
if_acmpneは、value1 ≠ value2の場合にのみ成功します。
比較が成功すると、符号なしのbranchbyte1およびbranchbyte2を使用して、符号付き16ビット・オフセットを構築し、オフセットは(branchbyte1 << 8) | branchbyte2と計算されます。 次に、この if_acmp<cond>命令のopcodeのアドレスから、そのオフセットで実行します。 ターゲットアドレスは、この if_acmp<cond>命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
それ以外の場合、比較が失敗すると、この if_acmp<cond>命令のあとの命令のアドレスで実行が続行されます。
int比較が成功した場合のブランチ
if_icmp<cond>
branchbyte1
branchbyte2
if_icmpeq = 159 (0x9f)
if_icmpne = 160 (0xa0)
if_icmplt = 161 (0xa1)
if_icmpge = 162 (0xa2)
if_icmpgt = 163 (0xa3)
if_icmple = 164 (0xa4)
...、 value1、 value2 →
...
value1とvalue2はどちらもint型である必要があります。 これらはどちらもオペランド・スタックからポップされ、比較されます。 すべての比較が署名されています。 比較の結果は次のとおりです。
if_icmpeqは、value1 = value2の場合にのみ成功します
if_icmpneは、value1 ≠ value2の場合にのみ成功します。
if_icmpltは、value1 < value2の場合にのみ成功します。
if_icmpleは、value1 ≤ value2の場合にのみ成功します。
if_icmpgtは、value1 > value2の場合にのみ成功します
if_icmpgeは、value1 ≥ value2の場合にのみ成功します。
比較が成功すると、符号なしのbranchbyte1およびbranchbyte2を使用して、符号付き16ビット・オフセットを構築し、オフセットは(branchbyte1 << 8) | branchbyte2と計算されます。 次に、この if_icmp<cond>命令のopcodeのアドレスから、そのオフセットで実行します。 ターゲットアドレスは、この if_icmp<cond>命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
それ以外の場合は、この if_icmp<cond>命令に続く命令のアドレスで実行が続行されます。
intとゼロの比較が成功した場合のブランチ
if<cond>
branchbyte1
branchbyte2
ifeq = 153 (0x99)
ifne = 154 (0x9a)
iflt = 155 (0x9b)
ifge = 156 (0x9c)
ifgt = 157 (0x9d)
ifle = 158 (0x9e)
...、 value →
...
valueはint型である必要があります。 オペランド・スタックからポップされ、ゼロと比較されます。 すべての比較が署名されています。 比較の結果は次のとおりです。
value = 0の場合のみ、ifeqが成功する
ifneは、value ≠ 0の場合にのみ成功します。
valueが0より小さい場合にのみ、ifltが成功する
ifleは、value ≤ 0の場合にのみ成功します。
ifgtは、value > 0の場合にのみ成功します
ifgeは、value ≥ 0の場合にのみ成功します。
比較が成功すると、符号なしのbranchbyte1およびbranchbyte2を使用して、符号付き16ビット・オフセットを構築し、オフセットは(branchbyte1 << 8) | branchbyte2と計算されます。 その後、このif<cond>命令のopcodeのアドレスから、そのオフセットで実行されます。 ターゲットアドレスは、この if<cond>命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
それ以外の場合は、この if<cond>命令のあとの命令のアドレスで実行が続行されます。
referenceがnullでない場合にブランチ
ifnonnull
branchbyte1
branchbyte2
ifnonnull = 199 (0xc7)
...、 value →
...
valueはreference型である必要があります。 オペランド・スタックからポップされます。 valueがnullでない場合は、符号なしbranchbyte1およびbranchbyte2を使用して、符号付き16ビット・オフセットを構築します。ここで、オフセットは(branchbyte1 << 8) | branchbyte2として計算されます。 次に、このifnonnull命令のopcodeのアドレスからのそのオフセットで実行されます。 ターゲット・アドレスは、このifnonnull命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
それ以外の場合は、このifnonnull命令に続く命令のアドレスで実行が続行されます。
referenceがnullの場合のブランチ
ifnull
branchbyte1
branchbyte2
ifnull = 198 (0xc6)
...、 value →
...
valueは、reference型である必要があります。 オペランド・スタックからポップされます。 valueがnullの場合、符号なしbranchbyte1およびbranchbyte2を使用して、符号付き16ビット・オフセットを構築します。ここで、オフセットは(branchbyte1 << 8) | branchbyte2と計算されます。 その後、このifnull命令のopcodeのアドレスからそのオフセットで実行されます。 ターゲット・アドレスは、このifnull命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
それ以外の場合は、このifnull命令に続く命令のアドレスで実行が続行されます。
ローカル変数を定数で増分
iinc
index
const
iinc = 132 (0x84)
変更なし
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 constは即時の符号付きバイトです。 indexのローカル変数には、intが含まれている必要があります。 値constは、最初にintに符号拡張され、次にindexのローカル変数がその量だけ増分されます。
iinc opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスし、2バイトの即時の符号付き値で増分できます。
ローカル変数からintをロードします
iload
index
iload = 21 (0x15)
... →
..., value
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 indexのローカル変数には、intが含まれている必要があります。 indexのローカル変数のvalueは、オペランド・スタックにプッシュされます。
iload opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
ローカル変数からintをロードします
iload_<n>
iload_0 = 26 (0x1a)
iload_1 = 27 (0x1b)
iload_2 = 28 (0x1c)
iload_3 = 29 (0x1d)
... →
..., value
<n>は、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 <n>のローカル変数には、intが含まれている必要があります。 <n>のローカル変数の値がオペランド・スタックにプッシュされます。
iload_<n>の各命令は、<n>のindexを持つiloadと同じですが、オペランド<n>が暗黙的に指定されている点が異なります。
intの乗算
imul
imul = 104 (0x68)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int resultは、value1 * value2です。 resultは、オペランド・スタックにプッシュされます。
結果は、真の数学的結果の32ビットの下位ビットであり、int型の値として表される、十分に幅の広い2の補完形式になります。 オーバーフローが発生した場合、結果の符号は、2つの値の数学的乗算の符号と同じでない可能性があります。
オーバーフローが発生する可能性があるにもかかわらず、imul命令を実行すると、実行時例外がスローされることはありません。
否定int
ineg
ineg = 116 (0x74)
...、 value →
..., result
valueはint型である必要があります。 オペランド・スタックからポップされます。 int resultは、value、-valueの算術否定です。 resultは、オペランド・スタックにプッシュされます。
int値の場合、否定はゼロからの減算と同じです。 Java Virtual Machineでは整数に2の補数表現が使用され、2の補数値の範囲は対称ではないため、負の最大intを否定すると、同じ最大負数になります。 オーバーフローが発生したにもかかわらず、例外はスローされません。
すべてのint値xについて、-xは(~x)+1と等しくなります。
オブジェクトが特定のタイプかどうかの判断
instanceof
indexbyte1
indexbyte2
instanceof = 193 (0xc1)
...、 objectref →
..., result
objectrefは、reference型である必要がありますが、オペランド・スタックからポップされます。 符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、クラス、配列またはインタフェース・タイプへのシンボリック参照である必要があります。
objectrefがnullの場合、instanceof命令はintresultをオペランド・スタックにプッシュします。
それ以外の場合は、名前付きクラス、配列、またはインタフェース型が解決されます(§5.4.3.1)。 objectrefが解決されたクラス、配列またはインタフェース・タイプによって指定された型の値である場合、instanceof命令はintresultをオペランド・スタックにプッシュし、それ以外の場合はintresultを0にプッシュします。
objectrefが解決されたクラス、配列またはインタフェース・タイプで指定される型の値かどうかは、§checkcastに指定されたルールに従って決定されます。
クラス、配列またはインタフェース型へのシンボリック参照の解決中に、§5.4.3.1に記載されている例外をスローできます。
instanceof命令は、checkcast命令(§checkcast)と非常によく似ています。 nullの処理、テストが失敗した場合の動作(checkcastは例外をスローし、instanceofは結果コードをプッシュ)、オペランド・スタックへの影響は異なります。
動的に計算されたコール・サイトを呼び出す
invokedynamic
indexbyte1
indexbyte2
0
0
invokedynamic = 186 (0xba)
...、 [arg1、 [arg2 ...]] →
...
まず、符号なしindexbyte1およびindexbyte2を使用して、現在のクラスの実行時定数プール(§2.6)に索引を構築します。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、動的に計算されるコール・サイト(§5.1)へのシンボリック参照である必要があります。 3番目と4番目のオペランドバイトの値は、常に0である必要があります。
シンボリック参照は、この特定のinvokedynamic命令§5.4.3.6で解決され、java.lang.invoke.CallSiteのインスタンスに対するreferenceが取得されます。 java.lang.invoke.CallSiteのインスタンスは、この特定のinvokedynamic命令にバインドされているとみなされます。
java.lang.invoke.CallSiteのインスタンスは、ターゲット・メソッド・ハンドルを示します。 オペランド・スタックからnargs引数値がポップされ、ターゲット・メソッド・ハンドルが呼び出されます。 この呼出しは、シンボリック参照Rへの実行時定数プール索引を示すinvokevirtual命令を実行した場合のように行われます。ここでは:
Rは、クラスのメソッドへのシンボリック参照です。
メソッドが見つかるクラスへのシンボリック参照の場合、Rはjava.lang.invoke.MethodHandleを指定します。
メソッドの名前として、RはinvokeExactを指定します。
メソッドの記述子に対して、Rは動的に計算されるコール・サイトのメソッド記述子を指定します。
次の項目がオペランドスタックに順番にプッシュされたかのように表示されます。
ターゲット・メソッド・ハンドルに対するreference。
nargs引数値。この値の数、型および順序は、動的に計算されるコール・サイトのメソッド記述子と一致している必要があります。
動的に計算されたコールサイトへのシンボリック参照の解決中に、動的に計算されたコールサイト解決に関する例外をスローできます。
動的に計算されたコール・サイトへのシンボリック参照を解決できる場合、java.lang.invoke.CallSiteのインスタンスに対するnull reference以外のnullがinvokedynamic命令にバインドされていることを意味します。 したがって、java.lang.invoke.CallSiteのインスタンスによって示されるターゲット・メソッド・ハンドルは、nullではありません。
同様に、解決が成功すると、シンボリック参照のメソッド記述子は、ターゲット・メソッド・ハンドルの型記述子と意味的に等しくなります。
これらの不変条件は、java.lang.invoke.CallSiteのインスタンスにバインドされたinvokedynamic命令がNullPointerExceptionまたはjava.lang.invoke.WrongMethodTypeExceptionをスローしないことを意味します。
インタフェース・メソッドの起動
invokeinterface
indexbyte1
indexbyte2
count
0
invokeinterface = 185 (0xb9)
...、 objectref、 [arg1、 [arg2 ...]] →
...
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、インタフェース・メソッド(§5.1)の名前と記述子(§4.3.3)およびインタフェース・メソッドが見つかるインタフェースへのシンボリック参照を示す、インタフェース・メソッド(§5.1)へのシンボリック参照である必要があります。 指定されたインタフェース・メソッドが解決されます(§5.4.3.4)。
解決されたインタフェース・メソッドは、インスタンス初期化メソッド、クラスまたはインタフェース初期化メソッド(§2.9.1、§2.9.2)であってはなりません。
countオペランドは、ゼロにできない符号なしバイトです。 objectrefはreference型である必要があり、オペランド・スタックではnargs引数値の後に続ける必要があります。この場合、値の数、型および順序は、解決されたインタフェース・メソッドの記述子と一致している必要があります。 4番目のオペランド・バイトの値は、常にゼロである必要があります。
Cをobjectrefのクラスにします。 Cおよび解決済メソッド(§5.4.6)に関してメソッドが選択されます。 これは呼び出されるメソッドです。
呼び出されるメソッドがsynchronizedの場合、objectrefに関連付けられたモニターは、現在のスレッドでmonitorenter命令(§monitorenter)を実行したかのように入力または再入力されます。
呼び出されるメソッドがnativeでない場合は、オペランド・スタックからnargs引数値およびobjectrefがポップされます。 呼び出されるメソッドのJava Virtual Machineスタックに新しいフレームが作成されます。 objectrefおよび引数値は、ローカル変数0にobjectref、ローカル変数1にarg1 (または、arg1がlongまたはdoubleタイプ、ローカル変数1および2タイプなど)を使用して、新しいフレームのローカル変数の値を連続して作成します。 その後、新しいフレームがカレントになり、Java Virtual Machineのpcが、呼び出されるメソッドの最初の命令のopcodeに設定されます。 実行は、メソッドの最初の指示に従って続行されます。
呼び出されるメソッドがnativeで、それを実装するプラットフォーム依存のコードがまだJava Virtual Machineにバインドされていない場合(§5.6)、それが実行されます。 nargs引数値およびobjectrefは、オペランド・スタックからポップされ、メソッドを実装するコードにパラメータとして渡されます。 パラメータが渡され、コードは実装に依存した方法で呼び出されます。 プラットフォームに依存するコードが返す場合:
nativeメソッドがsynchronizedの場合、objectrefに関連付けられているモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。
nativeメソッドが値を返す場合、プラットフォーム依存コードの戻り値は、実装に依存した方法でnativeメソッドの戻り型に変換され、オペランド・スタックにプッシュされます。
インタフェース・メソッドへのシンボリック参照の解決中に、インタフェース・メソッド解決に関する例外(§5.4.3.4)をスローできます。
それ以外の場合、解決されたメソッドがstaticの場合、invokeinterface命令はIncompatibleClassChangeErrorをスローします。
invokeinterfaceは、ネストメイト・インタフェースを含むインタフェースで宣言されたprivateメソッドを参照できます。
それ以外の場合、objectrefがnullの場合、invokeinterface命令はNullPointerExceptionをスローします。
それ以外の場合、objectrefのクラスが解決されたインタフェースを実装しない場合、invokeinterfaceはIncompatibleClassChangeErrorをスローします。
それ以外の場合、選択したメソッドがpublicでもprivateでもない場合、invokeinterfaceはIllegalAccessErrorをスローします。
それ以外の場合、選択したメソッドがabstractの場合、invokeinterfaceはAbstractMethodErrorをスローします。
それ以外の場合、選択したメソッドがnativeで、そのメソッドを実装するコードをバインドできない場合、invokeinterfaceはUnsatisfiedLinkErrorをスローします。
それ以外の場合、メソッドが選択されておらず、解決されたメソッドの名前および記述子と一致し、abstractではないCの最大固有のスーパーインタフェース・メソッドが複数存在する場合、invokeinterfaceはIncompatibleClassChangeErrorをスローします。
それ以外の場合、メソッドが選択されておらず、解決されたメソッドの名前および記述子と一致し、abstractではないCの最大固有スーパーインタフェース・メソッドがない場合、invokeinterfaceはAbstractMethodErrorをスローします。
invokeinterface命令のcountオペランドは、引数値の数のメジャーを記録します。この場合、long型の引数値またはdouble型の引数値は、count値に2つの単位を寄与し、他の型の引数は1つの単位を寄与します。 この情報は、選択したメソッドの記述子からも導出できます。 冗長性は履歴です。
4番目のオペランド・バイトは、実行時にinvokeinterface命令を特殊な擬似命令に置き換える、OracleのJava Virtual Machine実装の一部で使用される追加のオペランド用の領域を予約するために存在します。 下位互換性のために保持する必要があります。
nargs引数値およびobjectrefは、最初のnargs+1ローカル変数を持つ1対1ではありません。 long型およびdouble型の引数値は、連続する2つのローカル変数に格納する必要があるため、nargs引数値を呼び出されたメソッドに渡すには、nargsを超えるローカル変数が必要になる場合があります。
選択ロジックにより、スーパーインタフェースで宣言されたabstract以外のメソッドを選択できます。 インタフェースのメソッドは、クラス階層内に一致するメソッドがない場合にのみ考慮されます。 スーパーインタフェース階層に2つの非abstractメソッドがあり、どちらも他方より限定的でない場合、エラーが発生します。あいまいさを解消しようという試みはありません(たとえば、1つは参照されるメソッドで、もう1つは無関係ですが、参照されるメソッドを好まない)。 一方、abstractメソッドが多数あり、abstract以外のメソッドが1つのみの場合は、abstractメソッドがより具体的でないかぎり、abstract以外のメソッドが選択されます。
インスタンス・メソッドを呼び出します。現在のクラスとそのスーパータイプのインスタンス初期化メソッドとメソッドを直接呼び出します。
invokespecial
indexbyte1
indexbyte2
invokespecial = 183 (0xb7)
...、 objectref、 [arg1、 [arg2 ...]] →
...
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、メソッドまたはインタフェース・メソッド(§5.1)へのシンボリック参照である必要があり、メソッドまたはインタフェース・メソッドの名前と記述子(§4.3.3)、およびメソッドまたはインタフェース・メソッドが見つかるクラスまたはインタフェースへのシンボリック参照が与えられます。 指定されたメソッドが解決されます(§5.4.3.3、§5.4.3.4)。
次のすべてに当てはまる場合は、Cを現在のクラスの直接スーパークラスにします。
それ以外の場合は、Cをシンボリック参照によって指定されたクラスまたはインタフェースにしてください。
呼び出される実際のメソッドは、次の参照プロシージャによって選択されます。
Cに、解決済メソッドと同じ名前および記述子を持つインスタンス・メソッドの宣言が含まれている場合は、呼び出されるメソッドです。
それ以外の場合、Cがクラスでスーパークラスがある場合、解決されたメソッドと同じ名前および記述子を持つインスタンス・メソッドの宣言を検索します。Cの直接スーパークラスから開始し、一致が見つかるかそれ以上のスーパークラスが存在しなくなるまで、そのクラスの直接スーパークラスを継続して実行します。 一致が見つかった場合は、呼び出されるメソッドです。
それ以外の場合、Cがインタフェースで、クラスObjectに解決済メソッドと同じ名前および記述子を持つpublicインスタンス・メソッドの宣言が含まれていると、呼び出されるメソッドになります。
それ以外の場合、Cのスーパーインタフェースに、解決されたメソッドの名前および記述子と一致し、abstractでない最大固有メソッド(§5.4.3.3)が1つしかないと、呼び出されるメソッドになります。
objectrefはreference型である必要があり、オペランド・スタックではnargs引数値が続く必要があります。この場合、値の数、型および順序は、選択したインスタンス・メソッドの記述子と一致している必要があります。
メソッドがsynchronizedの場合、objectrefに関連付けられたモニターは、現在のスレッドでmonitorenter命令(§monitorenter)を実行したかのように入力または再入力されます。
メソッドがnativeでない場合は、オペランド・スタックからnargs引数値およびobjectrefがポップされます。 呼び出されるメソッドのJava Virtual Machineスタックに新しいフレームが作成されます。 objectrefおよび引数値は、ローカル変数0にobjectref、ローカル変数1にarg1 (または、arg1がlongまたはdoubleタイプ、ローカル変数1および2タイプなど)を使用して、新しいフレームのローカル変数の値を連続して作成します。 その後、新しいフレームがカレントになり、Java Virtual Machineのpcが、呼び出されるメソッドの最初の命令のopcodeに設定されます。 実行は、メソッドの最初の指示に従って続行されます。
メソッドがnativeで、そのメソッドを実装するプラットフォーム依存のコードがまだJava Virtual Machineにバインドされていない場合(§5.6)、これが実行されます。 nargs引数値およびobjectrefは、オペランド・スタックからポップされ、メソッドを実装するコードにパラメータとして渡されます。 パラメータが渡され、コードは実装に依存した方法で呼び出されます。 プラットフォーム依存コードが返されると、次の処理が実行されます。
nativeメソッドがsynchronizedの場合、objectrefに関連付けられているモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。
nativeメソッドが値を返す場合、プラットフォーム依存コードの戻り値は、実装に依存した方法でnativeメソッドの戻り型に変換され、オペランド・スタックにプッシュされます。
メソッドへのシンボリック参照の解決中に、メソッド解決に関する例外(§5.4.3.3)をスローできます。
それ以外の場合、解決されたメソッドがインスタンス初期化メソッドで、そのメソッドが宣言されているクラスが命令によって象徴的に参照されているクラスでないと、NoSuchMethodErrorがスローされます。
それ以外の場合、解決されたメソッドがクラス(static)メソッドの場合、invokespecial命令はIncompatibleClassChangeErrorをスローします。
それ以外の場合、objectrefがnullの場合、invokespecial命令はNullPointerExceptionをスローします。
それ以外の場合、ルックアップ・プロシージャのステップ1、ステップ2またはステップ3でabstractメソッドが選択されると、invokespecialによってAbstractMethodErrorがスローされます。
それ以外の場合、ルックアップ・プロシージャのステップ1、ステップ2またはステップ3でnativeメソッドが選択され、そのメソッドを実装するコードをバインドできない場合、invokespecialはUnsatisfiedLinkErrorをスローします。
それ以外の場合、解決されたメソッドの名前および記述子と一致し、abstractではないCの最大固有のスーパーインタフェース・メソッドが複数あるとルックアップ・プロシージャのステップ4で判断された場合、invokespecialはIncompatibleClassChangeErrorをスローします。
それ以外の場合、解決されたメソッドの名前および記述子と一致し、abstractではないCの最大固有スーパーインタフェース・メソッドがないとルックアップ・プロシージャのステップ4が判断した場合、invokespecialはAbstractMethodErrorをスローします。
invokespecial命令とinvokevirtual命令(§invokevirtual)の違いは、invokevirtualがオブジェクトのクラスに基づいてメソッドを呼び出すことです。 invokespecial命令は、インスタンス初期化メソッド(§2.9.1)および現在のクラスとそのスーパータイプのメソッドを直接呼び出すために使用されます。
invokespecial命令は、JDKリリース1.0.2より前のinvokenonvirtualという名前でした。
nargs引数値およびobjectrefは、最初のnargs+1ローカル変数を持つ1対1ではありません。 long型およびdouble型の引数値は、連続する2つのローカル変数に格納する必要があるため、nargs引数値を呼び出されたメソッドに渡すには、nargsを超えるローカル変数が必要になる場合があります。
invokespecial命令は、直接スーパーインタフェースまたはスーパークラスを介して参照される、abstract以外のインタフェース・メソッドの呼出しを処理します。 このような場合、選択のルールは、invokeinterfaceのルールと基本的に同じです(検索が別のクラスから開始する場合を除く)。
クラス(static)メソッドの起動
invokestatic
indexbyte1
indexbyte2
invokestatic = 184 (0xb8)
...、 [arg1、 [arg2 ...]] →
...
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、メソッドまたはインタフェース・メソッド(§5.1)へのシンボリック参照である必要があり、メソッドまたはインタフェース・メソッドの名前と記述子(§4.3.3)、およびメソッドまたはインタフェース・メソッドが見つかるクラスまたはインタフェースへのシンボリック参照が与えられます。 指定されたメソッドが解決されます(§5.4.3.3、§5.4.3.4)。
解決されたメソッドは、インスタンス初期化メソッド、クラスまたはインタフェース初期化メソッド(§2.9.1、§2.9.2)であってはなりません。
解決されたメソッドはstaticである必要があり、abstractにはできません。
メソッドが正常に解決されると、解決されたメソッドを宣言したクラスまたはインタフェースは、そのクラスまたはインタフェースがまだ初期化されていない場合に初期化されます(§5.5)。
オペランド・スタックには、nargs引数値が含まれている必要があります。この場合、値の数、型および順序は、解決されたメソッドの記述子と一致している必要があります。
メソッドがsynchronizedの場合、解決されたClassオブジェクトに関連付けられたモニターは、現在のスレッドでmonitorenter命令(§monitorenter)を実行したかのように入力または再入力されます。
メソッドがnativeでない場合、nargs引数値はオペランド・スタックからポップされます。 呼び出されるメソッドのJava Virtual Machineスタックに新しいフレームが作成されます。 nargs引数値は、ローカル変数0にarg1 (または、arg1がlongまたはdouble型で、ローカル変数0および1)などを使用して、新しいフレームのローカル変数の値を連続して設定します。 その後、新しいフレームがカレントになり、Java Virtual Machineのpcが、呼び出されるメソッドの最初の命令のopcodeに設定されます。 実行は、メソッドの最初の指示に従って続行されます。
メソッドがnativeで、そのメソッドを実装するプラットフォーム依存のコードがまだJava Virtual Machineにバインドされていない場合(§5.6)、これが実行されます。 nargs引数値は、オペランド・スタックからポップされ、メソッドを実装するコードにパラメータとして渡されます。 パラメータが渡され、コードは実装に依存した方法で呼び出されます。 プラットフォーム依存コードが返されると、次の処理が実行されます。
nativeメソッドがsynchronizedの場合、解決されたClassオブジェクトに関連付けられたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。
nativeメソッドが値を返す場合、プラットフォーム依存コードの戻り値は、実装に依存した方法でnativeメソッドの戻り型に変換され、オペランド・スタックにプッシュされます。
メソッドへのシンボリック参照の解決中に、メソッド解決に関する例外(§5.4.3.3)をスローできます。
それ以外の場合、解決されたメソッドがインスタンス・メソッドの場合、invokestatic命令はIncompatibleClassChangeErrorをスローします。
そうでない場合、このinvokestatic命令の実行によって参照されるクラスまたはインタフェースの初期化が発生した場合、invokestaticは§5.5の説明に従ってErrorをスローすることがあります。
それ以外の場合、解決されたメソッドがnativeで、そのメソッドを実装するコードをバインドできない場合、invokestaticはUnsatisfiedLinkErrorをスローします。
nargs引数値は、最初のnargsローカル変数を持つ1対1ではありません。 long型およびdouble型の引数値は、連続する2つのローカル変数に格納する必要があるため、nargs引数値を呼び出されたメソッドに渡すには、nargsを超えるローカル変数が必要になる場合があります。
インスタンス・メソッドの起動、クラスに基づくディスパッチ
invokevirtual
indexbyte1
indexbyte2
invokevirtual = 182 (0xb6)
...、 objectref、 [arg1、 [arg2 ...]] →
...
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、メソッドの名前と記述子(§4.3.3)およびメソッドが見つかるクラスのシンボリック参照を示すメソッド(§5.1)へのシンボリック参照である必要があります。 指定されたメソッドが解決されます(§5.4.3.3)。
解決されたメソッドがシグネチャ多型でない場合(§2.9.3)は、invokevirtual命令は次のように進みます。
Cをobjectrefのクラスにします。 Cおよび解決済メソッド(§5.4.6)に関してメソッドが選択されます。 これは呼び出されるメソッドです。
オペランド・スタックでは、objectrefの後にnargs引数値を指定する必要があります。ここで、値の数、タイプおよび順序は、選択したインスタンス・メソッドの記述子と一致している必要があります。
呼び出されるメソッドがsynchronizedの場合、objectrefに関連付けられたモニターは、現在のスレッドでmonitorenter命令(§monitorenter)を実行したかのように入力または再入力されます。
呼び出されるメソッドがnativeでない場合は、オペランド・スタックからnargs引数値およびobjectrefがポップされます。 呼び出されるメソッドのJava Virtual Machineスタックに新しいフレームが作成されます。 objectrefおよび引数値は、ローカル変数0にobjectref、ローカル変数1にarg1 (または、arg1がlongまたはdoubleタイプ、ローカル変数1および2タイプなど)を使用して、新しいフレームのローカル変数の値を連続して作成します。 その後、新しいフレームがカレントになり、Java Virtual Machineのpcが、呼び出されるメソッドの最初の命令のopcodeに設定されます。 実行は、メソッドの最初の指示に従って続行されます。
呼び出されるメソッドがnativeで、それを実装するプラットフォーム依存のコードがまだJava Virtual Machineにバインドされていない場合(§5.6)。 nargs引数値およびobjectrefは、オペランド・スタックからポップされ、メソッドを実装するコードにパラメータとして渡されます。 パラメータが渡され、コードは実装に依存した方法で呼び出されます。 プラットフォーム依存コードが返されると、次の処理が実行されます。
nativeメソッドがsynchronizedの場合、objectrefに関連付けられているモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。
nativeメソッドが値を返す場合、プラットフォーム依存コードの戻り値は、実装に依存した方法でnativeメソッドの戻り型に変換され、オペランド・スタックにプッシュされます。
解決されたメソッドがシグネチャ多相(§2.9.3)であり、java.lang.invoke.MethodHandleクラスで宣言されている場合、invokevirtual命令は次のように進みます。ここで、Dは命令によって象徴的に参照されるメソッドの記述子です。
まず、java.lang.invoke.MethodTypeのインスタンスに対するreferenceは、Dと同じパラメータおよび戻り型を持つメソッド型(§5.4.3.5)へのシンボリック参照を解決することによって得られるかのように取得されます。
指定されたメソッドがinvokeExactの場合、java.lang.invoke.MethodTypeのインスタンスは、受信側メソッド・ハンドルobjectrefの型記述子と意味的に等しくなる必要があります。 呼び出されるメソッド・ハンドルはobjectrefです。
指定されたメソッドがinvokeで、java.lang.invoke.MethodTypeのインスタンスが受信メソッド・ハンドルobjectrefの型記述子と意味的に等しい場合、呼び出されるメソッド・ハンドルはobjectrefになります。
指定されたメソッドがinvokeで、java.lang.invoke.MethodTypeのインスタンスが受信メソッド・ハンドルobjectrefの型記述子と意味的に等しくない場合、Java Virtual Machineは、java.lang.invoke.MethodHandleのasTypeメソッドを呼び出して、正確に呼出し可能なメソッド・ハンドルmを取得する場合と同様に、受信メソッド・ハンドルの型記述子を調整しようとします。 呼び出されるメソッド・ハンドルはmです。
オペランド・スタックでは、objectrefの後にnargs引数値を指定する必要があります。この場合、値の数、型および順序は、呼び出されるメソッド・ハンドルの型記述子と一致している必要があります。 (この型記述子は、§5.4.3.5で指定されているように、呼び出されるメソッド・ハンドルの種類に適したメソッド記述子に対応しています。)
次に、呼び出されるメソッド・ハンドルがバイトコード動作を持つ場合、Java Virtual Machineはメソッド・ハンドルの種類に関連付けられたバイトコード動作を実行するかのようにメソッド・ハンドルを呼び出します。 種類が5 (REF_invokeVirtual)、6 (REF_invokeStatic)、7 (REF_invokeSpecial)、8 (REF_newInvokeSpecial)または9 (REF_invokeInterface)の場合、フレームが作成され、バイトコード動作の実行中に現在のフレームになります。ただし、このフレームは表示されず、バイトコード動作によって呼び出されたメソッドが(通常または突然)完了すると、呼出し元のフレームは、このinvokevirtual命令を含むメソッドのフレームとみなされます。
それ以外の場合、呼び出されるメソッド・ハンドルにバイトコード動作がない場合、Java Virtual Machineは実装に依存した方法でそれを呼び出します。
解決されたメソッドがシグネチャ多相であり、java.lang.invoke.VarHandleクラスで宣言されている場合、invokevirtual命令は次のように進みます。ここで、NおよびDは、命令によって象徴的に参照されるメソッドの名前および記述子です。
まず、java.lang.invoke.VarHandle.AccessModeのインスタンスに対するreferenceは、Nを示すString引数を使用してjava.lang.invoke.VarHandle.AccessModeのvalueFromMethodNameメソッドを呼び出すことによって取得されます。
次に、java.lang.invoke.MethodTypeのインスタンスに対するreferenceは、インスタンスobjectrefでjava.lang.invoke.VarHandleのaccessModeTypeメソッドを呼び出し、引数としてjava.lang.invoke.VarHandle.AccessModeのインスタンスを使用して取得します。
第3に、java.lang.invoke.MethodHandleのインスタンスに対するreferenceは、最初の引数としてjava.lang.invoke.VarHandle.AccessModeのインスタンス、2番目の引数としてjava.lang.invoke.MethodTypeのインスタンスを使用して、java.lang.invoke.MethodHandlesのvarHandleExactInvokerメソッドを呼び出すことによって取得されます。 結果のインスタンスは、実行者メソッド・ハンドルと呼ばれます。
最後に、nargs引数値およびobjectrefがオペランド・スタックからポップされ、実行者メソッド・ハンドルが呼び出されます。 この呼出しは、シンボリック参照Rへの実行時定数プール索引を示すinvokevirtual命令を実行した場合のように行われます。ここでは:
Rは、クラスのメソッドへのシンボリック参照です。
メソッドが見つかるクラスへのシンボリック参照の場合、Rはjava.lang.invoke.MethodHandleを指定します。
メソッドの名前として、Rはinvokeを指定します。
メソッドの記述子に対して、RはDの戻り記述子によって示される戻り型を指定し、java.lang.invoke.VarHandleの最初のパラメータ型と、Dのパラメータ記述子(ある場合)によって示されるパラメータ型(ある場合)を指定します。
次の項目がオペランドスタックに順番にプッシュされたかのように表示されます。
java.lang.invoke.MethodHandleのインスタンスに対するreference(実行者メソッド・ハンドル)。
objectref。
nargs引数値。値の数、型および順序は、実行者メソッド・ハンドルの型記述子と一致している必要があります。
メソッドへのシンボリック参照の解決中に、メソッド解決に関する例外(§5.4.3.3)をスローできます。
それ以外の場合、解決されたメソッドがクラス(static)メソッドの場合、invokevirtual命令はIncompatibleClassChangeErrorをスローします。
それ以外の場合、解決されたメソッドがシグネチャ多相であり、java.lang.invoke.MethodHandleクラスで宣言されている場合、メソッドへのシンボリック参照のディスクリプタから導出されたメソッド・タイプの解決時に、メソッド・タイプの解決に関する例外(§5.4.3.5)をスローできます。
それ以外の場合、解決されたメソッドがシグネチャ多相であり、java.lang.invoke.VarHandleクラスで宣言されている場合は、呼出し元メソッド・ハンドルの呼出しから発生する可能性のあるリンク例外をスローできます。 valueFromMethodName、accessModeTypeおよびvarHandleExactInvokerメソッドの呼出しからリンク例外はスローされません。
それ以外の場合、objectrefがnullの場合、invokevirtual命令はNullPointerExceptionをスローします。
それ以外の場合、解決されたメソッドがシグネチャ多相でない場合:
選択したメソッドがabstractの場合、invokevirtualはAbstractMethodErrorをスローします。
それ以外の場合、選択したメソッドがnativeで、そのメソッドを実装するコードをバインドできない場合、invokevirtualはUnsatisfiedLinkErrorをスローします。
それ以外の場合、メソッドが選択されておらず、解決されたメソッドの名前および記述子と一致し、abstractではないCの最大固有のスーパーインタフェース・メソッドが複数存在する場合、invokevirtualはIncompatibleClassChangeErrorをスローします。
それ以外の場合、メソッドが選択されておらず、解決されたメソッドの名前および記述子と一致し、abstractではないCの最大固有のスーパーインタフェース・メソッドがない場合、invokevirtualはAbstractMethodErrorをスローします。
それ以外の場合、解決されたメソッドがシグネチャ多相であり、java.lang.invoke.MethodHandleクラスで宣言されている場合は、次のようになります。
メソッド名がinvokeExactで、取得したjava.lang.invoke.MethodTypeのインスタンスが受信メソッド・ハンドルobjectrefの型記述子と意味的に等しくない場合、invokevirtual命令はjava.lang.invoke.WrongMethodTypeExceptionをスローします。
メソッド名がinvokeで、取得したjava.lang.invoke.MethodTypeのインスタンスが、受信側メソッド・ハンドルobjectrefで呼び出されたjava.lang.invoke.MethodHandleのasTypeメソッドに対する有効な引数ではない場合、invokevirtual命令はjava.lang.invoke.WrongMethodTypeExceptionをスローします。
それ以外の場合、解決されたメソッドがシグネチャ多相であり、java.lang.invoke.VarHandleクラスで宣言されている場合は、起動側メソッド・ハンドルの呼出しから発生する可能性のある実行時例外をスローできます。 objectrefがnullの場合、NullPointerExceptionを除き、valueFromMethodName、accessModeTypeおよびvarHandleExactInvokerメソッドの呼出しからランタイム例外はスローされません。
nargs引数値およびobjectrefは、最初のnargs+1ローカル変数を持つ1対1ではありません。 long型およびdouble型の引数値は、連続する2つのローカル変数に格納する必要があるため、nargs引数値を呼び出されたメソッドに渡すには、nargsを超えるローカル変数が必要になる場合があります。
invokevirtual命令のシンボリック参照がインタフェース・メソッドに解決される場合があります。 この場合、クラス階層にオーバーライド・メソッドはありませんが、abstract以外のインタフェース・メソッドが解決済メソッドの記述子と一致する可能性があります。 選択ロジックは、invokeinterfaceと同じルールを使用して、このようなメソッドに一致します。
ビット単位またはint
ior
ior = 128 (0x80)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 オペランド・スタックからポップされます。 int結果は、value1およびvalue2のビット単位のORを使用して計算されます。 resultは、オペランド・スタックにプッシュされます。
剰余int
irem
irem = 112 (0x70)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int resultは、value1 - (value1 / value2) * value2です。 resultは、オペランド・スタックにプッシュされます。
irem命令の結果は、(a/b)*b + (a%b)がaと等しくなるようになります。 このアイデンティティは、配当がそのタイプで可能な最大の大きさの負のintであり、除数が-1 (残りは0)である特殊なケースでも保持されます。 このルールから、剰余演算の結果は、配当がマイナスの場合のみマイナスにでき、配当がプラスの場合のみプラスにできることがわかります。 さらに、結果の大きさは、常に除数の大きさより小さくなります。
int剰余演算子の除数の値が0の場合、iremはArithmeticExceptionをスローします。
メソッドからintを返します
解雇
ireturn = 172 (0xac)
...、 value →
[空]
現在のメソッドには、boolean、byte、char、shortまたはintの戻り型が必要です。 valueはint型である必要があります。 現在のメソッドがsynchronizedメソッドの場合、メソッドの起動時に入力または再入力されたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。 例外がスローされない場合、valueは現在のフレームのオペランドスタック(§2.6)からポップされ、呼び出し元のフレームのオペランドスタックにプッシュされます。 現在のメソッドのオペランド・スタック上のその他の値はすべて破棄されます。
valueを起動側のフレームのオペランド・スタックにプッシュする前に、変換する必要がある場合があります。 呼び出されたメソッドの戻り型がbyte、charまたはshortの場合、valueは、i2b、i2cまたはi2sをそれぞれ実行した場合と同様に、intから戻り型に変換されます。 呼び出されたメソッドの戻り型がbooleanの場合、valueは、valueおよび1のビット単位ANDを使用して、intからbooleanに絞り込まれます。
インタプリタは、メソッドの起動元に制御を戻し、起動元のフレームを元に戻します。
Java Virtual Machineの実装で、§2.11.10で説明されている構造化ロックのルールが強制されない場合は、現在のメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、ireturnはIllegalMonitorStateExceptionをスローします。 これは、たとえば、synchronizedメソッドにmonitorexit命令が含まれているが、メソッドが同期されているオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックにルールが適用され、現在のメソッドの起動中にそれらのルールの最初のルールに違反すると、ireturnによってIllegalMonitorStateExceptionがスローされます。
左にシフト int
ishl
ishl = 120 (0x78)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 intresultは、value1をsビット位置でシフトすることで計算されます。ここで、sは、value2の下位5ビットの値です。 resultは、オペランド・スタックにプッシュされます。
これは、(オーバーフローが発生した場合でも) 2を乗算して累乗 sに相当します。 実際に使用されるシフト距離は、value2がビット単位の論理ANDの対象となり、マスク値が0x1fの場合と同様に、常に0から31の範囲内です。
算術シフト右 int
ishr
ishr = 122 (0x7a)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int結果は、value1を右にsビット位置でシフトし、符号拡張子を付けて計算されます。ここで、sは、value2の下位5ビットの値です。 resultは、オペランド・スタックにプッシュされます。
結果の値はfloor(value1 / 2s)で、sはvalue2および0x1fです。 負でないvalue1の場合、これはint除算を2で累乗sに切り捨てるのと同じです。 実際に使用されるシフト距離は、value2がビット単位の論理ANDの対象となり、マスク値が0x1fの場合と同様に、常に0から31の範囲内です。
intをローカル変数に格納します
istore
index
istore = 54 (0x36)
...、 value →
...
indexは、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければならない符号なしバイトです。 オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、indexのローカル変数の値がvalueに設定されます。
istore opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
intをローカル変数に格納します
istore_<n>
istore_0 = 59 (0x3b)
istore_1 = 60 (0x3c)
istore_2 = 61 (0x3d)
istore_3 = 62 (0x3e)
...、 value →
...
<n>は、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 オペランド・スタックの先頭にある値は、int型である必要があります。 オペランド・スタックからポップされ、<n>のローカル変数の値がvalueに設定されます。
istore_<n>の各命令は、<n>のindexを持つistoreと同じです。ただし、オペランド<n>は暗黙的です。
intを減算
isub
isub = 100 (0x64)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int resultは、value1 - value2です。 resultは、オペランド・スタックにプッシュされます。
intの減算の場合、a-bはa+(-b)と同じ結果を生成します。 int値の場合、ゼロからの減算は否定と同じです。
結果は、真の数学的結果の32ビットの下位ビットであり、int型の値として表される、十分に幅の広い2の補完形式になります。 オーバーフローが発生した場合、結果の符号は、2つの値の数学的差の符号と同じでない可能性があります。
オーバーフローが発生する可能性があるにもかかわらず、isub命令を実行すると、ランタイム例外がスローされることはありません。
論理シフト右 int
iushr
iushr = 124 (0x7c)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 値はオペランド・スタックからポップされます。 int resultは、value1を右にsビット位置でシフトし、拡張子はゼロで、sはvalue2の下位5ビットの値です。 resultは、オペランド・スタックにプッシュされます。
value1が正で、sがvalue2および0x1fの場合、結果はvalue1 >> sの結果と同じになります。value1が負の場合、結果は式の値と等しくなります(value1 >> s) + (2 << ~s)。 (2 << ~s)項を追加すると、伝播された符号ビットが取り消されます。 実際に使用されるシフト距離は常に0から31の範囲内です。
ビット単位のXOR int
ixor
ixor = 130 (0x82)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもint型である必要があります。 オペランド・スタックからポップされます。 int結果は、value1およびvalue2のビット単位の排他ORを使用して計算されます。 resultは、オペランド・スタックにプッシュされます。
ジャンプサブルーチン
jsr
branchbyte1
branchbyte2
jsr = 168 (0xa8)
... →
...、address
このjsr命令の直後の命令のopcodeのaddressは、returnAddress型の値としてオペランド・スタックにプッシュされます。 符号なしのbranchbyte1およびbranchbyte2を使用して、符号付き16ビット・オフセットを構築します。オフセットは(branchbyte1 << 8) | branchbyte2です。 実行は、この jsr命令のアドレスからそのオフセットで続行されます。 ターゲットアドレスは、この jsr命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
ジャンプサブルーチン(ワイドインデックス)
jsr_w
branchbyte1
branchbyte2
branchbyte3
branchbyte4
jsr_w = 201 (0xc9)
... →
...、address
このjsr_w命令の直後の命令のopcodeのaddressは、returnAddress型の値としてオペランド・スタックにプッシュされます。 符号なしのbranchbyte1、branchbyte2、branchbyte3およびbranchbyte4を使用して、符号付き32ビット・オフセットを構築します。オフセットは(branchbyte1 << 24) | (branchbyte2 << 16) | (branchbyte3 << 8) | branchbyte4です。 実行は、この jsr_w命令のアドレスからそのオフセットで続行されます。 ターゲットアドレスは、この jsr_w命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
longをdoubleに変換します。
l2d
l2d = 138 (0x8a)
...、 value →
..., result
オペランド・スタックの先頭にある値は、long型である必要があります。 オペランド・スタックからポップされ、最も近い丸めポリシー(§2.8)を使用してdouble結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
l2d命令は、double型の値には53個の仮ビットしかないため、精度を失う可能性のある拡張プリミティブ変換(JLS§5.1.2)を実行します。
longをfloatに変換します。
l2f
l2f = 137 (0x89)
...、 value →
..., result
オペランド・スタックの先頭にある値は、long型である必要があります。 オペランド・スタックからポップされ、最も近い丸めポリシー(§2.8)を使用してfloat結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
l2f命令は、float型の値には24個の符号ビットしかないため、精度を失う可能性のある拡張プリミティブ変換(JLS§5.1.2)を実行します。
longをintに変換します。
l2i
l2i = 136 (0x88)
...、 value →
..., result
オペランド・スタックの先頭にある値は、long型である必要があります。 オペランド・スタックからポップされ、long値の下位32ビットを取得し、上位32ビットを破棄することで、int結果に変換されます。 resultは、オペランド・スタックにプッシュされます。
l2i命令は、絞込みプリミティブ変換(JLS§5.1.3)を実行します。 値の全体的な大きさに関する情報が失われる可能性があります。 resultには、値と同じ符号がないこともあります。
longを追加します。
ladd
ladd = 97 (0x61)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 値はオペランド・スタックからポップされます。 long resultは、value1 + value2です。 resultは、オペランド・スタックにプッシュされます。
結果は、真の数学的結果の64ビットの下位ビットであり、long型の値として表される、十分に幅の広い2の補完形式になります。 オーバーフローが発生した場合、結果の符号は、2つの値の数学的合計の符号と同じでない可能性があります。
オーバーフローが発生する可能性があるにもかかわらず、ladd命令を実行すると、実行時例外がスローされることはありません。
配列からのlongのロード
ラロード
laload = 47 (0x2f)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがlong型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネント内のlongvalueが取得され、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、laloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、laload命令はArrayIndexOutOfBoundsExceptionをスローします。
ビット単位AND long
土地
land = 127 (0x7f)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 オペランド・スタックからポップされます。 long結果は、value1およびvalue2のビット単位ANDを使用して計算されます。 resultは、オペランド・スタックにプッシュされます。
long配列に格納
lastore
lastore = 80 (0x50)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがlong型である配列を参照する必要があります。 索引はint型で、値はlong型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。 long valueは、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、lastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、lastore命令はArrayIndexOutOfBoundsExceptionをスローします。
比較 long
lcmp
lcmp = 148 (0x94)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 これらはどちらもオペランド・スタックからポップされ、符号付き整数比較が実行されます。 value1がvalue2より大きい場合、int値1はオペランド・スタックにプッシュされます。 value1がvalue2と等しい場合、int値0はオペランド・スタックにプッシュされます。 value1がvalue2より小さい場合、int値-1はオペランド・スタックにプッシュされます。
long定数のプッシュ
lconst_<l>
lconst_0 = 9 (0x9)
lconst_1 = 10 (0xa)
... →
...、<l>
long定数<l> (0または1)をオペランド・スタックにプッシュします。
実行時定数プールからのアイテムのプッシュ
ldc
インデックス
ldc = 18 (0x12)
... →
..., value
indexは、現在のクラスの実行時定数プールへの有効なインデックスである必要がある符号なしバイトです(§2.5.5)。 indexの実行時定数プールエントリは、以下のいずれかではなく、ロード可能(§5.1)でなければなりません。
longまたはdouble型の数値定数。
フィールド記述子がJ (longを示す)またはD (doubleを示す)である、動的に計算される定数へのシンボリック参照。
ランタイム定数プール・エントリがint型またはfloat型の数値定数である場合、その数値定数の値は、それぞれintまたはfloatとしてオペランド・スタックにプッシュされます。
それ以外の場合、実行時定数プール・エントリが文字列定数、つまりクラスStringのインスタンスに対するreferenceである場合、そのインスタンスに対するreferenceであるvalueがオペランド・スタックにプッシュされます。
それ以外の場合、実行時定数プール・エントリがクラスまたはインタフェースへのシンボリック参照である場合、指定されたクラスまたはインタフェースが解決され(§5.4.3.1)、そのクラスまたはインタフェースを表すClassオブジェクトへのreferenceがオペランド・スタックにプッシュされます(value)。
それ以外の場合、実行時定数プール・エントリは、メソッド・タイプ、メソッド・ハンドルまたは動的に計算される定数へのシンボリック参照です。 シンボリック参照が解決され(§5.4.3.5、§5.4.3.6)、解決の結果であるvalueがオペランド・スタックにプッシュされます。
シンボリック参照の解決中に、その種類のシンボリック参照の解決に関する例外をスローできます。
実行時定数プールからのアイテムのプッシュ (ワイド・インデックス)
ldc_w
indexbyte1
indexbyte2
ldc_w = 19 (0x13)
... →
..., value
符号なしの indexbyte1および indexbyte2は、符号なしの16ビットインデックスに、現在のクラスの実行時定数プール(§2.5.5)にアセンブルされます。ここで、インデックスの値は(indexbyte1 << 8) | indexbyte2として計算されます。 索引は、現在のクラスの実行時定数プールへの有効な索引である必要があります。 索引のランタイム定数プール・エントリは、次のいずれでもなくロード可能(§5.1)である必要があります。
longまたはdouble型の数値定数。
フィールド記述子がJ (longを示す)またはD (doubleを示す)である、動的に計算される定数へのシンボリック参照。
ランタイム定数プール・エントリがint型またはfloat型の数値定数、あるいは文字列定数である場合、valueが決定され、ldc命令に指定されたルールに従ってオペランド・スタックにプッシュされます。
それ以外の場合、実行時定数プール・エントリは、クラス、インタフェース、メソッド・タイプ、メソッド・ハンドルまたは動的に計算された定数へのシンボリック参照です。 これは解決され、valueは、ldc命令に指定されたルールに従って決定され、オペランド・スタックにプッシュされます。
シンボリック参照の解決中に、その種類のシンボリック参照の解決に関する例外をスローできます。
ldc_w命令は、より広い実行時定数プールインデックスを除き、ldc命令(§ldc)と同じです。
ランタイム定数プール(全索引)からのlongまたはdoubleのプッシュ
ldc2_w
indexbyte1
indexbyte2
ldc2_w = 20 (0x14)
... →
..., value
符号なしの indexbyte1および indexbyte2は、符号なしの16ビットインデックスに、現在のクラスの実行時定数プール(§2.5.5)にアセンブルされます。ここで、インデックスの値は(indexbyte1 << 8) | indexbyte2として計算されます。 索引は、現在のクラスの実行時定数プールへの有効な索引である必要があります。 索引のランタイム定数プール・エントリは、ロード可能(§5.1)、および特に次のいずれかである必要があります。
longまたはdouble型の数値定数。
フィールド記述子がJ (longを示す)またはD (doubleを示す)である、動的に計算される定数へのシンボリック参照。
ランタイム定数プール・エントリがlong型またはdouble型の数値定数である場合、その数値定数の値は、それぞれlongまたはdoubleとしてオペランド・スタックにプッシュされます。
それ以外の場合、実行時定数プール・エントリは、動的に計算される定数へのシンボリック参照です。 シンボリック参照が解決され(§5.4.3.6)、解決の結果である valueがオペランドスタックにプッシュされます。
動的に計算された定数へのシンボリック参照の解決中に、動的に計算された定数解決に関連する例外をスローできます。
ldc2_w命令のワイドインデックス・バージョンのみが存在し、シングルバイト索引でlongまたはdoubleをプッシュするldc2命令はありません。
longの除算
ldiv
ldiv = 109 (0x6d)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 値はオペランド・スタックからポップされます。 long resultは、Javaプログラミング言語式value1 / value2の値です。 resultは、オペランド・スタックにプッシュされます。
long除算は0に丸められます。つまり、n/dのlong値に対して生成される商はlong値qで、その大きさは|d ⋅ q| ≤ |n|を満たしている間はできるだけ大きくなります。 また、qは、|n| ≥ |d|とnとdが同じ符号を持つ場合に正ですが、|n| ≥ |d|とnとdに逆の符号がある場合、負の値になります。
このルールを満たさない特殊なケースが1つあります。long型で可能な最大の大きさの負の整数で除数が-1の場合、オーバーフローが発生し、結果は除算と等しくなります。オーバーフローにもかかわらず、この場合、例外はスローされません。
long除数の値が0の場合、ldivはArithmeticExceptionをスローします。
ローカル変数からlongをロードします
lload
index
lload = 22 (0x16)
... →
..., value
索引は符号なしバイトです。 indexと index+1はどちらも、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければなりません。 indexのローカル変数には、longが含まれている必要があります。 indexのローカル変数のvalueは、オペランド・スタックにプッシュされます。
lload opcodeは、2バイトの符号なし索引を使用してローカル変数にアクセスするために、wide命令(§wide)と組み合せて使用できます。
ローカル変数からlongをロードします
lload_<n>
lload_0 = 30 (0x1e)
lload_1 = 31 (0x1f)
lload_2 = 32 (0x20)
lload_3 = 33 (0x21)
... →
..., value
<n>と<n>+1の両方が、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 <n>のローカル変数には、longが含まれている必要があります。 <n>のローカル変数の値がオペランド・スタックにプッシュされます。
lload_<n>の各命令は、<n>の索引を持つlloadと同じですが、オペランド<n>が暗黙的に指定されています。
longの乗算
lmul
lmul = 105 (0x69)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 値はオペランド・スタックからポップされます。 long resultは、value1 * value2です。 resultは、オペランド・スタックにプッシュされます。
結果は、真の数学的結果の64ビットの下位ビットであり、long型の値として表される、十分に幅の広い2の補完形式になります。 オーバーフローが発生した場合、結果の符号は、2つの値の数学的乗算の符号と同じでない可能性があります。
オーバーフローが発生する可能性があるにもかかわらず、lmul命令を実行すると、実行時例外がスローされることはありません。
否定long
lneg
lneg = 117 (0x75)
...、 value →
..., result
valueはlong型である必要があります。 オペランド・スタックからポップされます。 long resultは、value、-valueの算術否定です。 resultは、オペランド・スタックにプッシュされます。
long値の場合、否定はゼロからの減算と同じです。 Java Virtual Machineでは整数に2の補数表現が使用され、2の補数値の範囲は対称ではないため、負の最大longを否定すると、同じ最大負数になります。 オーバーフローが発生したにもかかわらず、例外はスローされません。
すべてのlong値xについて、-xは(~x)+1と等しくなります。
キー一致およびジャンプによるジャンプ表へのアクセス
lookupswitch
<0-3バイトパッド>
defaultbyte1
defaultbyte2
defaultbyte3
defaultbyte4
npairs1
npairs2
npairs3
npairs4
match-offset pair...
lookupswitch = 171 (0xab)
...、 key →
...
lookupswitchは可変長命令です。 lookupswitch opcodeの直後、0から3バイトの間はパディングとして機能する必要があります。これにより、defaultbyte1は、現在のメソッドの開始から4バイトの倍数(最初の命令のopcode)のアドレスで開始されます。 パディングの直後には、一連の符号付き32ビット値(default、npairs、および符号付き32ビット値のnpairsペア)に従います。 npairsは0以上である必要があります。 npairsの各ペアは、int一致と符号付き32ビットオフセットで構成されます。 これらの符号付き32ビット値はそれぞれ、(byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4として4つの符号なしバイトから構成されます。
lookupswitch命令の表のmatch-offsetペアは、matchの数値順でソートする必要があります。
キーはint型である必要があり、オペランド・スタックからポップされます。 キーは、match値と比較されます。 いずれかと等しい場合、ターゲット・アドレスは、対応するオフセットをこのlookupswitch命令のopcodeのアドレスに追加して計算されます。 keyがmatch値のいずれとも一致しない場合、ターゲット・アドレスは、このlookupswitch命令のopcodeのアドレスにdefaultを加算して計算されます。 その後、ターゲットアドレスで実行が続行されます。
各match-offsetペアのoffsetから計算できるターゲット・アドレスと、defaultから計算されるターゲット・アドレスは、このlookupswitch命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
lookupswitch命令の4バイトオペランドに必要な整列によって、lookupswitchを含むメソッドが4バイト境界上に配置されている場合にのみ、それらのオペランドの4バイト整列が保証されます。
match-offsetペアは、線形検索よりも速い参照ルーチンをサポートするようにソートされます。
ビット単位またはlong
lor
lor = 129 (0x81)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 オペランド・スタックからポップされます。 long結果は、value1およびvalue2のビット単位のORを使用して計算されます。 resultは、オペランド・スタックにプッシュされます。
剰余long
lrem
lrem = 113 (0x71)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 値はオペランド・スタックからポップされます。 long resultは、value1 - (value1 / value2) * value2です。 resultは、オペランド・スタックにプッシュされます。
lrem命令の結果は、(a/b)*b + (a%b)がaと等しくなるようになります。 このアイデンティティは、配当がそのタイプで可能な最大の大きさの負のlongであり、除数が-1 (残りは0)である特殊なケースでも保持されます。 このルールから、剰余演算の結果は、配当が負の場合にのみ負になる可能性があり、配当が正の場合にのみ正になる可能性があり、さらに、結果の大きさは常に除数の大きさより小さくなります。
long剰余演算子の除数の値が0の場合、lremはArithmeticExceptionをスローします。
メソッドからlongを返します
リターン
lreturn = 173 (0xad)
...、 value →
[空]
現在のメソッドには、戻り型longが必要です。 valueはlong型である必要があります。 現在のメソッドがsynchronizedメソッドの場合、メソッドの起動時に入力または再入力されたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。 例外がスローされない場合、valueは現在のフレームのオペランドスタック(§2.6)からポップされ、呼び出し元のフレームのオペランドスタックにプッシュされます。 現在のメソッドのオペランド・スタック上のその他の値はすべて破棄されます。
インタプリタは、メソッドの起動元に制御を戻し、起動元のフレームを元に戻します。
Java Virtual Machineの実装で、§2.11.10で説明されている構造化ロックのルールが強制されない場合は、現在のメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、lreturnはIllegalMonitorStateExceptionをスローします。 これは、たとえば、synchronizedメソッドにmonitorexit命令が含まれ、メソッドがsynchronizedであるオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックにルールが適用され、現在のメソッドの呼出し中にそれらのルールの最初のルールに違反した場合、lreturnはIllegalMonitorStateExceptionをスローします。
左にシフト long
lshl
lshl = 121 (0x79)
...、 value1、 value2 →
..., result
value1はlong型で、value2はint型である必要があります。 値はオペランド・スタックからポップされます。 long結果は、value1をsビット位置でシフトすることで計算されます。ここで、sはvalue2の下位6ビットです。 resultは、オペランド・スタックにプッシュされます。
これは、(オーバーフローが発生した場合でも) 2を乗算して累乗 sに相当します。 したがって、実際に使用されるシフト距離は、value2がビット単位の論理ANDの対象となり、マスク値が0x3fの場合と同様に、常に0から63の範囲内です。
算術シフト右 long
lshr
lshr = 123 (0x7b)
...、 value1、 value2 →
..., result
value1はlong型で、value2はint型である必要があります。 値はオペランド・スタックからポップされます。 long結果は、value1をsビット位置で右にシフトし、符号拡張子を付けて計算されます。ここで、sは、value2の下位6ビットの値です。 resultは、オペランド・スタックにプッシュされます。
結果の値はfloor(value1 / 2s)で、sはvalue2および0x3fです。 負でないvalue1の場合、これはlong除算を2で累乗sに切り捨てるのと同じです。 したがって、実際に使用されるシフト距離は、value2がビット単位の論理ANDの対象となり、マスク値が0x3fの場合と同様に、常に0から63の範囲内です。
longをローカル変数に格納します
lstore
索引
lstore = 55 (0x37)
...、 value →
...
索引は符号なしバイトです。 indexと index+1はどちらも、現在のフレームのローカル変数配列(§2.6)へのインデックスでなければなりません。 オペランド・スタックの先頭にある値は、long型である必要があります。 オペランド・スタックからポップされ、indexおよびindex+1のローカル変数はvalueに設定されます。
lstore opcodeは、wide命令(§wide)と組み合せて使用して、2バイトの符号なし索引を使用してローカル変数にアクセスできます。
longをローカル変数に格納します
lstore_<n>
lstore_0 = 63 (0x3f)
lstore_1 = 64 (0x40)
lstore_2 = 65 (0x41)
lstore_3 = 66 (0x42)
...、 value →
...
<n>と<n>+1の両方が、現在のフレームのローカル変数配列へのインデックスである必要があります(§2.6)。 オペランド・スタックの先頭にある値は、long型である必要があります。 オペランド・スタックからポップされ、<n>および<n>+1のローカル変数がvalueに設定されます。
lstore_<n>の各命令は、<n>の索引を持つlstoreと同じですが、オペランド<n>が暗黙的に指定されている点が異なります。
longを減算
lsub
lsub = 101 (0x65)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 値はオペランド・スタックからポップされます。 long resultは、value1 - value2です。 resultは、オペランド・スタックにプッシュされます。
longの減算の場合、a-bはa+(-b)と同じ結果を生成します。 long値の場合、ゼロからの減算は否定と同じです。
結果は、真の数学的結果の64ビットの下位ビットであり、long型の値として表される、十分に幅の広い2の補完形式になります。 オーバーフローが発生した場合、結果の符号は、2つの値の数学的差の符号と同じでない可能性があります。
オーバーフローが発生する可能性があるにもかかわらず、lsub命令を実行すると、実行時例外がスローされることはありません。
論理シフト右 long
lushr
lushr = 125 (0x7d)
...、 value1、 value2 →
..., result
value1はlong型で、value2はint型である必要があります。 値はオペランド・スタックからポップされます。 long resultは、value1をsビット位置で論理的に右にシフトし、拡張子はゼロで、sはvalue2の下位6ビットの値です。 resultは、オペランド・スタックにプッシュされます。
value1が正で、sがvalue2および0x3fの場合、結果はvalue1 >> sの結果と同じで、value1が負の場合、結果は式の値(value1 >> s) + (2L << ~s)と等しくなります。 (2L << ~s)項を追加すると、伝播された符号ビットが取り消されます。 実際に使用されるシフト距離は常に0から63の範囲内です。
ビット単位のXOR long
lxor
lxor = 131 (0x83)
...、 value1、 value2 →
..., result
value1とvalue2はどちらもlong型である必要があります。 オペランド・スタックからポップされます。 long結果は、value1およびvalue2のビット単位の排他ORを使用して計算されます。 resultは、オペランド・スタックにプッシュされます。
オブジェクトのモニターの入力
monitorenter
monitorenter = 194 (0xc2)
...、 objectref →
...
objectrefはreference型である必要があります。
各オブジェクトはモニターに関連付けられます。 モニターは、所有者がいる場合にのみロックされます。 monitorenterを実行するスレッドは、次のようにobjectrefに関連付けられたモニターの所有権を取得しようとします。
objectrefに関連付けられたモニターのエントリ数が0の場合、スレッドはモニターに入り、そのエントリ数を1に設定します。 スレッドはモニターの所有者になります。
スレッドがobjectrefに関連付けられたモニターをすでに所有している場合は、モニターが再挿入され、エントリ数が増加します。
objectrefに関連付けられたモニターをすでに別のスレッドが所有している場合、スレッドはモニターのエントリ数がゼロになるまでブロックし、所有権の取得を再試行します。
objectrefがnullの場合、monitorenterはNullPointerExceptionをスローします。
monitorenter命令は、1つ以上のmonitorexit命令(§monitorexit)とともに使用して、Javaプログラミング言語(§3.14)でsynchronized文を実装できます。 monitorenterおよびmonitorexit命令は、synchronizedメソッドの実装では使用されませんが、同等のロック・セマンティクスを提供するために使用できます。 synchronizedメソッドの起動時にエントリをモニターし、その戻り時に終了をモニターすることは、monitorenterおよびmonitorexitが使用されたかのように、Java Virtual Machineのメソッド呼出しおよび戻り命令によって暗黙的に処理されます。
モニターとオブジェクトの関連付けは、この仕様の範囲を超える様々な方法で管理できます。 たとえば、モニターはオブジェクトと同時に割当ておよび割当て解除できます。 または、スレッドがオブジェクトへの排他的アクセスを取得しようとしたときに動的に割り当てられ、後でオブジェクトのモニターにスレッドが残っていないときに解放されます。
Javaプログラミング言語の同期構成では、開始および終了以外のモニターでの操作のサポートが必要です。 これには、モニターでの待機(Object.wait)や、モニターで待機している他のスレッドへの通知(Object.notifyAllおよびObject.notify)が含まれます。 これらの操作は、Java Virtual Machineに付属の標準パッケージjava.langでサポートされています。 これらの操作の明示的なサポートは、Java Virtual Machineの命令セットには表示されません。
オブジェクトの終了モニター
monitorexit
monitorexit = 195 (0xc3)
...、 objectref →
...
objectrefはreference型である必要があります。
monitorexitを実行するスレッドは、objectrefによって参照されるインスタンスに関連付けられたモニターの所有者である必要があります。
スレッドは、objectrefに関連付けられたモニターのエントリ数を減少させます。 その結果、エントリ数の値がゼロの場合、スレッドはモニターを終了し、その所有者ではなくなります。 モニターに入ることをブロックしているほかのスレッドは、そのように試行できます。
objectrefがnullの場合、monitorexitはNullPointerExceptionをスローします。
それ以外の場合、monitorexitを実行するスレッドが、objectrefによって参照されるインスタンスに関連付けられたモニターの所有者でない場合は、monitorexitによってIllegalMonitorStateExceptionがスローされます。
それ以外の場合、Java Virtual Machine実装が§2.11.10で説明されている構造化ロックにルールを適用し、これらのルールの2番目がこのmonitorexit命令の実行によって違反された場合、monitorexitはIllegalMonitorStateExceptionをスローします。
1つ以上のmonitorexit命令をmonitorenter命令(§monitorenter)とともに使用して、Javaプログラミング言語(§3.14)でsynchronized文を実装できます。 monitorenterおよびmonitorexit命令は、synchronizedメソッドの実装では使用されませんが、同等のロック・セマンティクスを提供するために使用できます。
Java Virtual Machineでは、synchronizedメソッドおよびsynchronized文内でスローされる例外は、次のように異なる方法でサポートされます。
通常のsynchronizedメソッド完了時のモニター終了は、Java Virtual Machineの戻り命令によって処理されます。 synchronizedメソッドの異常終了時のモニターの終了は、Java Virtual Machineのathrow命令によって暗黙的に処理されます。
synchronized文内から例外がスローされた場合、Java Virtual Machineの例外処理メカニズム(§3.14)を使用して、synchronized文の実行前に入力されたモニターを終了します。
新規多次元配列の作成
マルチアレイ
indexbyte1
indexbyte2
ディメンション
multianewarray = 197 (0xc5)
...、 count1、 [count2、 ...] →
..., arrayref
dimensionsオペランドは、1以上でなければならない符号なしバイトです。 作成する配列のディメンションの数を表します。 オペランド・スタックには、ディメンション値が含まれている必要があります。 このような値はそれぞれ、作成する配列のディメンション内のコンポーネントの数を表し、int型で、負でない必要があります。 count1は、最初のディメンションで必要な長さ、2番目のディメンションでcount2などです。
すべてのcount値がオペランド・スタックからポップされます。 符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、クラス、配列またはインタフェース・タイプへのシンボリック参照である必要があります。 指定されたクラス、配列、またはインタフェース型が解決されます(§5.4.3.1)。 結果のエントリは、ディメンション以上のディメンションの配列クラス・タイプである必要があります。
配列型の新しい多次元配列は、ガベージ・コレクション・ヒープから割り当てられます。 count値がゼロの場合、後続のディメンションは割り当てられません。 最初のディメンションの配列のコンポーネントは、2番目のディメンションのタイプのサブ配列に初期化されます。 配列の最後に割り当てられた次元のコンポーネントは、配列型の要素型のデフォルトの初期値(§2.3、§2.4)に初期化されます。 新しい配列へのreferencearrayrefは、オペランド・スタックにプッシュされます。
クラス、配列またはインタフェース型へのシンボリック参照の解決中に、§5.4.3.1に記載されている例外をスローできます。
それ以外の場合、現在のクラスに解決された配列クラスの要素タイプにアクセスする権限がない場合は、multianewarrayによってIllegalAccessErrorがスローされます。
それ以外の場合、オペランド・スタックのdimensions値のいずれかが0より小さい場合、multianewarray命令はNegativeArraySizeExceptionをスローします。
単一ディメンションの配列を作成する場合は、newarrayまたはanewarray (§newarray、§anewarray)を使用する方が効率的です。
ランタイム定数プールを介して参照される配列クラスは、multianewarray命令のdimensionsオペランドよりも多くのディメンションを持つ場合があります。 その場合、配列のディメンションの最初のディメンションのみが作成されます。
新規オブジェクトの作成
new
indexbyte1
indexbyte2
new = 187 (0xbb)
... →
..., objectref
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、クラスまたはインタフェース・タイプへのシンボリック参照である必要があります。 名前付きクラスまたはインタフェース型は解決され(§5.4.3.1)、結果としてクラス型になります。 そのクラスの新しいインスタンスのメモリーはガベージ・コレクション・ヒープから割り当てられ、新しいオブジェクトのインスタンス変数はデフォルトの初期値に初期化されます(§2.3、§2.4)。 objectrefは、インスタンスに対するreferenceであり、オペランド・スタックにプッシュされます。
クラスの解決に成功すると、まだ初期化されていなければ初期化されます(§5.5)。
クラスまたはインタフェース型へのシンボリック参照の解決中に、§5.4.3.1に記載されている例外をスローできます。
それ以外の場合、クラスまたはインタフェース型へのシンボリック参照がインタフェースまたはabstractクラスに解決されると、newはInstantiationErrorをスローします。
それ以外の場合、このnew命令の実行によって参照クラスが初期化される場合、newはJLS§15.9.4で詳しく説明されているようにErrorをスローすることがあります。
new命令は完全に新しいインスタンスを作成しません。インスタンスの作成は、初期化されていないインスタンスでインスタンス初期化メソッド(§2.9.1)が呼び出されるまで完了しません。
新しい配列を作成
newarray
atype
newarray = 188 (0xbc)
...、 count →
..., arrayref
countはint型である必要があります。 オペランド・スタックからポップされます。 countは、作成される配列内の要素の数を表します。
typeは、作成する配列のタイプを示すコードです。 次のいずれかの値が必要です。
表6.5.newarray-A. 配列型コード
| 配列型 | atype |
|---|---|
T_BOOLEAN |
4 |
T_CHAR |
5 |
T_FLOAT |
6 |
T_DOUBLE |
7 |
T_BYTE |
8 |
T_SHORT |
9 |
T_INT |
10 |
T_LONG |
11 |
コンポーネントのタイプがatypeで長さがcountの新しい配列は、ガベージ・コレクション・ヒープから割り当てられます。 この新しい配列オブジェクトに対するreferencearrayrefは、オペランド・スタックにプッシュされます。 新しい配列の各要素は、配列型の要素型のデフォルトの初期値(§2.3、§2.4)に初期化されます。
countが0より小さい場合、newarrayはNegativeArraySizeExceptionをスローします。
意味なし
nop
nop = 0 (0x0)
変更なし
意味なし
上部のオペランド・スタック値をポップ
pop
pop = 87 (0x57)
...、 value →
...
上位1つまたは2つのオペランド・スタック値をポップ
pop2
pop2 = 88 (0x58)
フォーム 1:
...、 value2、 value1 →
...
ここで、value1とvalue2はそれぞれ、カテゴリ1の計算型の値です(§2.11.1)。
フォーム 2:
...、 value →
...
ここで、valueは、カテゴリ2の計算型の値です(§2.11.1)。
オペランドスタックから上部の1つまたは2つの値をポップします。
オブジェクトにフィールドを設定
putfield
indexbyte1
indexbyte2
putfield = 181 (0xb5)
...、 objectref、 value →
...
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、フィールド(§5.1)へのシンボリック参照である必要があります。この参照では、フィールドの名前と記述子、およびフィールドが見つかるクラスのシンボリック参照が示されます。 参照フィールドは解決されます(§5.4.3.2)。
putfield命令によって格納されるvalueの型は、参照されるフィールドの記述子と互換性がある必要があります(§4.3.2)。 フィールド記述子のタイプがboolean、byte、char、shortまたはintの場合、valueはintである必要があります。 フィールド記述子のタイプがfloat、longまたはdoubleの場合、valueはそれぞれfloat、longまたはdoubleである必要があります。 フィールド記述子タイプがクラス型または配列型の場合、valueはフィールド記述子型の値である必要があります。 フィールドがfinalの場合、カレント・クラスで宣言する必要があり、命令はカレント・クラスのインスタンス初期化メソッド(§2.9.1)で発生する必要があります。
valueおよびobjectrefは、オペランド・スタックからポップされます。
objectrefはreference型である必要がありますが、配列型ではありません。
valueのタイプがintで、フィールド記述子のタイプがbyte、char、shortまたはbooleanのいずれかである場合、int valueは、次のようにフィールド記述子タイプに変換されます。 フィールド記述子タイプがbyte、charまたはshortの場合、int valueは、フィールド記述子タイプvalueの値に切り捨てられます。 フィールド記述子タイプがbooleanの場合、intvalueはvalueおよび1のビット単位ANDを使用して絞り込まれ、結果としてvalue'になります。 objectrefで参照されるフィールドは、value'に設定されます。
それ以外の場合、objectrefで参照されるフィールドはvalueに設定されます。
フィールドへのシンボリック参照の解決中に、フィールド解決に関する例外(§5.4.3.2)をスローできます。
それ以外の場合、解決されたフィールドがstaticフィールドの場合、putfieldはIncompatibleClassChangeErrorをスローします。
それ以外の場合、解決されたフィールドがfinalの場合は、現在のクラスで宣言する必要があり、命令は現在のクラスのインスタンス初期化メソッドで発生する必要があります。 それ以外の場合は、IllegalAccessErrorがスローされます。
それ以外の場合、objectrefがnullの場合、putfield命令はNullPointerExceptionをスローします。
クラスの静的フィールドの設定
putstatic
indexbyte1
indexbyte2
putstatic = 179 (0xb3)
...、 value →
...
符号なしのindexbyte1およびindexbyte2は、現在のクラスの実行時定数プール(§2.6)に索引を構築するために使用されます。索引の値は(indexbyte1 << 8) | indexbyte2です。 索引のランタイム定数プール・エントリは、フィールド(§5.1)へのシンボリック参照である必要があります。この参照では、フィールドの名前と記述子、およびフィールドが見つかるクラスまたはインタフェースへのシンボリック参照が示されます。 参照フィールドは解決されます(§5.4.3.2)。
フィールドが正常に解決されると、解決されたフィールドを宣言したクラスまたはインタフェースは、そのクラスまたはインタフェースがまだ初期化されていない場合に初期化されます(§5.5)。
putstatic命令によって格納される valueの型は、参照されるフィールドの記述子と互換性がある必要があります(§4.3.2)。 フィールド記述子のタイプがboolean、byte、char、shortまたはintの場合、valueはintである必要があります。 フィールド記述子のタイプがfloat、longまたはdoubleの場合、valueはそれぞれfloat、longまたはdoubleである必要があります。 フィールド記述子タイプがクラス型または配列型の場合、valueはフィールド記述子型の値である必要があります。 フィールドがfinalの場合、現在のクラスまたはインタフェースで宣言する必要があり、命令は現在のクラスまたはインタフェースのクラスまたはインタフェース初期化メソッド(§2.9.2)で発生する必要があります。
valueは、オペランド・スタックからポップされます。
valueのタイプがintで、フィールド記述子のタイプがbyte、char、shortまたはbooleanのいずれかである場合、int valueは、次のようにフィールド記述子タイプに変換されます。 フィールド記述子タイプがbyte、charまたはshortの場合、int valueは、フィールド記述子タイプvalueの値に切り捨てられます。 フィールド記述子タイプがbooleanの場合、intvalueはvalueおよび1のビット単位ANDを使用して絞り込まれ、結果としてvalue'になります。 クラスまたはインタフェースの参照フィールドは、value'に設定されます。
それ以外の場合は、クラスまたはインタフェースの参照フィールドがvalueに設定されます。
クラスまたはインタフェース・フィールドへのシンボリック参照の解決時に、フィールド解決に関する例外(§5.4.3.2)をスローできます。
それ以外の場合、解決されたフィールドがstatic (クラス)フィールドまたはインタフェース・フィールドでない場合、putstaticはIncompatibleClassChangeErrorをスローします。
それ以外の場合、解決されたフィールドがfinalの場合は、現在のクラスまたはインタフェースで宣言する必要があり、命令は現在のクラスまたはインタフェースのクラスまたはインタフェース初期化メソッドで発生する必要があります。 それ以外の場合は、IllegalAccessErrorがスローされます。
それ以外の場合、このputstatic命令の実行によって参照されるクラスまたはインタフェースの初期化が発生すると、putstaticは§5.5の説明に従ってErrorをスローすることがあります。
putstatic命令は、そのフィールドの初期化時にインタフェース・フィールドの値を設定する場合にのみ使用できます。 インタフェースの初期化時にインタフェース変数初期化式を実行するときに、インタフェース・フィールドを1回のみ割り当てることができます(§5.5、JLS§9.3.1)。
サブルーチンからの戻り値
ret
index
ret = 169 (0xa9)
変更なし
索引は、0から255までの符号なしバイトです。 現在のフレーム(§2.6)のindexのローカル変数には、returnAddress型の値を含める必要があります。 ローカル変数の内容はJava Virtual Machineのpcレジスタに書き込まれ、そこで実行が続行されます。
jsr (§jsr)はアドレスをオペランドスタックにプッシュし、retはそのアドレスをローカル変数から取り出します。 この非対称性は意図的なものです。
Java SE 6より前のJavaプログラミング言語用のOracleのコンパイラ実装では、ret命令がjsrおよびjsr_w命令(§jsr、§jsr_w)とともに使用され、finally句(§3.13、§4.10.2.5)の実装に使用されました。
ret命令は、return命令(§return)と混同しないでください。 return命令は、呼出し元に値を渡さずに、メソッドから呼出し元に制御を返します。
ret opcodeは、2バイトの符号なし索引を使用してローカル変数にアクセスするために、wide命令(§wide)と組み合せて使用できます。
メソッドからvoidを返します
戻り値
return = 177 (0xb1)
... →
[空]
現在のメソッドには、戻り型voidが必要です。 現在のメソッドがsynchronizedメソッドの場合、メソッドの起動時に入力または再入力されたモニターが更新され、現在のスレッドでmonitorexit命令(§monitorexit)を実行した場合と同様に終了する可能性があります。 例外がスローされない場合、現在のフレーム(§2.6)のオペランドスタック上の値はすべて破棄されます。
インタプリタは、メソッドの起動元に制御を戻し、起動元のフレームを元に戻します。
Java Virtual Machineの実装で、§2.11.10で説明されている構造化ロックのルールが強制されない場合は、現在のメソッドがsynchronizedメソッドであり、現在のスレッドがメソッドの起動時に入力または再入力されたモニターの所有者ではない場合、returnはIllegalMonitorStateExceptionをスローします。 これは、たとえば、synchronizedメソッドにmonitorexit命令が含まれ、メソッドがsynchronizedであるオブジェクトにmonitorenter命令が含まれていない場合に発生します。
それ以外の場合、Java Virtual Machine実装で§2.11.10で説明されている構造化ロックにルールが適用され、現在のメソッドの呼出し中にそれらのルールの最初のルールに違反した場合、returnはIllegalMonitorStateExceptionをスローします。
配列からのshortのロード
saload
saload = 53 (0x35)
...、 arrayref、 index →
..., value
arrayrefはreference型である必要があり、コンポーネントがshort型である配列を参照する必要があります。 索引は、int型である必要があります。 arrayrefとindexの両方がオペランド・スタックからポップされます。 indexの配列のコンポーネントが取得され、intvalueに符号が拡張されます。 その値は、オペランド・スタックにプッシュされます。
arrayrefがnullの場合、saloadはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、saload命令はArrayIndexOutOfBoundsExceptionをスローします。
short配列に格納
sastore
sastore = 86 (0x56)
...、 arrayref、 index、 value →
...
arrayrefはreference型である必要があり、コンポーネントがshort型である配列を参照する必要があります。 indexとvalueはどちらもint型である必要があります。 オペランド・スタックからarrayref、indexおよびvalueがポップされます。 int valueは、shortに切り捨てられ、indexによって索引付けされた配列のコンポーネントとして格納されます。
arrayrefがnullの場合、sastoreはNullPointerExceptionをスローします。
それ以外の場合、indexがarrayrefによって参照される配列の境界内にない場合、sastore命令はArrayIndexOutOfBoundsExceptionをスローします。
プッシュshort
sipush
byte1
byte2
sipush = 17 (0x11)
... →
..., value
即時の符号なしのbyte1およびbyte2値は中間shortにアセンブルされます。ここで、shortの値は(byte1 << 8) | byte2です。 次に、中間値はint値に符号拡張されます。 その値は、オペランド・スタックにプッシュされます。
上位2つのオペランド・スタック値を入れ替えます
swap
swap = 95 (0x5f)
...、 value2、 value1 →
..., value1, value2
Java Virtual Machineは、カテゴリ2の計算タイプのオペランドにスワップを実装する命令を提供しません。
索引およびジャンプによるジャンプ表へのアクセス
tableswitch
<0-3バイト・パッド>
defaultbyte1
defaultbyte2
defaultbyte3
defaultbyte4
lowbyte1
lowbyte2
lowbyte3
lowbyte4
highbyte1
highbyte2
highbyte3
highbyte4
jump offsets...
tableswitch = 170 (0xaa)
...、 index →
...
tableswitchは、可変長命令です。 tableswitch opcodeの直後、0から3バイトがパディングとして機能し、defaultbyte1が現在のメソッドの開始から4バイトの倍数であるアドレス(最初の命令のopcode)から始まるようにする必要があります。 パディングの直後には、3つの符号付き32ビット値(default、lowおよびhigh)を構成するバイトがあります。 直後には、一連の高 - 低 + 1個の符号付き32ビット・オフセットを構成するバイトがあります。 値lowは、high以下にする必要があります。 high - low + 1つの符号付き32ビット・オフセットは、0ベースのジャンプ表として扱われます。 これらの符号付き32ビット値はそれぞれ(byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4として構築されます。
索引はint型である必要があり、オペランド・スタックからポップされます。 indexがlowより小さい場合、またはindexがhighより大きい場合、ターゲット・アドレスは、このtableswitch命令のopcodeのアドレスにdefaultを加算して計算されます。 それ以外の場合は、ジャンプ・テーブルの位置index - lowのオフセットが抽出されます。 ターゲットアドレスは、この tableswitch命令のopcodeのアドレスにそのオフセットを追加することによって計算されます。 その後、ターゲットアドレスで実行が続行されます。
各ジャンプテーブルオフセットから計算できるターゲットアドレスと、defaultから計算できるターゲットアドレスは、この tableswitch命令を含むメソッド内の命令のopcodeのアドレスである必要があります。
tableswitch命令の4バイトオペランドに必要な整列は、tableswitchを含むメソッドが4バイト境界で開始した場合にのみ、これらのオペランドの4バイト整列を保証します。
追加バイトによるローカル変数索引の拡張
全体
<opcode>
indexbyte1
indexbyte2
ここで、<opcode>は、iload、fload、aload、lload、dload、istore、fstore、astore、lstore、dstore、またはretのいずれかです。
全体
iinc
indexbyte1
indexbyte2
constbyte1
constbyte2
wide = 196 (0xc4)
変更された命令と同じ
wide命令は、別の命令の動作を変更します。 これは、変更される命令に応じて、2つの形式のいずれかを取ります。 The first form of the wide instruction modifies one of the instructions iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, or ret (§iload, §fload, §aload, §lload, §dload, §istore, §fstore, §astore, §lstore, §dstore, §ret). 2番目の形式は、iinc命令(§iinc)にのみ適用されます。
いずれの場合も、wide opcode自体は、コンパイルされたコード内で命令 wideのopcodeによって変更されます。 どちらの形式でも、2つの符号なしバイト indexbyte1と indexbyte2は変更されたopcodeのあとにあり、現在のフレーム(§2.6)内のローカル変数への16ビットの符号なしインデックスにアセンブルされます。ここで、インデックスの値は(indexbyte1 << 8) | indexbyte2です。 計算されたインデックスは、現在のフレームのローカル変数配列へのインデックスである必要があります。 wide命令がlload、dload、lstoreまたはdstore命令を変更する場合、計算されたインデックス(インデックス+ 1)に続くインデックスもローカル変数配列へのインデックスである必要があります。 2番目の形式では、コード・ストリームのconstbyte1およびconstbyte2の2つの即時符号なしバイトがindexbyte1およびindexbyte2の後に続きます。 これらのバイトは、符号付き16ビット定数にも組み立てられます。ここで、定数は(constbyte1 << 8) | constbyte2です。
拡張バイトコードは、より広い索引の使用、および2番目の形式の場合は大きい増分範囲を除き、通常どおり動作します。
wideは「別の命令の動作を変更する」と言いますが、wide命令は、変更された命令を構成するバイトをオペランドとして効果的に処理し、プロセス内の組み込み命令を示します。 変更された iinc命令の場合、iincの論理オペランドの1つが、opcodeからの通常のオフセットでさえありません。 組み込み命令を直接実行してはいけません。そのopcodeは制御転送命令のターゲットであってはいけません。