モジュール java.base

パッケージ java.lang.invoke

java.lang.invokeパッケージには、Javaコア・クラス・ライブラリおよび仮想マシンによって直接提供される動的言語サポートが含まれています。

Java仮想マシン仕様で説明されているように、このパッケージ内の特定の型と、仮想マシンの動的言語サポートには、特別な関係があります。

Java仮想マシンの関連する変更点のサマリー

次の低レベル情報は、Java仮想マシン仕様の関連部分のサマリーです。 完全な詳細については、この仕様の現在のバージョンを参照してください。 invokedynamic命令の個々の出現は動的コール・サイトと呼ばれます。

invokedynamic命令

動的コール・サイトは最初はリンクされていない状態です。 この状態では、コール・サイトが呼び出すべきターゲット・メソッドは存在しません。

JVMが動的コール・サイト(invokedynamic命令)を実行するには、そのコール・サイトをまずリンクする必要があります。 リンクはブートストラップ・メソッドを呼び出すことで実現されますが、このメソッドは、与えられたコール・サイトの静的な情報コンテンツに基づいて、コール・サイトの動作を与えるメソッド・ハンドルを生成する必要があります。

invokedynamic命令は、自身のブートストラップ・メソッドを定数プール参照として静的に指定します。 invokevirtualやその他の呼出し命令の場合とまったく同じく、この定数プール参照はコール・サイトの名前と型記述子も指定します。

リンク処理ではまず、ブートストラップ・メソッドの定数プール・エントリの解決と、動的コール・サイトの型記述子のMethodTypeオブジェクトの解決が行われます。 この解決プロセスでクラスのロード処理がトリガーされる可能性があります。 したがって、クラスのロードに失敗した場合に、エラーがスローされる可能性があります。 このエラーは、動的コール・サイト実行の異常終了になります。 リンクではクラスの初期化はトリガーされません。

ブートストラップ・メソッドの呼出し時には少なくとも3つの値が渡されます。

  • MethodHandles.Lookup (動的コール・サイトの発生元である呼出し元クラス上のルックアップ・オブジェクト)
  • String (コール・サイト内で言及されたメソッド名)
  • MethodType (呼出しの解決済みの型記述子)
  • (オプション)定数プールから取得された1 - 251個の追加の静的引数
呼出しは、MethodHandle.invokeを使用したかのように行われます。 返される結果はCallSite (またはサブクラス)でなければなりません。さもなければBootstrapMethodErrorがスローされます。 コール・サイト・ターゲットの型は、動的呼び出しサイト型記述子から派生した型と正確に等しく、ブートストラップ・メソッドに渡さなければなりません。そうでない場合は、BootstrapMethodErrorがスローされます。 成功すると、コール・サイトはダイナミック・コール・サイトに永続的にリンクされます。

コール・サイトをリンクするときに例外、Eが発生すると、リンケージは失敗し、異常終了します。 E の型がErrorまたはサブクラスである場合、Eは再スローされます。そうでない場合は、EをラップするBootstrapMethodErrorがスローされます。 この場合、ダイナミック・コール・サイトを実行しようとするすべての試行で、同じErrorまたはサブクラスがスローされます。

リンクのタイミング

動的コール・サイトがリンクされるのは、その最初の実行の直前です。 リンクを実装するブートストラップ・メソッドの呼出しが発生するのは、最初の実行を試みているスレッド内です。

そのようなスレッドがいくつか存在する場合、ブートストラップ・メソッドがいくつかのスレッド内で並行して呼び出される可能性があります。 したがって、グローバル・アプリケーション・データにアクセスするブートストラップ・メソッドでは、競合状態に対する通常の予防策を講じる必要があります。 いずれにせよ、すべてのinvokedynamic命令は、リンクされていない状態、一意のCallSiteオブジェクトにリンクされた状態、のいずれかになります。

個別に変更可能な動作を備えた動的コール・サイトが必要なアプリケーションでは、ブートストラップ・メソッドはそれぞれ異なるCallSiteオブジェクトを生成すべきです(リンク要求ごとに1つずつ)。 また、アプリケーションでは単一のCallSiteオブジェクトをいくつかのinvokedynamic命令にリンクすることもできますが、その場合、ターゲット・メソッドへの変更がすべての命令で可視になります。

単一の動的コール・サイトのブートストラップ・メソッドがいくつかのスレッド内で同時に実行された場合、JVMは1つのCallSiteオブジェクトを選択し、それをすべてのスレッドにインストールして可視状態にする必要があります。 ほかのすべてのブートストラップ・メソッド呼出しは完了まで実行を許可されますが、それらの結果は無視され、それらの動的コール・サイト呼出しは、最初に選択されたターゲット・オブジェクトを使って処理されます。

解説: これらのルールにより、JVMが動的コール・サイトの複製や「偶発的な」ブートストラップ・メソッド呼出しの発行を行えるようになるわけではありません。 どの動的コール・サイトでも、未リンクからリンク済みへの遷移は、最初の呼出しの直前に最大1回しか行われません。 完了したブートストラップ・メソッド呼出しの効果を取り消す方法はありません。

ブートストラップ・メソッドの種類

各ブートストラップ・メソッドがMethodHandle.invokeで正しく呼び出せるかぎり、その詳細な型は任意となります。 たとえば、最初の引数をMethodHandles.LookupではなくObjectにしてもかまいませんし、戻り値の型もCallSiteではなくObjectにすることができます。 (スタック内の引数の型と数により、適合するブートストラップ・メソッドの種類が、CallSiteサブクラスの適切に型付けされたstaticメソッドおよびコンストラクタに制限されます。)

特定のinvokedynamic命令に静的な引数が1つも指定されていない場合、その命令のブートストラップ・メソッドが3つの引数(命令の呼出し元クラス、名前、およびメソッド型)で呼び出されます。 invokedynamic命令に1つ以上の静的引数が指定されている場合、それらの値は追加の引数としてメソッド・ハンドルに渡されます。 (すべてのメソッドの引数には255個という上限が存在するので、最大251個の追加引数を指定できます。これは、ブートストラップ・メソッド・ハンドル自体とその最初の3つの引数も、スタックに格納しなければいけないからです。) ブートストラップ・メソッドの呼出しは、MethodHandle.invokeまたはinvokeWithArgumentsのいずれかを使用したかのように行われます。 (その違いを区別する方法はありません。)

MethodHandle.invokeの通常の引数変換ルールが、スタック内のすべての引数に適用されます。 たとえば、プッシュされる値がプリミティブ型であった場合、それはボクシング変換によって参照に変換される可能性があります。 ブートストラップ・メソッドが可変引数メソッドである(修飾子ビット0x0080が設定されている)場合、ここに指定された引数の一部または全部が末尾の配列パラメータ内に集められる可能性があります。 (これは特殊なルールでなく、CONSTANT_MethodHandle定数、可変引数メソッド用の修飾子ビット、およびasVarargsCollector変換の間の相互作用の有用な結果です。)

以上のルールに基づき、追加引数のさまざまな個数Nごとに、正しいブートストラップ・メソッド宣言の例を次に示します。 最初の数行(*の付いたもの)は、任意の数の追加引数で動作します。

静的引数型
Nブートストラップ・メソッドの例
* CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
* CallSite bootstrap(Object... args)
* CallSite bootstrap(Object caller, Object... nameAndTypeWithArgs)
0 CallSite bootstrap(Lookup caller, String name, MethodType type)
0 CallSite bootstrap(Lookup caller, Object... nameAndType)
1 CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
2 CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
2 CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
2 CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)
最後の例では、追加引数の型がそれぞれCONSTANT_StringCONSTANT_Integerであると仮定しています。 最後から2番目の例では、すべての追加引数の型がCONSTANT_Stringであると仮定しています。 その他の例は、あらゆる型の追加引数で動作します。

前述したように、ブートストラップ・メソッドの実際のメソッド型は変更可能です。 たとえば、4番目の引数はMethodHandleでもかまいません(それがCONSTANT_InvokeDynamicエントリ内の対応する定数の型である場合)。 その場合、MethodHandle.invokeの呼出しでは追加メソッド・ハンドル定数がObjectとして渡されますが、MethodHandle.invokeの型一致機構によってその参照が元のMethodHandleにキャストされたあと、ブートストラップ・メソッドが呼び出されます。 (不適切に生成されたコードによって文字列定数が代わりに渡された場合、そのキャストは失敗し、BootstrapMethodErrorが発行されます。)

上記のルールの結果として、ブートストラップ・メソッドを定数プール・エントリで表現できる場合は、それがプリミティブ引数を受け入れる可能性があることに注意してください。 ただし、型がbooleanbyteshort、またはcharの引数をブートストラップ・メソッド用に作成することはできず(そのような定数を定数プールで直接表現することができないため)、ブートストラップ・メソッドを呼び出しても必要なナロー・プリミティブ変換は行われません。

ブートストラップ・メソッドの追加引数の目的は、言語実装者がメタデータのエンコードを安全かつコンパクトに行えるようにすることです。 原則として名前引数や追加引数は冗長になりますが、それは、各コール・サイトにそれぞれ一意のブートストラップ・メソッドが指定される可能性があるからです。 そのような運用ではおそらく、大きなクラス・ファイルや定数プールが生成されます。

導入されたバージョン:
1.7