モジュール java.base
パッケージ java.lang.foreign

インタフェースLinker


public sealed interface Linker
Linkerは、JavaプラットフォームのプレビューAPIです。
プレビュー機能が有効な場合のみ、プログラムでLinkerを使用できます。
プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
リンカーは、Javaコードから外部関数にアクセスでき、外部関数からJavaコードにアクセスできます。

外部関数は通常、オンデマンドでロードできるライブラリに存在します。 各ライブラリは、特定のABI (アプリケーション・バイナリ・インタフェース)に準拠しています。 ABIは、ライブラリが構築されたコンパイラ、OS、およびプロセッサに関連付けられた呼び出し規則とデータ型のセットです。 たとえば、Linux/x64上のCコンパイラは通常、SystemV ABIに準拠するライブラリを構築します。

リンカーは、特定のABIで使用される呼び出し規則とデータ型について詳細に把握しています。 そのABIに準拠するライブラリの場合、リンカーはJVMで実行されているJavaコードとライブラリ内の外部関数を仲介できます。 特に次の点が重要です。

さらに、リンカーはABIに準拠するライブラリ内の外部関数を検索する方法も提供します。 各リンカーは、ABIに関連付けられたOSとプロセッサの組み合わせで一般的に使用されるライブラリ・セットを選択します。 たとえば、Linux/x64のリンカーは2つのライブラリを選択できます: libclibm これらのライブラリの関数は、「シンボル・ルックアップ」を介して公開されます。

nativeLinker()メソッドは、Javaランタイムが現在実行されているOSおよびプロセッサに関連付けられたABIのリンカーを提供します。 このリンカーは、その「デフォルト・ルックアップ」を介して、Javaランタイムとともにロードも提供します。

ダウンコール・メソッドのハンドル

「外部機能のリンク」は、関数記述子、メモリー・レイアウトのセットを必要とするプロセスです。これらを組み合せて、リンクする外部関数のシグネチャを指定し、完了するとダウンコール・メソッド・ハンドル、つまりターゲット外部関数の呼出しに使用できるメソッド・ハンドルを返します。

返されるメソッド・ハンドルに関連付けられたJava 「メソッド・タイプ」は、引数からのderivedであり、関数記述子のレイアウトを返します。 さらに具体的には、関数記述子の各レイアウトLでは、次に示すように、対応するキャリアCが推測されます:

  • LがキャリアEを持つValueLayoutPREVIEWの場合、次の2つのケースがあります:
    • Lがパラメータ位置で発生し、EMemoryAddress.classの場合、C = Addressable.class ;
    • otherwise, C = E;
  • または、LGroupLayoutPREVIEWの場合、CMemorySegment.classに設定されます

前述のとおりに導出されたダウン・コール・メソッド・ハンドル・タイプは、追加の先行パラメータによって、両方が存在する場合、指定された順序で装飾される場合があります:

  • ダウンコール・メソッド・ハンドルが「ターゲット・アドレスを指定しない」の場合、ダウンコール・メソッド・ハンドル・タイプはAddressablePREVIEWタイプの先行パラメータを備えており、そこからターゲットの外部関数のアドレスを導出できます。
  • 関数記述子の戻りレイアウトがグループ・レイアウトの場合、結果のダウンコール・メソッド・ハンドルは、ダウンコール・メソッド・ハンドルによって返される構造体に関連付けられたメモリー・リージョンを割り当てるためにリンカー・ランタイムによって使用されるSegmentAllocatorPREVIEW型の追加の先頭パラメータを受け入れます。

アップコール・スタブ

「アップ・コール・スタブの作成」には、メソッド・ハンドルおよび関数記述子が必要です。この場合、関数記述子内のメモリー・レイアウトのセットによって、upcallスタブに関連付けられた関数ポインタのシグネチャが指定されます。

指定されたメソッド・ハンドルのタイプは、アップコール・スタブに関連付けられたJava 「メソッド・タイプ」matchする必要があります。これは、関数記述子の引数および戻りレイアウトから導出されます。 さらに具体的には、関数記述子の各レイアウトLでは、次に示すように、対応するキャリアCが推測されます:

  • LがキャリアEを持つValueLayoutPREVIEWの場合、次の2つのケースがあります:
    • Lが戻り位置にあり、EMemoryAddress.classの場合、C = Addressable.class ;
    • Otherwise, C = E;
  • または、LGroupLayoutPREVIEWの場合、CMemorySegment.classに設定されます
アップコール・スタブは、MemorySegmentPREVIEWタイプのインスタンスによってモデル化されます。アップコール・スタブは、他のダウンコール・メソッド・ハンドル(MemorySegmentPREVIEWAddressablePREVIEWインタフェースを実装する場合)を参照して渡すことができます。不要になった場合は、関連する「セッション」PREVIEWを介して「リリース済」PREVIEWにできます。

安全に関する考慮事項

ダウンコール・メソッド・ハンドルの作成は本質的に安全ではありません。 一般的に、外部ライブラリ内のシンボルには十分なシグネチャ情報 (例、外部ファンクション・パラメータのアリティおよびタイプ)が含まれていません。 その結果、リンカーのランタイムはリンケージ・リクエストを検証できません。 クライアントが無効なリンケージ・リクエスト(例:引数のレイアウトが多すぎる関数記述子を指定)を介して取得されたダウン・コール・メソッド・ハンドルと対話する場合、このような対話の結果は不特定であり、JVMがクラッシュする可能性があります。 ダウンコール・ハンドルの呼出しでは、リンカー・ランタイムによって、メモリー・リソースR (タイプMemorySegmentPREVIEWまたはVaListPREVIEW)である引数に対して次のことが保証されます:

アップ・コール・スタブを作成する場合、リンカー・ランタイムは、指定された関数記述子に対してターゲット・メソッド・ハンドルのタイプを検証し、不一致が検出されるとエラーをレポートします。 ダウンコールの場合、外部コードがアップコール・スタブに関連付けられた関数ポインタを、指定された関数記述子と互換性のない型にキャストすると、JVMがクラッシュすることがあります。 さらに、アップコール・スタブに関連付けられたターゲット・メソッド・ハンドルが「メモリー・アドレス」PREVIEWを返す場合、クライアントは、アップコールの完了後にこのアドレスが無効にならないことを確認する必要があります。 これは、通常、アップ・コールはダウン・コール・メソッド・ハンドルの起動のコンテキストで実行されるため、不特定の動作を引き起こし、JVMがクラッシュする可能性があります。

実装要件:
このインタフェースの実装は不変、スレッド・セーフ、およびvalue-basedです。
導入されたバージョン:
19
  • メソッドの詳細

    • nativeLinker

      static LinkerPREVIEW nativeLinker()
      基礎となるネイティブ・プラットフォームに関連付けられたABIのリンカーを返します。 基礎となるネイティブ・プラットフォームは、Javaランタイムが現在実行されているOSとプロセッサの組合せです。

      返されたリンカーと対話する場合、クライアントは引数および戻りレイアウトを次のように指定するfunction descriptorPREVIEWを使用して、外部関数のシグネチャを記述する必要があります:

      • スカラー・タイプは、適切なキャリアの「値レイアウト」PREVIEWインスタンスによってモデル化されます。 Cのスカラー型の例は、int, long, size_tなどです。スカラー・タイプとそれに対応するレイアウト間のマッピングは、返されたリンカーのABIに依存
      • コンポジット・タイプは、「グループ・レイアウト」PREVIEWによってモデル化されます。 返されたリンカーのABIによっては、C (例、structまたはunionを使用)内のコンポジット・タイプ定義のサイズおよび整列制約に準拠するために、追加のpaddingPREVIEWメンバー・レイアウトが必要になる場合があります
      • ポインタ・タイプは、キャリアMemoryAddressPREVIEWを持つ「値レイアウト」PREVIEWインスタンスによってモデル化されます。 Cのポインタ型の例には、int**int(*)(size_t*, size_t*)があります

      前述にリストされていないレイアウトは「未サポート」です。サポートされていないレイアウトを含むファンクション記述子によって、downcall method handleまたは「アップコール・スタブ」の作成に使用するとIllegalArgumentExceptionがスローされます。

      可変個関数(例、末尾の省略記号...を使用して宣言されたC関数(仮パラメータ・リストの最後または空の仮パラメータ・リストを使用))は直接サポートされません。 ただし、可変個PREVIEW関数記述子を使用して、可変アリ・ティー呼び出しサイトの特殊なシグネチャを完全に記述することによって、可変個関数をリンクできます。 または、外部ライブラリで許可されている場合、クライアントはタイプVaListPREVIEW (例、vsprintfのように)の末尾のパラメータを渡すことで、可変個関数と対話できる可能性があります。

      このメソッドは制限付きです。 制限されたメソッドは安全ではなく、誤って使用するとJVMがクラッシュしたり、悪化したりするとメモリーが破損する可能性があります。 したがって、クライアントは制限付きメソッドに応じて屈折し、可能な場合は安全でサポートされている機能を使用する必要があります。

      APIのノート:
      現在、OSとプロセッサの異なる組み合わせに対してリンカーを取得することはできません。
      実装上のノート:
      返されるリンカーに関連付けられた「デフォルト・ルックアップ」によって公開されるライブラリは、Javaランタイムが現在実行されているプロセスにロードされるネイティブ・ライブラリです。 たとえば、Linuxの場合、これらのライブラリには通常、libclibmおよびlibdlが含まれます。
      戻り値:
      Javaランタイムが現在実行されているOSおよびプロセッサに関連付けられたABIのリンカー。
      例外:
      UnsupportedOperationException - 基盤となるネイティブ・プラットフォームがサポートされていない場合。
      IllegalCallerException - このメソッドへのアクセスがモジュールMから発生し、コマンドライン・オプション--enable-native-accessが指定されているが、モジュール名M、またはMが無名モジュールの場合はALL-UNNAMEDが指定されていない場合。
    • downcallHandle

      default MethodHandle downcallHandle(AddressablePREVIEW symbol, FunctionDescriptorPREVIEW function)
      指定されたシグネチャとアドレスを使用してターゲットの外部関数を呼び出すために使用できるメソッド・ハンドルを作成します。

      指定されたメソッド・タイプの戻り型がMemorySegmentの場合、結果のメソッド・ハンドルは、SegmentAllocatorPREVIEW型の追加プリフィクス・パラメータを備えており、リンカー・ランタイムによって値が戻される構造体を割り当てるために使用されます。

      このメソッドの呼出しは、次のコードと同じです:

      linker.downcallHandle(function).bindTo(symbol);
      

      パラメータ:
      symbol - ターゲット関数のアドレス。
      function - ターゲット関数の関数記述子。
      戻り値:
      ダウンコール・メソッド・ハンドル。 メソッド・ハンドル・タイプは推測です
      例外:
      IllegalArgumentException - 指定された関数記述子がこのリンカーでサポートされていない場合、またはシンボルがMemoryAddress.NULLPREVIEWの場合
    • downcallHandle

      MethodHandle downcallHandle(FunctionDescriptorPREVIEW function)
      指定されたシグネチャでターゲットの外部関数をコールするために使用できるメソッド・ハンドルを作成します。 結果のメソッド・ハンドルは、AddressablePREVIEW型の外部関数エントリ・ポイントに対応するプレフィクス・パラメータ(最初のパラメータとして)を備えており、コールされるターゲット関数のアドレスを指定するために使用されます。

      指定された関数記述子の戻りレイアウトがGroupLayoutPREVIEWの場合、結果として得られるメソッド・ハンドルは、SegmentAllocatorPREVIEW型の追加のプレフィクス・パラメータ(addressパラメータの直後に挿入されます)を備えており、リンカー・ランタイムによって値が戻される構造体を割り当てるために使用されます。

      戻されたメソッド・ハンドルは、渡されたAddressablePREVIEWパラメータがMemoryAddress.NULLPREVIEWアドレスに関連付けられている場合はIllegalArgumentExceptionを、そのパラメータがnullの場合はNullPointerExceptionをスローします。

      パラメータ:
      function - ターゲット関数の関数記述子。
      戻り値:
      ダウンコール・メソッド・ハンドル。 メソッド・ハンドル・タイプは、指定された関数記述子から推測です。
      例外:
      IllegalArgumentException - 指定された関数記述子がこのリンカーでサポートされていない場合。
    • upcallStub

      指定されたメモリー・セッションを使用して、関数ポインタとしてほかの外部関数に渡すことができるスタブを作成します。 このような関数ポインタを外部コードから呼び出すと、指定されたメソッド・ハンドルが実行されます。

      返されるメモリー・セグメントのベース・アドレスは、新しく割り当てられたアップコール・スタブを指し、指定されたメモリー・セッションに関連付けられます。 そのようなセッションが終了すると、対応するアップコール・スタブの割り当てが解除されます。

      ターゲット・メソッド・ハンドルは例外をスローしません。 ターゲット・メソッド・ハンドルが例外をスローすると、VMはゼロ以外の終了コードで終了します。 例外の捕捉が原因でVMが中断しないように、クライアントは、Throwableを捕捉するtry/catchブロック内のターゲット・メソッド・ハンドル内のすべてのコードをラップできます。たとえば、MethodHandles.catchException(MethodHandle, Class, MethodHandle)メソッド・ハンドル・コンビネータを使用し、対応するcatchブロックで必要に応じて例外を処理します。

      パラメータ:
      target - ターゲット・メソッド・ハンドル。
      function - upcallスタブ関数記述子。
      session - アップコール・スタブ・メモリー・セッション。
      戻り値:
      ベース・アドレスがアップコール・スタブのアドレスであるゼロ長セグメント。
      例外:
      IllegalArgumentException - 指定された関数記述子がこのリンカーでサポートされていない場合。
      IllegalArgumentException - ターゲット・メソッド・ハンドルが例外をスローできると判断された場合、またはターゲット・メソッド・ハンドルにアップコール・スタブ推測タイプと一致しないタイプがある場合。
      IllegalStateException - sessionalivePREVIEWでない場合。
      WrongThreadException - このメソッドが、session「所有している」PREVIEWスレッド以外のスレッドからコールされる場合。
    • defaultLookup

      SymbolLookupPREVIEW defaultLookup()
      一般的に使用される一連のライブラリ内のシンボル・ルックアップを返します。

      LinkerPREVIEWは、LinkerPREVIEWでサポートされているOSとプロセッサの組合せで広く認識されているライブラリを選択します。 したがって、シンボル・ルックアップによって公開されるシンボルの正確なセットは指定されず、LinkerPREVIEWによって異なります。

      実装上のノート:
      defaultLookup()の結果は、時間の経過とともに安定している一連の記号を公開することを強くお薦めします。 以前にシンボル・ルックアップによって公開されたシンボルが公開されなくなった場合、defaultLookup()のクライアントは失敗する可能性があります。

      実装者が複数のOSとプロセッサの組合せに対してLinkerPREVIEW実装を提供する場合、defaultLookup()の結果が、すべてのOSとプロセッサの組合せにわたって一貫した一連の記号を可能なかぎり公開することを強くお薦めします。

      戻り値:
      一般的に使用される一連のライブラリ内のシンボルのシンボル・ルックアップ。
    • downcallType

      static MethodType downcallType(FunctionDescriptorPREVIEW functionDescriptor)
      指定された関数記述子に関連付けられているダウンコール・メソッド・ハンドルtypeを返します。
      パラメータ:
      functionDescriptor - 関数記述子。
      戻り値:
      指定された関数記述子に関連付けられているダウンコール・メソッド・ハンドルtype
      例外:
      IllegalArgumentException - 関数記述子内の1つ以上のレイアウトがサポートされていない場合、(例:シーケンス・レイアウトまたはパディング・レイアウトの場合)。
    • upcallType

      static MethodType upcallType(FunctionDescriptorPREVIEW functionDescriptor)
      指定された関数記述子を持つアップコール・スタブに関連付けられたメソッド・ハンドルtypeを返します。
      パラメータ:
      functionDescriptor - 関数記述子。
      戻り値:
      指定された関数記述子を持つアップコール・スタブに関連付けられたメソッド・ハンドルtype
      例外:
      IllegalArgumentException - 関数記述子内の1つ以上のレイアウトがサポートされていない場合、(例:シーケンス・レイアウトまたはパディング・レイアウトの場合)。