Java™ Platform
Standard Edition 7

パッケージ java.lang.invoke

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

参照: 説明

パッケージ java.lang.invoke の説明

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

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

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

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

invokedynamic 命令

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

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

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

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

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

呼び出しは、MethodHandle.invoke を使用したかのように行われます。返される結果は、CallSite (またはサブクラス) でなければいけません。このコールサイトのターゲットの型は、動的コールサイトの型記述子から派生されてブートストラップメソッドに渡された型と、厳密に等しくなければいけません。このコールサイトはその後、その動的コールサイトに永続的にリンクされた状態になります。

JVM 仕様にドキュメント化されているように、動的コールサイトのリンクに起因する失敗はすべて BootstrapMethodError として報告されますが、これは、動的コールサイト実行の異常終了としてスローされます。これが発生した場合、動的コールサイトを実行する後続のすべての試みで、同じエラーがスローされます。

リンクのタイミング

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

そのようなスレッドがいくつか存在する場合、ブートストラップメソッドがいくつかのスレッド内で並行して呼び出される可能性があります。したがって、グローバルアプリケーションデータにアクセスするブートストラップメソッドでは、競合状態に対する通常の予防策を講じる必要があります。いずれにせよ、すべての 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)
0CallSite bootstrap(Lookup caller, String name, MethodType type)
0CallSite bootstrap(Lookup caller, Object... nameAndType)
1CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
2CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
2CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
2CallSite 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
Java™ Platform
Standard Edition 7

バグまたは機能を送信
詳細な API リファレンスおよび開発者ドキュメントについては、Java SE のドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.