モジュール jdk.dynalink
Dynalinkは、オブジェクトに対する高レベルの操作を動的にリンクするためのライブラリです。 これらの操作には、"read a property"、"write a property"、"invoke a function"などがあります。 Dynalinkは主に、少なくとも一部の式に動的型(つまり、静的に決定できない型)があり、動的型に対する操作がコール・サイトとして表されるプログラミング言語の実装に役立ちます。 これらのコール・サイトは、式が評価される値の実際の型に基づいて、実行時に適切なターゲット・メソッド・ハンドルにリンクされます。 これらは呼出し間で変更される可能性があり、新しいタイプに対応するためにコール・サイトを複数回再リンクする必要があります。Dynalinkはそれ以上のすべてを処理します。
Dynalinkでは、JVMのクラスベース・モデルとは(根本的に)異なっていて、カスタム型変換を持つオブジェクト・モデルを使用したプログラミング言語の実装をサポートしています。
Dynalinkは、java.lang.invokeパッケージと密接に関連しており、それに依存しています。
java.lang.invokeは、invokedynamicコール・サイトの動的リンクのための低レベルのAPIを提供しますが、オブジェクトに対する高レベルの操作や、それらを実装するメソッドを表現する方法は提供しません。 これらの操作は、オブジェクト指向環境での通常の操作です。プロパティ・アクセス、コレクションの要素へのアクセス、メソッドおよびコンストラクタの起動(Javaオーバーロード・メソッド解決のリンクおよびランタイム等価など、複数のディスパッチがある可能性があります)。 これらはすべて、通常JVM上の言語で必要とされる関数です。 言語が静的に型指定され、その型システムがJVMの型と一致する場合、通常の呼出しやフィールド・アクセスなどの命令(invokevirtual、getfieldなど)を使用してこれを実現できます。 ただし、言語が動的(したがって、一部の式のタイプは実行時に評価されるまでわからない)、またはそのオブジェクト・モデルまたはタイプ・システムがJVMと密接に一致しない場合は、かわりにinvokedynamicコール・サイトを使用し、Dynalinkでそれらを管理する必要があります。
例
Dynalinkはおそらく、その使用例によって最もよく説明されています。 オブジェクトのタイプを宣言する必要がなく、そのオブジェクトのプロパティにアクセスしたい言語のプログラムがあるとします。var color = obj.color;前述の1行プログラムを表すJavaクラスを生成した場合、そのバイトコードは次のようになります。
aload 2 // load "obj" on stack invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type astore 3 // store the return value into local variable "color"
invokedynamic命令をリンクするには、ブートストラップ・メソッドが必要です。 Dynalinkを使用したミニマリスト・ブートストラップ・メソッドは次のようになります。
import java.lang.invoke.*;
import jdk.dynalink.*;
import jdk.dynalink.support.*;
class MyLanguageRuntime {
private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
return dynamicLinker.link(
new SimpleRelinkableCallSite(
new CallSiteDescriptor(lookup, parseOperation(name), type)));
}
private static Operation parseOperation(String name) {
...
}
}
前述のコード・スニペットには、いくつかの重要なオブジェクトがあります。
DynamicLinkerは、Dynalinkのメイン・オブジェクトで、コール・サイトと、コール・サイトで指定した操作を実装するメソッド・ハンドルとのリンクを調整します。 これは、DynamicLinkerFactoryを使用して構成および作成されます。- ブートストラップ・メソッドが呼び出されると、
CallSiteオブジェクトを作成する必要があります。 Dynalinkでは、これらのコール・サイトがさらにRelinkableCallSiteインタフェースを実装する必要があります。 ここで「再リンク可能」は、コール・サイトが実行時に異なる型のオブジェクトを検出した場合、そのターゲットが、新しく検出された型に対して操作を実行できるメソッド・ハンドルに変更されるという事実を暗示しています。SimpleRelinkableCallSiteとChainedCallSite(前述の例では使用されていません)は、ライブラリによってすでに提供されている2つの実装です。 - Dynalinkは、
CallSiteDescriptorオブジェクトを使用して、ブートストラップ・メソッドのパラメータ(ルックアップおよびメソッド・タイプ)を保持します。これは、コール・サイトを再リンクする必要があるときに必要になるためです。 - Dynalinkは、
Operationオブジェクトを使用して動的操作を表現します。 ただし、コール・サイトで操作をエンコードする方法は規定されていません。 そのため、前述の例では、parseOperation関数は空のままであり、コール・サイトの名前の文字列"GET:PROPERTY:color"を解析するコードを、StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")という名前のプロパティgetter操作オブジェクトに指定する必要があります。
上記の設定で何ができますか? デフォルトでは、DynamicLinkerFactoryは、Javaオブジェクトを通常のJavaセマンティクスにリンクできるDynamicLinkerを作成します。 次の3つの単純なクラスがある場合:
public class A {
public String color;
public A(String color) { this.color = color; }
}
public class B {
private String color;
public B(String color) { this.color = color; }
public String getColor() { return color; }
}
public class C {
private int color;
public C(int color) { this.color = color; }
public int getColor() { return color; }
}
また、なんらかの方法でインスタンスを作成し、それらをプログラミング言語でコール・サイトに渡します。
for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
print(obj.color);
}
次に、最初の呼出しで、Dynalinkは.colorゲッター操作をA.colorのフィールド・ゲッターにリンクし、2回目の呼出しではStringを戻すB.getColor()に再リンクし、3回目の呼出しではintを戻すC.getColor()に再リンクします。 前述で使用したSimpleRelinkableCallSiteは、最後に検出された型のリンケージのみを記憶します(モノモーフィック・インライン・キャッシュと呼ばれるものを実装します)。 もう1つのすでに提供されている実装であるChainedCallSiteは、複数の異なるタイプのリンケージを記憶します(これは多相インライン・キャッシュです)。また、深刻なアプリケーションでは、おそらくより適切な選択です。
ダイナリンクとバイトコードの作成
CallSiteオブジェクトは、通常、バイトコード内のinvokedynamic命令のブートストラップの一部として作成されます。 したがって、Dynalinkは通常、プログラムをJava .classバイトコード形式にコンパイルする言語ランタイムの一部として使用されます。 Dynalinkは、バイトコード・クラスの作成またはJVMへのロードのどちらの側面にも対応していません。 つまり、Dynalinkは、CallSiteオブジェクトを明示的に作成し、それらをインタプリタ・プログラム内の動的操作の表現に関連付けることで、バイトコード・コンパイルなし(言語インタプリタなど)でも使用できます(たとえば、典型的な表現は構文ツリー内のノード・オブジェクトです)。
使用可能な操作
Dynalinkは、そのStandardOperationクラスでいくつかの標準操作を定義します。 Javaオブジェクトのリンカーは、これらのすべての操作をリンクできます。また、少なくともこれらの操作をサポートし、ご使用の言語でも使用することを推奨します。 標準操作GETおよびSETは、少なくとも1つのNamespaceと組み合せる必要があります。たとえば、プロパティ・ゲッターを表現するには、StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)を使用します。 Dynalinkは、StandardNamespaceクラスに3つの標準ネームスペースを定義します。 固定名と操作を関連付けるには、前の例のようにNamedOperationを使用できます。StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")は、colorという名前のプロパティのgetterを表します。
複数のネームスペースに対する操作
一部の言語では、プロパティ、要素およびメソッドのオブジェクトに別々のネームスペースがない場合があります。また、ソース言語構成では、それらのいくつかを一度に対処できます。 Dynalinkでは、NamespaceOperationを使用して複数のNamespaceオブジェクトを指定することがサポートされています。
言語固有のリンカー
JVMクラスベースのモデルとは異なる独自のオブジェクト・モデルを定義したり、独自の型変換を使用する言語は、独自の言語固有のリンカーを作成する必要があります。 はじめに、jdk.dynalink.linkerパッケージおよび特に GuardingDynamicLinkerインタフェースを参照してください。
DynalinkおよびJavaオブジェクト
DynamicLinkerFactoryによってデフォルトで作成されるDynamicLinkerオブジェクトには、BeansLinkerの内部インスタンスが含まれます。これは、前述のすべての操作に対して通常のJavaセマンティクスを実装する言語固有のリンカーであり、他の言語固有のリンカーでリンクが管理されていないJavaオブジェクトをリンクできます。 このように、すべての言語ランタイムには、通常のJavaオブジェクトとの相互運用性が組み込まれています。 様々な操作をリンクする方法の詳細は、BeansLinkerを参照してください。
言語間の相互運用性
DynamicLinkerFactoryは、クラス・ローダーで構成できます。 これは、そのクラス・ローダーから参照可能なすべてのGuardingDynamicLinkerExporterクラスをインスタンス化し、それらが提供するリンカーを作成したDynamicLinkerに構成しようとします。 これにより、2つの言語ランタイムAとBがJVMにデプロイされ、前述のメカニズムを介してリンカーをエクスポートする場合、言語ランタイムAはBの言語固有のリンカー・インスタンスを持ち、その逆もDynamicLinkerオブジェクト内に存在します。 つまり、言語ランタイムBのオブジェクトが言語ランタイムAからコードに渡されると、Bのリンカーは、Bからオブジェクトを検出したときにAのコール・サイトをリンクする機会を得ます。 -
-
パッケージ
エクスポート パッケージ 説明 jdk.dynalink invokedynamicコール・サイトのリンクに使用されるインタフェースおよびクラスが含まれます。jdk.dynalink.beans 通常のJavaオブジェクトのリンカーが含まれます。jdk.dynalink.linker 独自の言語固有のオブジェクト・モデルおよび型変換を実装するために言語ランタイムに必要なインタフェースおよびクラスが含まれます。jdk.dynalink.linker.support 一部のクラスおよび様々なユーティリティの基本的な実装を提供することで、言語ランタイムが独自の言語固有のオブジェクト・モデルおよび型変換を実装しやすくするクラスが含まれています。jdk.dynalink.support 一部のクラスおよび様々なユーティリティの基本的な実装を提供することで、Dynalinkの使用をより便利にするクラスが含まれています。
-
サービス
使用 型 説明 GuardingDynamicLinkerExporter 他の言語ランタイムによって自動的にロードできる動的リンカーを保護するサプライヤとして機能するクラス。
-
