Linker
は、JavaプラットフォームのプレビューAPIです。
外部関数は通常、オンデマンドでロードできるライブラリに存在します。 各ライブラリは、特定のABI (アプリケーション・バイナリ・インタフェース)に準拠しています。 ABIは、ライブラリが構築されたコンパイラ、OS、およびプロセッサに関連付けられた呼び出し規則とデータ型のセットです。 たとえば、Linux/x64上のCコンパイラは通常、SystemV ABIに準拠するライブラリを構築します。
リンカーは、特定のABIで使用される呼び出し規則とデータ型について詳細に把握しています。 そのABIに準拠するライブラリの場合、リンカーはJVMで実行されているJavaコードとライブラリ内の外部関数を仲介できます。 特に次の点が重要です。
- リンカーを使用すると、Javaコードは「ダウンコール・メソッド・ハンドル」を介して外部関数とリンクできます
- リンカーを使用すると、外部関数が「アップコール・スタブ」の生成を介してJavaメソッド・ハンドルをコールできます。
libc
とlibm
。 これらのライブラリの関数は、「シンボル・ルックアップ」を介して公開されます。
nativeLinker()
メソッドは、Javaランタイムが現在実行されているOSおよびプロセッサに関連付けられたABIのリンカーを提供します。 このリンカーは、その「デフォルト・ルックアップ」を介して、Javaランタイムとともにロードも提供します。
ダウンコール・メソッドのハンドル
「外部機能のリンク」は、関数記述子、メモリー・レイアウトのセットを必要とするプロセスです。これらを組み合せて、リンクする外部関数のシグネチャを指定し、完了するとダウンコール・メソッド・ハンドル、つまりターゲット外部関数の呼出しに使用できるメソッド・ハンドルを返します。
返されるメソッド・ハンドルに関連付けられたJava 「メソッド・タイプ」は、引数からのderivedであり、関数記述子のレイアウトを返します。 さらに具体的には、関数記述子の各レイアウトL
では、次に示すように、対応するキャリアC
が推測されます:
L
がキャリアE
を持つValueLayout
PREVIEWの場合、次の2つのケースがあります:L
がパラメータ位置で発生し、E
がMemoryAddress.class
の場合、C = Addressable.class
;- otherwise,
C = E
;
- または、
L
がGroupLayout
PREVIEWの場合、C
はMemorySegment.class
に設定されます
前述のとおりに導出されたダウン・コール・メソッド・ハンドル・タイプは、追加の先行パラメータによって、両方が存在する場合、指定された順序で装飾される場合があります:
- ダウンコール・メソッド・ハンドルが「ターゲット・アドレスを指定しない」の場合、ダウンコール・メソッド・ハンドル・タイプは
Addressable
PREVIEWタイプの先行パラメータを備えており、そこからターゲットの外部関数のアドレスを導出できます。 - 関数記述子の戻りレイアウトがグループ・レイアウトの場合、結果のダウンコール・メソッド・ハンドルは、ダウンコール・メソッド・ハンドルによって返される構造体に関連付けられたメモリー・リージョンを割り当てるためにリンカー・ランタイムによって使用される
SegmentAllocator
PREVIEW型の追加の先頭パラメータを受け入れます。
アップコール・スタブ
「アップ・コール・スタブの作成」には、メソッド・ハンドルおよび関数記述子が必要です。この場合、関数記述子内のメモリー・レイアウトのセットによって、upcallスタブに関連付けられた関数ポインタのシグネチャが指定されます。
指定されたメソッド・ハンドルのタイプは、アップコール・スタブに関連付けられたJava 「メソッド・タイプ」をmatchする必要があります。これは、関数記述子の引数および戻りレイアウトから導出されます。 さらに具体的には、関数記述子の各レイアウトL
では、次に示すように、対応するキャリアC
が推測されます:
L
がキャリアE
を持つValueLayout
PREVIEWの場合、次の2つのケースがあります:L
が戻り位置にあり、E
がMemoryAddress.class
の場合、C = Addressable.class
;- Otherwise,
C = E
;
- または、
L
がGroupLayout
PREVIEWの場合、C
はMemorySegment.class
に設定されます
MemorySegment
PREVIEWタイプのインスタンスによってモデル化されます。アップコール・スタブは、他のダウンコール・メソッド・ハンドル(MemorySegment
PREVIEWがAddressable
PREVIEWインタフェースを実装する場合)を参照して渡すことができます。不要になった場合は、関連する「セッション」PREVIEWを介して「リリース済」PREVIEWにできます。
安全に関する考慮事項
ダウンコール・メソッド・ハンドルの作成は本質的に安全ではありません。 一般的に、外部ライブラリ内のシンボルには十分なシグネチャ情報 (例、外部ファンクション・パラメータのアリティおよびタイプ)が含まれていません。 その結果、リンカーのランタイムはリンケージ・リクエストを検証できません。 クライアントが無効なリンケージ・リクエスト(例:引数のレイアウトが多すぎる関数記述子を指定)を介して取得されたダウン・コール・メソッド・ハンドルと対話する場合、このような対話の結果は不特定であり、JVMがクラッシュする可能性があります。 ダウンコール・ハンドルの呼出しでは、リンカー・ランタイムによって、メモリー・リソースR
(タイプMemorySegment
PREVIEWまたはVaList
PREVIEW)である引数に対して次のことが保証されます:
R
のメモリー・セッションは、alivePREVIEWです。 それ以外の場合、呼出しはIllegalStateException
をスローR
のメモリー・セッションが制限されている場合、起動は「所有している」PREVIEWと同じスレッドで実行されます。 それ以外の場合、起動はWrongThreadException
をスローR
のメモリー・セッションは、起動時の「キープ・アライブ」PREVIEW (およびクローズできません)です。
アップ・コール・スタブを作成する場合、リンカー・ランタイムは、指定された関数記述子に対してターゲット・メソッド・ハンドルのタイプを検証し、不一致が検出されるとエラーをレポートします。 ダウンコールの場合、外部コードがアップコール・スタブに関連付けられた関数ポインタを、指定された関数記述子と互換性のない型にキャストすると、JVMがクラッシュすることがあります。 さらに、アップコール・スタブに関連付けられたターゲット・メソッド・ハンドルが「メモリー・アドレス」PREVIEWを返す場合、クライアントは、アップコールの完了後にこのアドレスが無効にならないことを確認する必要があります。 これは、通常、アップ・コールはダウン・コール・メソッド・ハンドルの起動のコンテキストで実行されるため、不特定の動作を引き起こし、JVMがクラッシュする可能性があります。
- 実装要件:
- このインタフェースの実装は不変、スレッド・セーフ、およびvalue-basedです。
- 導入されたバージョン:
- 19
-
メソッドのサマリー
修飾子と型メソッド説明一般的に使用される一連のライブラリ内のシンボル・ルックアップを返します。default MethodHandle
downcallHandle
(AddressablePREVIEW symbol, FunctionDescriptorPREVIEW function) 指定されたシグネチャとアドレスを使用してターゲットの外部関数を呼び出すために使用できるメソッド・ハンドルを作成します。downcallHandle
(FunctionDescriptorPREVIEW function) 指定されたシグネチャでターゲットの外部関数をコールするために使用できるメソッド・ハンドルを作成します。static MethodType
downcallType
(FunctionDescriptorPREVIEW functionDescriptor) 指定された関数記述子に関連付けられているダウンコール・メソッド・ハンドルtypeを返します。基礎となるネイティブ・プラットフォームに関連付けられたABIのリンカーを返します。upcallStub
(MethodHandle target, FunctionDescriptorPREVIEW function, MemorySessionPREVIEW session) 指定されたメモリー・セッションを使用して、関数ポインタとしてほかの外部関数に渡すことができるスタブを作成します。static MethodType
upcallType
(FunctionDescriptorPREVIEW functionDescriptor) 指定された関数記述子を持つアップコール・スタブに関連付けられたメソッド・ハンドルtypeを返します。
-
メソッドの詳細
-
nativeLinker
基礎となるネイティブ・プラットフォームに関連付けられたABIのリンカーを返します。 基礎となるネイティブ・プラットフォームは、Javaランタイムが現在実行されているOSとプロセッサの組合せです。返されたリンカーと対話する場合、クライアントは引数および戻りレイアウトを次のように指定する
function descriptor
PREVIEWを使用して、外部関数のシグネチャを記述する必要があります:- スカラー・タイプは、適切なキャリアの「値レイアウト」PREVIEWインスタンスによってモデル化されます。 Cのスカラー型の例は、
int
,long
,size_t
などです。スカラー・タイプとそれに対応するレイアウト間のマッピングは、返されたリンカーのABIに依存 - コンポジット・タイプは、「グループ・レイアウト」PREVIEWによってモデル化されます。 返されたリンカーのABIによっては、C (例、
struct
またはunion
を使用)内のコンポジット・タイプ定義のサイズおよび整列制約に準拠するために、追加のpaddingPREVIEWメンバー・レイアウトが必要になる場合があります - ポインタ・タイプは、キャリア
MemoryAddress
PREVIEWを持つ「値レイアウト」PREVIEWインスタンスによってモデル化されます。 Cのポインタ型の例には、int**
とint(*)(size_t*, size_t*)
があります
前述にリストされていないレイアウトは「未サポート」です。サポートされていないレイアウトを含むファンクション記述子によって、
downcall method handle
または「アップコール・スタブ」の作成に使用するとIllegalArgumentException
がスローされます。可変個関数(例、末尾の省略記号
...
を使用して宣言されたC関数(仮パラメータ・リストの最後または空の仮パラメータ・リストを使用))は直接サポートされません。 ただし、「可変個」PREVIEW関数記述子を使用して、可変アリ・ティー呼び出しサイトの特殊なシグネチャを完全に記述することによって、可変個関数をリンクできます。 または、外部ライブラリで許可されている場合、クライアントはタイプVaList
PREVIEW (例、vsprintf
のように)の末尾のパラメータを渡すことで、可変個関数と対話できる可能性があります。このメソッドは「制限付き」です。 制限されたメソッドは安全ではなく、誤って使用するとJVMがクラッシュしたり、悪化したりするとメモリーが破損する可能性があります。 したがって、クライアントは制限付きメソッドに応じて屈折し、可能な場合は安全でサポートされている機能を使用する必要があります。
- APIのノート:
- 現在、OSとプロセッサの異なる組み合わせに対してリンカーを取得することはできません。
- 実装上のノート:
- 返されるリンカーに関連付けられた「デフォルト・ルックアップ」によって公開されるライブラリは、Javaランタイムが現在実行されているプロセスにロードされるネイティブ・ライブラリです。 たとえば、Linuxの場合、これらのライブラリには通常、
libc
、libm
およびlibdl
が含まれます。 - 戻り値:
- Javaランタイムが現在実行されているOSおよびプロセッサに関連付けられたABIのリンカー。
- 例外:
UnsupportedOperationException
- 基盤となるネイティブ・プラットフォームがサポートされていない場合。IllegalCallerException
- このメソッドへのアクセスがモジュールM
から発生し、コマンドライン・オプション--enable-native-access
が指定されているが、モジュール名M
、またはM
が無名モジュールの場合はALL-UNNAMED
が指定されていない場合。
- スカラー・タイプは、適切なキャリアの「値レイアウト」PREVIEWインスタンスによってモデル化されます。 Cのスカラー型の例は、
-
downcallHandle
default MethodHandle downcallHandle(AddressablePREVIEW symbol, FunctionDescriptorPREVIEW function) 指定されたシグネチャとアドレスを使用してターゲットの外部関数を呼び出すために使用できるメソッド・ハンドルを作成します。指定されたメソッド・タイプの戻り型が
MemorySegment
の場合、結果のメソッド・ハンドルは、SegmentAllocator
PREVIEW型の追加プリフィクス・パラメータを備えており、リンカー・ランタイムによって値が戻される構造体を割り当てるために使用されます。このメソッドの呼出しは、次のコードと同じです:
linker.downcallHandle(function).bindTo(symbol);
- パラメータ:
symbol
- ターゲット関数のアドレス。function
- ターゲット関数の関数記述子。- 戻り値:
- ダウンコール・メソッド・ハンドル。 メソッド・ハンドル・タイプは「推測」です
- 例外:
IllegalArgumentException
- 指定された関数記述子がこのリンカーでサポートされていない場合、またはシンボルがMemoryAddress.NULL
PREVIEWの場合
-
downcallHandle
MethodHandle downcallHandle(FunctionDescriptorPREVIEW function) 指定されたシグネチャでターゲットの外部関数をコールするために使用できるメソッド・ハンドルを作成します。 結果のメソッド・ハンドルは、Addressable
PREVIEW型の外部関数エントリ・ポイントに対応するプレフィクス・パラメータ(最初のパラメータとして)を備えており、コールされるターゲット関数のアドレスを指定するために使用されます。指定された関数記述子の戻りレイアウトが
GroupLayout
PREVIEWの場合、結果として得られるメソッド・ハンドルは、SegmentAllocator
PREVIEW型の追加のプレフィクス・パラメータ(addressパラメータの直後に挿入されます)を備えており、リンカー・ランタイムによって値が戻される構造体を割り当てるために使用されます。戻されたメソッド・ハンドルは、渡された
Addressable
PREVIEWパラメータがMemoryAddress.NULL
PREVIEWアドレスに関連付けられている場合はIllegalArgumentException
を、そのパラメータがnull
の場合はNullPointerException
をスローします。- パラメータ:
function
- ターゲット関数の関数記述子。- 戻り値:
- ダウンコール・メソッド・ハンドル。 メソッド・ハンドル・タイプは、指定された関数記述子から「推測」です。
- 例外:
IllegalArgumentException
- 指定された関数記述子がこのリンカーでサポートされていない場合。
-
upcallStub
MemorySegmentPREVIEW upcallStub(MethodHandle target, FunctionDescriptorPREVIEW function, MemorySessionPREVIEW session) 指定されたメモリー・セッションを使用して、関数ポインタとしてほかの外部関数に渡すことができるスタブを作成します。 このような関数ポインタを外部コードから呼び出すと、指定されたメソッド・ハンドルが実行されます。返されるメモリー・セグメントのベース・アドレスは、新しく割り当てられたアップコール・スタブを指し、指定されたメモリー・セッションに関連付けられます。 そのようなセッションが終了すると、対応するアップコール・スタブの割り当てが解除されます。
ターゲット・メソッド・ハンドルは例外をスローしません。 ターゲット・メソッド・ハンドルが例外をスローすると、VMはゼロ以外の終了コードで終了します。 例外の捕捉が原因でVMが中断しないように、クライアントは、
Throwable
を捕捉するtry/catchブロック内のターゲット・メソッド・ハンドル内のすべてのコードをラップできます。たとえば、MethodHandles.catchException(MethodHandle, Class, MethodHandle)
メソッド・ハンドル・コンビネータを使用し、対応するcatchブロックで必要に応じて例外を処理します。- パラメータ:
target
- ターゲット・メソッド・ハンドル。function
- upcallスタブ関数記述子。session
- アップコール・スタブ・メモリー・セッション。- 戻り値:
- ベース・アドレスがアップコール・スタブのアドレスであるゼロ長セグメント。
- 例外:
IllegalArgumentException
- 指定された関数記述子がこのリンカーでサポートされていない場合。IllegalArgumentException
- ターゲット・メソッド・ハンドルが例外をスローできると判断された場合、またはターゲット・メソッド・ハンドルにアップコール・スタブ「推測タイプ」と一致しないタイプがある場合。IllegalStateException
-session
がalivePREVIEWでない場合。WrongThreadException
- このメソッドが、session
を「所有している」PREVIEWスレッド以外のスレッドからコールされる場合。
-
defaultLookup
SymbolLookupPREVIEW defaultLookup()一般的に使用される一連のライブラリ内のシンボル・ルックアップを返します。各
Linker
PREVIEWは、Linker
PREVIEWでサポートされているOSとプロセッサの組合せで広く認識されているライブラリを選択します。 したがって、シンボル・ルックアップによって公開されるシンボルの正確なセットは指定されず、Linker
PREVIEWによって異なります。- 実装上のノート:
defaultLookup()
の結果は、時間の経過とともに安定している一連の記号を公開することを強くお薦めします。 以前にシンボル・ルックアップによって公開されたシンボルが公開されなくなった場合、defaultLookup()
のクライアントは失敗する可能性があります。実装者が複数のOSとプロセッサの組合せに対して
Linker
PREVIEW実装を提供する場合、defaultLookup()
の結果が、すべてのOSとプロセッサの組合せにわたって一貫した一連の記号を可能なかぎり公開することを強くお薦めします。- 戻り値:
- 一般的に使用される一連のライブラリ内のシンボルのシンボル・ルックアップ。
-
downcallType
static MethodType downcallType(FunctionDescriptorPREVIEW functionDescriptor) 指定された関数記述子に関連付けられているダウンコール・メソッド・ハンドルtypeを返します。- パラメータ:
functionDescriptor
- 関数記述子。- 戻り値:
- 指定された関数記述子に関連付けられているダウンコール・メソッド・ハンドルtype
- 例外:
IllegalArgumentException
- 関数記述子内の1つ以上のレイアウトがサポートされていない場合、(例:シーケンス・レイアウトまたはパディング・レイアウトの場合)。
-
upcallType
static MethodType upcallType(FunctionDescriptorPREVIEW functionDescriptor) 指定された関数記述子を持つアップコール・スタブに関連付けられたメソッド・ハンドルtypeを返します。- パラメータ:
functionDescriptor
- 関数記述子。- 戻り値:
- 指定された関数記述子を持つアップコール・スタブに関連付けられたメソッド・ハンドルtype
- 例外:
IllegalArgumentException
- 関数記述子内の1つ以上のレイアウトがサポートされていない場合、(例:シーケンス・レイアウトまたはパディング・レイアウトの場合)。
-
Linker
を使用できます。