モジュールjdk.dynalink


モジュールjdk.dynalink
高水準の操作をオブジェクトに動的にリンクするためのAPIを定義します。

Dynalinkは、オブジェクトに対する高レベルの操作を動的にリンクするためのライブラリです。 これらの操作には、"物件を読む"、"プロパティを書く"、"関数を呼び出す"などが含まれます。 Dynalinkは、少なくとも一部の式に動的型(つまり、静的に決定できないタイプ)があり、動的型に対する操作が「コール・サイト」として表されるプログラミング言語の実装に主に役立ちます。 これらのコール・サイトは、式が評価された実際のタイプの値に基づいて、実行時に適切なターゲット「メソッド・ハンドル」にリンクされます。 これらは呼び出し間で変化し、新しいタイプに対応するために呼び出しサイトを複数回再リンクする必要があり、Dynalinkはそれすべてを処理します。

Dynalinkは、JVMのクラス・ベース・モデルと(根本的に)が異なるオブジェクト・モデルとカスタム型変換を持つプログラミング言語の実装をサポートします。

Dynalinkは、java.lang.invokeパッケージと密接に関連しており、それに依存しています。

java.lang.invokeは、invokedynamicコール・サイトの動的リンクのための低レベルのAPIを提供しますが、オブジェクトに対する上位レベルの操作や、それらを実装するメソッドを表現する方法はありません。 これらの操作は、オブジェクト指向環境における通常の操作です: プロパティ・アクセス、コレクションの要素へのアクセス、メソッドの呼出しおよびコンストラクタ(Javaのオーバーロードされたメソッド解決のリンクおよび実行時等価の複数のディスパッチがある可能性があります)。 これらはすべて、JVMの言語で通常必要な関数です。 言語が静的に型指定され、その型システムがJVMのものと一致する場合、通常の呼出し、フィールド・アクセスなどの命令(e.g. 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"を、名前付きプロパティgetter操作オブジェクトにStandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")として解析するコードを指定する必要があります。

すでに上記の設定で何ができますか? デフォルトでは、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 getter操作をA.colorのフィールド・ゲッターにリンクします。2番目の呼出しでは、Stringを返すB.getColor()に再リンクし、3番目の呼出しでは、intを返すC.getColor()に再リンクします。 上記で使用したSimpleRelinkableCallSiteは、最後に検出された型(それは「単相インライン・キャッシュ」として知られているものを実装)のリンケージを覚えています。 すでに提供されている別の実装であるChainedCallSiteは、複数の異なるタイプ(それは「ポリモーフィック・インライン・キャッシュ」です)のリンケージを記憶し、おそらく重大なアプリケーションで適切な選択となります。

CallSiteオブジェクトは、通常、バイトコードのinvokedynamic命令のブートストラップの一部として作成されます。 したがって、Dynalinkは、通常、プログラムをJava .classバイトコード形式にコンパイルする言語ランタイムの一部として使用されます。 Dynalinkは、バイトコード・クラスの作成やJVMへのロードの側面には対応していません。 つまり、Dynalinkは、CallSiteオブジェクトを明示的に作成し、それらを解釈されたプログラム(例えば、代表的な表現は、構文木のいくつかのノード・オブジェクトである)の動的操作の表現に関連付けることで、バイトコード・コンパイル(例:言語インタープリタ)なしでも使用できます。

利用可能な操作

Dynalinkは、StandardOperationクラスでいくつかの標準操作を定義します。 Javaオブジェクトのリンカーは、これらの操作をすべてリンクすることができ、これらの操作を少なくともサポートし、使用している言語でも使用することをお勧めします。 標準操作GETおよびSETは、少なくとも1つのNamespaceと組み合せて使用する必要があります。たとえば、プロパティgetterを表現するには、StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)を使用します。 Dynalinkは、StandardNamespaceクラスに3つの標準ネームスペースを定義します。 固定名を操作に関連付けるには、前の例のようにNamedOperationを使用: StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")は、"color"という名前のプロパティのゲッターを表します。

複数の名前空間に対する操作

一部の言語では、プロパティ、要素およびメソッドのオブジェクトに個別のネームスペースがなく、ソース言語構成では、それらのいくつかに一度に対処できます。 Dynalinkは、複数のNamespaceオブジェクトをNamespaceOperationで指定することをサポートしています。

言語固有のリンカー

JVMクラス・ベースのモデルとは異なる独自のオブジェクト・モデルを定義する言語や、独自の型変換を使用する言語は、独自の言語固有のリンカーを作成する必要があります。 開始するには、jdk.dynalink.linkerパッケージおよび特にGuardingDynamicLinkerインタフェースを参照してください。 DynamicLinkerFactoryによってデフォルトで作成されるDynamicLinkerオブジェクトには、BeansLinkerの内部インスタンスが含まれます。これは、前述のすべての操作に対して通常のJavaセマンティクスを実装し、他の言語固有のリンカーがリンクを管理していないJavaオブジェクトをリンクできる言語固有のリンカーです。 このように、すべての言語ランタイムには、通常のJavaオブジェクトとの相互運用性が組み込まれています。 様々な操作のリンク方法の詳細は、BeansLinkerを参照してください。

言語間の相互運用性

DynamicLinkerFactory「クラス・ローダー」で構成することができます。 そのクラス・ローダーから参照できるすべてのGuardingDynamicLinkerExporterクラスをインスタンス化し、それらが提供しているリンカーを作成したDynamicLinkerに作成しようとします。 これにより、言語間の相互運用性が可能になります: JVMに2つの言語ランタイムAとBがデプロイされており、前述のメカニズムを介してリンカーをエクスポートする場合、言語ランタイムAはBから言語固有のリンカー・インスタンスを持ち、その逆はDynamicLinkerオブジェクト内にあります。 つまり、言語ランタイムBのオブジェクトが言語ランタイムAからコードに渡されると、BのリンカーはBからオブジェクトを検出したときに、Aのコール・サイトをリンクする機会を得ます。
モジュール・グラフ:
jdk.dynalinkのモジュール・グラフjdk.dynalinkのモジュール・グラフ
導入されたバージョン:
9