パッケージ java.lang.invoke
java.lang.invoke
パッケージは、Java Virtual Machineとやりとりするための低レベルのプリミティブを提供します。
Java Virtual Machine仕様で説明されているように、このパッケージの特定の型には、仮想マシンによる特別な処理が与えられます。
- クラス
MethodHandle
VarHandle
には、型記述子に関係なくリンクできる「シグネチャ・ポリモーフィック・メソッド」が含まれています。 通常、メソッドのリンク時には型記述子が厳密に一致する必要があります。 - JVMのバイト・コード形式では、クラス
MethodHandle
とMethodType
の即値定数がサポートされます。 invokedynamic
命令では、カスタム・メソッド呼出し動作のためにMethodHandle
定数を使用してCallSite
オブジェクトを動的に解決します。ldc
命令では、カスタム定数値を動的に解決するためにbootstrapMethodHandle
定数を使用します。
コール・サイトおよび定数の動的解決方法
次の低レベル情報は、Java仮想マシン仕様の関連部分のサマリーです。 完全な詳細については、この仕様の現在のバージョンを参照してください。動的に計算されたコール・サイト
invokedynamic
命令は、最初はリンク解除された状態です。 この状態では、起動する命令のターゲット・メソッドはありません。
JVMがinvokedynamic
命令を実行するには、最初にlinkedの手順が必要です。 リンクは、呼出しの静的情報コンテンツが与えられた「ブートストラップ法」を呼び出して行い、呼出しの動作を提供するCallSite
を生成する必要があります。
各invokedynamic
命令は、自身のブートストラップ・メソッドを定数プール参照として静的に指定します。 定数プール参照では、invokestatic
のような起動名およびメソッド・タイプの記述子と、その他の呼出し指示も指定します。
動的に計算された定数
定数プールには、CONSTANT_Dynamic
とタグ付けされた定数が含まれ、その解決を実行するブートストラップ・メソッドが備えられています。 このような「動的定数」は当初未解決の状態です。 JVMで動的に計算された定数を使用するには、まず「解決済」にする必要があります。 動的に計算された定数の解決は、定数の静的情報コンテンツを指定し、静的に宣言された定数の値を生成する必要がある「ブートストラップ法」をコールすることで実現されます。
動的に計算される各定数は、その独自のブートストラップ・メソッドを定数プール参照として静的に指定します。 定数プール参照では、getstatic
のような定数名およびフィールド・タイプ記述子も指定し、他のフィールド参照指示も指定します。 (つまり、動的に計算される定数は、CONSTANT_Fieldref
として動的に計算されるコール・サイトになるのは、CONSTANT_Methodref
に対するものです。)
ブートストラップ・メソッドの実行
動的に計算されたコール・サイトまたは定数を解決するには、次のアイテムの定数プールから定数を解決します。- ブートストラップ・メソッド、
CONSTANT_MethodHandle
CONSTANT_NameAndType
記述子のタイプ・コンポーネントから導出されたClass
またはMethodType
- もしあれば、静的引数(静的引数自体が動的に計算される定数である可能性があることに注意してください)
その後、MethodHandle.invoke
の場合と同様に、次の引数を指定してブートストラップ・メソッドが呼び出されます。
MethodHandles.Lookup
(動的に計算された定数または呼出しサイトが発生する「呼び出し元クラス」のルックアップ・オブジェクト)String
(CONSTANT_NameAndType
に示された名前)MethodType
またはClass
(CONSTANT_NameAndType
の解決された型記述子)- 定数の解決された型記述子である
Class
(動的定数の場合) - その他の解決済静的引数(ある場合)
動的に計算されたコール・サイトの場合、戻される結果はCallSite
へのnull以外の参照である必要があります。 コール・サイト・ターゲットの型は、起動タイプ記述子から導出された型と完全に等しく、ブートストラップ・メソッドに渡される必要があります。 これらの条件が満たされない場合は、BootstrapMethodError
がスローされます。 正常に終了すると、呼出しサイトはinvokedynamic
の手順に永続的にリンクされます。
動的に計算される定数の場合、ブートストラップ・メソッドの最初のパラメータをMethodHandles.Lookup
に代入できる必要があります。 この条件が満たされない場合は、BootstrapMethodError
がスローされます。 成功すると、ブートストラップ・メソッドの結果は解決済の定数値としてキャッシュされます。
例外がE
という場合は、ブートストラップ・メソッドの実行中に例外が発生すると、解決は失敗して異常終了します。 E
の型がError
またはサブクラスである場合、E
は再スローされます。そうでない場合は、E
をラップするBootstrapMethodError
がスローされます。 このような場合、後でinvokedynamic
命令を実行したり、動的に計算された定数をロードしようとするたびに、同じエラーがスローされます。
解決のタイミング
invokedynamic
命令は、最初の実行前にリンクされます。 動的に計算される定数は、最初に(スタック上でプッシュするか、ブートストラップ・メソッド・パラメータとしてリンクします)が使用される直前に解決されます。 リンケージを実装するブートストラップ・メソッド・コールは、最初の実行または最初の使用を試行しているスレッド内で発生します。
そのようなスレッドがいくつか存在する場合、ブートストラップ・メソッドがいくつかのスレッド内で並行して呼び出される可能性があります。 したがって、グローバル・アプリケーション・データにアクセスするブートストラップ・メソッドでは、競合状態に対する通常の予防策を講じる必要があります。 いずれにせよ、すべてのinvokedynamic
命令は、リンクされていない状態、一意のCallSite
オブジェクトにリンクされた状態、のいずれかになります。
個別に変更可能な動作を備えたinvokedynamic
命令が必要なアプリケーションでは、ブートストラップ・メソッドはそれぞれ異なるCallSite
オブジェクトを生成すべきです(リンク・リクエストごとに1つずつ)。 また、アプリケーションでは単一のCallSite
オブジェクトをいくつかのinvokedynamic
命令にリンクすることもできますが、その場合、ターゲット・メソッドへの変更がすべての命令で可視になります。
単一の動的計算コール・サイトまたは定数のブートストラップ・メソッドがいくつかのスレッドによって同時に実行された場合、JVMは1つのブートストラップ・メソッドの結果を選択し、それをすべてのスレッドにインストールして可視状態にする必要があります。 他のブートストラップ・メソッド呼出しは完了できますが、その結果は無視されます。
討論:これらのルールでは、JVMがコール・サイトを共有したり、"注意"ブートストラップ・メソッド・コールを発行することはできません。 invokedynamic
命令は、最初の呼出しの直前にリンク解除からリンクされるまで最大1回遷移します。 完了したブートストラップ・メソッド呼出しの効果を取り消す方法はありません。
ブートストラップ・メソッドのタイプ
動的に計算されたコール・サイトの場合、ブートストラップ・メソッドは、パラメータ・タイプがMethodHandles.Lookup
、String
、MethodType
および任意の静的引数の型で起動されます。戻り型はCallSite
です。
動的に計算された定数の場合、ブートストラップ・メソッドは、パラメータ・タイプがMethodHandles.Lookup
、String
、Class
および任意の静的引数の型で呼び出されます。戻り型はClass
によって表される型です。
MethodHandle.invoke
は起動されたメソッド型とブートストラップ・メソッド・ハンドルのメソッド型との間の対応を可能にするため、ブートストラップ・メソッドの宣言には柔軟性があります。 動的に計算される定数の場合、ブートストラップ・メソッド・ハンドルの最初のパラメータ型をMethodHandles.Lookup
に代入できる必要があります。それ以外の制約では、動的に計算されるコール・サイトおよび動的に計算される定数のブートストラップ・メソッドに同じ柔軟性が適用されます。 ノート: この制約により、ブートストラップ・メソッドが静的引数のパラメータ・タイプのみを使用して起動される可能性があるため、静的引数(参照、名前および型のメタデータ・パラメータを宣言しない、または必要としないメソッドなど)と互換性のあるメソッドの範囲がより多くサポートされます。
たとえば、動的に計算される呼出しサイトでは、最初の引数はMethodHandles.Lookup
ではなくObject
であり、戻り型もCallSite
ではなくObject
である可能性があります。 (積上げ引数の型と数によって、適切に型指定された静的メソッドおよびコンストラクタにブートストラップ・メソッドの法的タイプが制限されることに注意してください。)
プッシュ値がプリミティブ型の場合は、ボックス変換によって参照に変換できます。 ブートストラップ・メソッドが可変引数メソッドである(修飾子ビット0x0080
が設定されている)場合、ここに指定された引数の一部または全部が末尾の配列パラメータ内に集められる可能性があります。 (これは特殊なルールでなく、CONSTANT_MethodHandle
定数、可変引数メソッド用の修飾子ビット、およびasVarargsCollector
変換の間の相互作用の有用な結果です。)
これらの規則に基づき、動的に計算されるコール・サイトの正しいブートストラップ・メソッド宣言の例で、様々な数のN
に特別な引数が指定されています。 最初の行(マークされた*
)は任意の数の余分な引数に対して機能します。
N | ブートストラップ・メソッドの例 |
---|---|
* |
|
0 |
|
1 |
CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg) |
2 |
|
String
とInteger
(またはint
)型であると仮定しています。 2番目から最後の例では、余分な引数はすべてString
型であると仮定しています。 その他の例は、あらゆる型の追加引数で動作します。 2番目および3番目の例を除くすべての例では、動的に計算される定数定数を使用して、戻り型が、定数が宣言された型(Object
など、常に互換性がある)であると互換性があるように変更されている場合にも、動的に計算される定数を使用します。
動的に計算される定数は、ブートストラップ・メソッドへの静的引数として提供できるため、ブートストラップ引数の型に制限はありません。 ただし、boolean
型、byte
型、short
またはshort
型の引数は、CONSTANT_Integer
から提供される「直接」の定数プール・エントリでは、asType
の変換は必要ないため、可変サイズ変換は実行できません。
前述の例では、戻り型は常にCallSite
ですが、ブートストラップ・メソッドに必要な機能ではありません。 動的に計算される呼出しサイトの場合、ブートストラップ・メソッドの戻り型が(asType
変換の使用)からCallSite
に変換可能であることのみが必要です。つまり、ブートストラップ・メソッドの戻り型がObject
またはConstantCallSite
になる可能性があります。 動的に解決される定数の場合、ブートストラップ・メソッドの戻り型は、フィールド型記述子で表される定数の型に変換可能である必要があります。 たとえば、動的定数に"C"
(char
)のフィールド・タイプ記述子がある場合、ブートストラップ・メソッドの戻りタイプはObject
、Character
、または、char
であり、int
またはInteger
ではない可能性があります。
- 導入されたバージョン:
- 1.7
-
インタフェースのサマリー インタフェース 説明 MethodHandleInfo 直接メソッド・ハンドルをその構成要素シンボリック部分に解決することによって取得されるシンボリック参照。 -
クラスのサマリー クラス 説明 CallSite CallSite
は、ターゲット
と呼ばれる変数MethodHandle
のホルダーです。ConstantBootstraps 動的に計算される定数のブートストラップ・メソッド。ConstantCallSite ConstantCallSite
は、永続的で決して変更できないターゲットを持つCallSite
です。LambdaMetafactory おそらく型適応と引数の部分評価の後に、指定されたMethodHandle
への委譲によって、1つ以上のインタフェースを実装する単純な関数オブジェクトの作成を容易にするメソッド。MethodHandle メソッド・ハンドルとは、ベースとなるメソッド、コンストラクタ、フィールド、または類似の低レベル操作に対する、直接実行可能な型付きの参照のことであり、オプションで引数や戻り値の変換も行います。MethodHandleProxies このクラスはstaticメソッドのみで構成され、メソッド・ハンドルをインタフェースなどのその他のJVM型に適応させるときに役立ちます。MethodHandles このクラスは、メソッド・ハンドルに対する処理を行うかメソッド・ハンドルを返すstaticメソッドだけで構成されます。MethodHandles.Lookup ルックアップ・オブジェクトは、メソッド・ハンドルの作成にアクセス・チェックが必要な場合のメソッド・ハンドル作成用ファクトリです。MethodType メソッド型は、メソッド・ハンドルが受け取ったり返したりする引数や戻り値の型、あるいはメソッド・ハンドルの呼出し元が渡したり期待したりする引数や戻り値の型を表します。MutableCallSite MutableCallSite
は、ターゲット変数の動作が通常のフィールドと同じであるようなCallSite
です。SerializedLambda ラムダ式の直列化された形式。StringConcatFactory おそらく型適応と引数の部分評価の後に既知の型の既知数の引数を効率的に連結するために使用できる文字列連結メソッドの作成を容易にするメソッド。SwitchPoint SwitchPoint
は、状態遷移をほかのスレッドに発行できるオブジェクトです。VarHandle VarHandleは、変数に対する、あるいはパラメータを用いて指定される変数の一群に対する、動的に強く型付けされた参照です。それら変数には、staticなフィールド、非staticなフィールド、配列の要素、ヒープの外側にあるデータ構造のコンポーネントなどが含まれます。VolatileCallSite VolatileCallSite
は、ターゲットの動作がvolatile変数と同じであるようなCallSite
です。 -
列挙型のサマリー 列挙型 説明 VarHandle.AccessMode VarHandleによって参照される変数へのアクセス方法を指定するアクセス・モードのセット。 -
例外のサマリー 例外 説明 LambdaConversionException LambdaConversionExceptionStringConcatException リンケージ・インバリアントが違反されると、StringConcatExceptionがStringConcatFactory
によってスローされます。WrongMethodTypeException コード内でメソッド・ハンドルを不正なメソッド型経由で呼び出そうとしたことを示すためにスローされます。