モジュール 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 これらのライブラリの関数は、「シンボル・ルックアップ」を介して公開されます。

ネイティブ関数の呼び出し

「ネイティブ・リンカー」を使用すると、Cライブラリ (ネイティブ関数)に定義されている関数に対してリンクできます。 Javaから、標準Cライブラリで定義されているstrlen関数に停止するとします:
size_t strlen(const char *s);
次のように、ネイティブ・リンカーを使用して、strlenを公開するダウンコール・メソッド・ハンドルを取得します:
Linker linker = Linker.nativeLinker();
MethodHandle strlen = linker.downcallHandle(
    linker.defaultLookup().find("strlen").orElseThrow(),
    FunctionDescriptor.of(JAVA_LONG, ADDRESS)
);
ネイティブ・リンカーが「デフォルト・ルックアップ」を介して、JavaランタイムとともにロードされるCライブラリによって定義されたネイティブ関数にアクセスする方法も確認します。 前述のデフォルトのルックアップは、strlenネイティブ関数のアドレスを検索するために使用されます。 そのアドレスは、ネイティブ・リンカーのdowncallHandle(MemorySegment, FunctionDescriptor, Option...)メソッドにFunctionDescriptorPREVIEW (その下の詳細)として表される関数のシグネチャの「プラットフォーム依存の説明」とともに渡されます。 取得されたdowncallメソッド・ハンドルは、次のように起動されます:
try (Arena arena = Arena.ofConfined()) {
    MemorySegment str = arena.allocateUtf8String("Hello");
    long len = (long) strlen.invokeExact(str);  // 5
}

シグネチャの説明

ネイティブ・リンカーと対話する場合、クライアントは、リンク先のC関数のシグネチャについてプラットフォームに依存する説明を提供する必要があります。 この説明(function descriptorPREVIEW)は、C関数のパラメータ・タイプおよび戻り型(もしあれば)に関連付けられたレイアウトを定義します。

boolintなどのスカラーCタイプは、適切なキャリアの「値レイアウト」PREVIEWとしてモデル化されます。 スカラー・タイプとそれに対応するレイアウトとの間のマッピングは、ネイティブ・リンカーによって実装されるABIに依存します。 たとえば、C型のlongは、Linux/x64のレイアウト定数ValueLayout.JAVA_LONGPREVIEWにマップされますが、Windows/x64のレイアウト定数ValueLayout.JAVA_INTPREVIEWにマップされます。 同様に、C型のsize_tは64ビット・プラットフォームではレイアウト定数ValueLayout.JAVA_LONGPREVIEWにマップされますが、32ビット・プラットフォームではレイアウト定数ValueLayout.JAVA_INTPREVIEWにマップされます。

コンポジット・タイプは、「グループ・レイアウト」PREVIEWとしてモデル化されます。 具体的には、C struct型は「構造体レイアウト」PREVIEWにマップされ、C union型はunion layoutPREVIEWにマップされます。 構造体または共用体のレイアウトを定義する場合、クライアントはC内の対応する複合型定義のサイズおよび整列制約に注意する必要があります。 たとえば、2つの構造体フィールド間のパディングは、適切なサイズの「パディング・レイアウト」PREVIEWメンバーを結果の構造体レイアウトに追加することで、明示的にモデル化する必要があります。

最後に、int**int(*)(size_t*, size_t*)などのポインタ型は、「アドレス・レイアウト」PREVIEWとしてモデル化されます。 ポインタ型の空間境界が静的にわかっている場合は、アドレス・レイアウトを「ターゲット・レイアウト」PREVIEWに関連付けることができます。 たとえば、C int[2]配列を指すことがわかっているポインタは、ターゲット・レイアウトが要素数が2で要素タイプがValueLayout.JAVA_INTPREVIEWのシーケンス・レイアウトであるアドレス・レイアウトとしてモデル化できます。

次の表に、C型がLinux/x64でモデル化される方法の例を示します:

マッピングCタイプ
Cタイプ レイアウト Javaタイプ
bool ValueLayout.JAVA_BOOLEANPREVIEW boolean
char ValueLayout.JAVA_BYTEPREVIEW byte
short ValueLayout.JAVA_SHORTPREVIEW short
int ValueLayout.JAVA_INTPREVIEW int
long ValueLayout.JAVA_LONGPREVIEW long
long long ValueLayout.JAVA_LONGPREVIEW long
float ValueLayout.JAVA_FLOATPREVIEW float
double ValueLayout.JAVA_DOUBLEPREVIEW double
size_t ValueLayout.JAVA_LONGPREVIEW long
char*, int**, struct Point* ValueLayout.ADDRESSPREVIEW MemorySegmentPREVIEW
int (*ptr)[10]
 ValueLayout.ADDRESS.withTargetLayout(
     MemoryLayout.sequenceLayout(10,
         ValueLayout.JAVA_INT)
 );
 
MemorySegmentPREVIEW
struct Point { int x; long y; };
 MemoryLayout.structLayout(
     ValueLayout.JAVA_INT.withName("x"),
     MemoryLayout.paddingLayout(32),
     ValueLayout.JAVA_LONG.withName("y")
 );
 
MemorySegmentPREVIEW
union Choice { float a; int b; }
 MemoryLayout.unionLayout(
     ValueLayout.JAVA_FLOAT.withName("a"),
     ValueLayout.JAVA_INT.withName("b")
 );
 
MemorySegmentPREVIEW

ネイティブ・リンカーのすべての実装は、メモリー・レイアウトのサブセットで動作します。 より正式には、ネイティブ・リンカーNLで次の場合、レイアウトLがサポートされます:

ネイティブ・リンカーは、引数/戻りレイアウトがそのリンカーでサポートされるレイアウトであり、シーケンス・レイアウトではない関数記述子のみをサポートします。

関数ポインタ

場合によっては、一部のネイティブ関数への関数ポインタとしてJavaコードを渡すのに役立つことがあります。これは「アップコール・スタブ」を使用することで実現されます。 これを示すために、C標準ライブラリの次の関数について考えてみます:
void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));
qsort関数は、関数ポインタ(comparパラメータ)として渡されるカスタム・コンパレータ関数を使用して、配列の内容をソートするために使用できます。 Javaからqsort関数をコールできるようにするには、まず、次のように、停止コール・メソッド・ハンドルを作成する必要があります:
Linker linker = Linker.nativeLinker();
MethodHandle qsort = linker.downcallHandle(
    linker.defaultLookup().find("qsort").orElseThrow(),
        FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
);
前述のとおり、ValueLayout.JAVA_LONGPREVIEWを使用してC型のsize_t型をマップし、最初のポインタ・パラメータ(配列ポインタ)と最後のパラメータ(関数ポインタ)の両方にValueLayout.ADDRESSPREVIEWを使用します。

上で取得したqsortダウンコール・ハンドルを呼び出すには、関数ポインタを最後のパラメータとして渡す必要があります。 つまり、既存のメソッド・ハンドルから関数ポインタを作成する必要があります。 まず、ポインタとして渡された2つのint要素を比較できるJavaメソッドを記述します。(例:「メモリー・セグメント」PREVIEW):

class Qsort {
    static int qsortCompare(MemorySegment elem1, MemorySegment elem2) {
        return Integer.compare(elem1.get(JAVA_INT, 0), elem2.get(JAVA_INT, 0));
    }
}
次に、上で定義したコンパレータ・メソッドのメソッド・ハンドルを作成します:
FunctionDescriptor comparDesc = FunctionDescriptor.of(JAVA_INT,
                                                      ADDRESS.withTargetLayout(JAVA_INT),
                                                      ADDRESS.withTargetLayout(JAVA_INT));
MethodHandle comparHandle = MethodHandles.lookup()
                                         .findStatic(Qsort.class, "qsortCompare",
                                                     comparDesc.toMethodType());
まず、関数ポインタ型の関数記述子を作成します。 コンパレータ・メソッドに渡されるパラメータはC int[]配列の要素へのポインタであることがわかっているため、両方のパラメータのアドレス・レイアウトのターゲット・レイアウトとしてValueLayout.JAVA_INTPREVIEWを指定できます。 これによって、比較メソッドが比較する配列要素のコンテンツにアクセスできるようになります。 次に、その関数記述子を適切な「メソッド・タイプ」「ターン」PREVIEWし、これを使用してコンパレータ・メソッド・ハンドルの検索を行います。 次に、そのメソッドを指すアップコール・スタブを作成し、これを関数ポインタとして、次のようにqsortダウンコール・ハンドルに渡すことができます:
try (Arena arena = Arena.ofConfined()) {
    MemorySegment comparFunc = linker.upcallStub(comparHandle, comparDesc, arena);
    MemorySegment array = arena.allocateArray(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
    qsort.invokeExact(array, 10L, 4L, comparFunc);
    int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
}
このコードは、オフ・ヒープ配列を作成し、その配列にJava配列の内容をコピーし、ネイティブ・リンカーから取得したコンパレータ関数とともに配列をqsortメソッド・ハンドルに渡します。 呼出し後、オフ・ヒープ配列の内容は、Javaで記述されたコンパレータ関数に従ってソートされます。 次に、ソートされた要素を含む新しいJava配列をセグメントから抽出します。

ポインタを返す関数

ネイティブ関数と対話する場合は、これらの関数がメモリーのリージョンを割り当て、その領域へのポインタを返すことが一般的です。 C標準ライブラリの次の関数について考えてみます:
void *malloc(size_t size);
malloc関数は、指定されたサイズのメモリーのリージョンを割り当て、そのメモリーのリージョンへのポインタを返します。このポインタは、あとでC標準ライブラリの別の関数を使用して割り当て解除されます:
void free(void *ptr);
free関数は、メモリーのリージョンへのポインタを取得し、その領域の割当てを解除します。 この項では、「安全」割当てAPI (次に示すアプローチは、mallocおよびfree以外の割当て関数に一般化できます)の提供を目的として、これらのネイティブ関数との対話方法を示します。

まず、次のように、mallocおよびfreeのダウンコール・メソッド・ハンドルを作成する必要があります:

Linker linker = Linker.nativeLinker();

MethodHandle malloc = linker.downcallHandle(
    linker.defaultLookup().find("malloc").orElseThrow(),
    FunctionDescriptor.of(ADDRESS, JAVA_LONG)
);

MethodHandle free = linker.downcallHandle(
    linker.defaultLookup().find("free").orElseThrow(),
    FunctionDescriptor.ofVoid(ADDRESS)
);
ダウンコール・メソッド・ハンドルを使用してポインタ(malloc)を返すネイティブ・ファンクションが呼び出されると、Javaランタイムは、返されるポインタのサイズまたは存続期間を把握できません。 次のコードについて検討します。
MemorySegment segment = (MemorySegment)malloc.invokeExact(100);
mallocダウンコール・メソッド・ハンドルによって返されるセグメントのサイズは、zeroです。 さらに、返されるセグメントのスコープは、常に有効である新しいスコープです。 セグメントに安全にアクセスできるようにするには、セグメントを適切なサイズ(100、この場合は)にサイズ変更する必要があります。 また、セグメントを既存の「アリーナ」PREVIEWに接続して、Javaコードから直接作成された他のネイティブ・セグメントと同様に、セグメントをバッキングするメモリーのリージョンの存続期間を自動的に管理できるようにすることも望ましい場合があります。 これらの操作はいずれも、次のように制限付きメソッドMemorySegment.reinterpret(long, Arena, Consumer)PREVIEWを使用して実行されます:
MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable {
    MemorySegment segment = (MemorySegment) malloc.invokeExact(byteSize); // size = 0, scope = always alive
    return segment.reinterpret(byteSize, arena, s -> {
        try {
            free.invokeExact(s);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    });  // size = byteSize, scope = arena.scope()
}
前述のallocateMemoryメソッドは、2つのパラメータを受け入れます: サイズとアリーナ。 このメソッドは、mallocダウンコール・メソッド・ハンドルをコールし、新しいサイズ(allocateMemoryメソッドに渡されるサイズ)および新しいスコープ(指定されたアリーナのスコープ)を指定することで、返されたセグメントを安全に再解釈します。 このメソッドは、指定されたアリーナが閉じられるときに実行される「クリーン・アップ処理」も指定します。 驚くべきことに、クリーンアップ・アクションは、セグメントをfreeダウンコール・メソッド・ハンドルに渡して、メモリーの基礎となるリージョンの割当てを解除します。 allocateMemoryメソッドは次のように使用できます:
try (Arena arena = Arena.ofConfined()) {
    MemorySegment segment = allocateMemory(100, arena);
} // 'free' called here
allocateMemoryから取得したセグメントが、限定されたアリーナによって管理される他のセグメントとして機能することに注意してください。 具体的には、取得したセグメントは必要なサイズを持ち、単一のスレッド(狭いアリーナを作成したスレッド)によってのみアクセスでき、その存続期間は周囲のtry-with-resourcesブロックに関連付けられます。

可変個引数関数

可変個引数関数とは、可変数と引数の型を受け入れることができるC関数です。 次のように宣言されます:
  1. 次のように、仮パラメータ・リストの最後に末尾の省略記号(...)が付きます: void foo(int x, ...);
  2. 次のようなプロトタイプ・レス関数と呼ばれる、空の仮パラメータ・リストを使用: void foo();
省略記号のかわりに渡される引数、またはプロトタイプなし関数に渡される引数は、「可変個引数」と呼ばれます。 可変個引数関数は、基本的に、...または空の仮パラメータ・リストを固定数値およびタイプの「可変個引数パラメータ」のリストで置き換えることで、「特殊化」を複数の可変個引数関数にできるテンプレートです。

可変個引数として渡される値は、Cでデフォルトの引数昇格を受けることに注意してください。 たとえば、次の引数プロモーションが適用されます:

  • _Bool -> unsigned int
  • [signed] char -> [signed] int
  • [signed] short -> [signed] int
  • float -> double
ソース・タイプの署名は、昇格されたタイプの署名状態に対応します。 デフォルトの引数昇格の完全なプロセスについては、Cの仕様を参照してください。 実際には、これらのプロモーションは、可変個引数関数の特殊な形式に制限を設けます。これは、特殊なフォームの可変個引数パラメータは常にプロモート・タイプを持つためです。

ネイティブ・リンカーは、特殊な形式の可変個引数関数のリンクのみをサポートします。 特殊な形式の可変個引数関数を、特殊な形式を記述する関数記述子を使用してリンクできます。 さらに、パラメータ・リストの最初の可変個引数パラメータを示すには、Linker.Option.firstVariadicArg(int)PREVIEWリンカー・オプションを指定する必要があります。 対応する引数レイアウト(もしあれば)、および特殊な関数記述子の次のすべての引数レイアウトは、「可変個引数レイアウト」と呼ばれます。 プロトタイプ・レス関数の場合、Linker.Option.firstVariadicArg(int)PREVIEWに渡される索引は常に0である必要があります。

ネイティブ・リンカーは、特殊な関数記述子を、デフォルトの引数プロモーション (前述のとおり)の対象となるC型に対応する任意の可変個引数レイアウトにリンクする試みを拒否します。 却下されるレイアウトはプラットフォーム固有ですが、例として: Linux/x64では、ValueLayout.JAVA_BOOLEANPREVIEWValueLayout.JAVA_BYTEPREVIEWValueLayout.JAVA_CHARPREVIEWValueLayout.JAVA_SHORTPREVIEWおよびValueLayout.JAVA_FLOATPREVIEWのレイアウトは拒否されます。

既知の可変個引数関数とは、C標準ライブラリで定義されるprintf関数です:

int printf(const char *format, ...);
この関数は、書式文字列、および多数の追加引数(このような引数の数は、書式文字列によって決定されます)を取ります。 次の可変個引数コールについて考えてみます:
printf("%d plus %d equals %d", 2, 2, 4);
ダウンコール・メソッド・ハンドルを使用して同等のコールを実行するには、コールするC関数の特殊なシグネチャを記述する関数記述子を作成する必要があります。 この記述子には、指定する各可変個引数に追加のレイアウトを含める必要があります。 この場合、書式文字列が3つの整数パラメータを受け入れるため、C関数の特殊なシグネチャは(char*, int, int, int)です。 次に、「リンカー・オプション」PREVIEWを使用して、指定された関数記述子(0から開始)の最初の可変個引数レイアウトの位置を指定する必要があります。 この場合、最初のパラメータが書式文字列(非可変個引数)であるため、最初の可変個引数索引を次のように1に設定する必要があります:
Linker linker = Linker.nativeLinker();
MethodHandle printf = linker.downcallHandle(
    linker.defaultLookup().find("printf").orElseThrow(),
        FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT),
        Linker.Option.firstVariadicArg(1) // first int is variadic
);
その後、通常どおり専用のダウンコール・ハンドルを呼び出すことができます:
try (Arena arena = Arena.ofConfined()) {
    int res = (int)printf.invokeExact(arena.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
}

安全に関する考慮事項

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

アップコール・スタブが外部関数に渡されると、アップコール・スタブに関連付けられた関数ポインタをアップコール・スタブの型と互換性のない型にキャストし、結果として得られる関数ポインタを介して関数を呼び出そうとすると、JVMクラッシュが発生する可能性があります。 さらに、アップコール・スタブに関連付けられたメソッド・ハンドルが「メモリー・セグメント」PREVIEWを返す場合、クライアントは、アップコールの完了後にこのアドレスが無効になることができないことを確認する必要があります。 これは、通常、アップ・コールはダウン・コール・メソッド・ハンドルの起動のコンテキストで実行されるため、不特定の動作を引き起こし、JVMがクラッシュする可能性があります。

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

    • nativeLinker

      static LinkerPREVIEW nativeLinker()
      基礎となるネイティブ・プラットフォームに関連付けられたABIのリンカーを返します。 基礎となるネイティブ・プラットフォームは、Javaランタイムが現在実行されているOSとプロセッサの組合せです。
      APIのノート:
      現在、OSとプロセッサの異なる組み合わせに対してリンカーを取得することはできません。
      実装上のノート:
      返されるリンカーに関連付けられた「デフォルト・ルックアップ」によって公開されるライブラリは、Javaランタイムが現在実行されているプロセスにロードされるネイティブ・ライブラリです。 たとえば、Linuxの場合、これらのライブラリには通常、libclibmおよびlibdlが含まれます。
      戻り値:
      ベースとなるネイティブ・プラットフォームに関連付けられたABIのリンカー
      例外:
      UnsupportedOperationException - 基盤となるネイティブ・プラットフォームがサポートされていない場合。
    • downcallHandle

      MethodHandle downcallHandle(MemorySegmentPREVIEW address, FunctionDescriptorPREVIEW function, Linker.OptionPREVIEW... options)
      指定されたシグネチャとアドレスで外部関数を呼び出すために使用されるメソッド・ハンドルを作成します。

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

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

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

      パラメータ:
      address - 「ベース・アドレス」PREVIEWがターゲット外部関数のアドレスであるネイティブ・メモリー・セグメント。
      function - ターゲット外部関数の関数記述子。
      options - このリンケージ・リクエストに関連付けられたリンカー・オプション。
      戻り値:
      ダウンコール・メソッド・ハンドル。
      例外:
      IllegalArgumentException - 指定された関数記述子がこのリンカーでサポートされていない場合。
      IllegalArgumentException - !address.isNative()の場合、またはaddress.equals(MemorySegment.NULL)の場合。
      IllegalArgumentException - リンカー・オプションの無効な組み合わせが指定されている場合。
      IllegalCallerException - 呼び出し元が、ネイティブ・アクセスが有効になっていないモジュール内にある場合。
      関連項目:
    • downcallHandle

      MethodHandle downcallHandle(FunctionDescriptorPREVIEW function, Linker.OptionPREVIEW... options)
      指定されたシグネチャで外部関数を呼び出すために使用されるメソッド・ハンドルを作成します。

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

      ダウンコール・メソッド・ハンドルを呼び出すと、リンカーは、対応するレイアウトがアドレス・レイアウトPREVIEWであるMemorySegmentPREVIEW型の引数Aに対して、次の保証を提供します:

      さらに、指定された関数記述子の戻りレイアウトが「アドレス・レイアウト」PREVIEWの場合、戻されたメソッド・ハンドルを呼び出すと、常に存続している新しいスコープに関連付けられたネイティブ・セグメントが返されます。 通常の状況では、返されるセグメントのサイズは0です。 ただし、関数記述子の戻りレイアウトに「ターゲット・レイアウト」PREVIEW Tがある場合、返されるセグメントのサイズはT.byteSize()に設定されます。

      外部関数のターゲット・アドレスを表すMemorySegmentPREVIEWMemorySegment.NULLPREVIEWアドレスである場合、戻されたメソッド・ハンドルはIllegalArgumentExceptionをスローします。 返されたメソッド・ハンドルは、渡された引数がnullである場合、さらにNullPointerExceptionをスローします。

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

      パラメータ:
      function - ターゲット外部関数の関数記述子。
      options - このリンケージ・リクエストに関連付けられたリンカー・オプション。
      戻り値:
      ダウンコール・メソッド・ハンドル。
      例外:
      IllegalArgumentException - 指定された関数記述子がこのリンカーでサポートされていない場合。
      IllegalArgumentException - リンカー・オプションの無効な組み合わせが指定されている場合。
      IllegalCallerException - 呼び出し元が、ネイティブ・アクセスが有効になっていないモジュール内にある場合。
    • upcallStub

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

      返されたメモリー・セグメントのアドレスは、新しく割り当てられたアップコール・スタブを指し、指定されたアリーナに関連付けられます。 したがって、返されたアップコール・スタブ・セグメントの寿命は、指定されたアリーナによって制御されます。 たとえば、指定されたアリーナが限定されたアリーナの場合、指定された限定されたアリーナがclosedPREVIEWのとき、返されるアップコール・スタブ・セグメントは割り当て解除されます。

      対応するレイアウトが「アドレス・レイアウト」PREVIEWであるアップコール・スタブ引数は、常に存在する新しいスコープに関連付けられたネイティブ・セグメントです。 通常の場合、このセグメント引数のサイズは0です。 ただし、アドレス・レイアウトに「ターゲット・レイアウト」PREVIEW Tがある場合、セグメント引数のサイズはT.byteSize()に設定されます。

      ターゲット・メソッド・ハンドルは例外をスローしません。 ターゲット・メソッド・ハンドルが例外をスローすると、JVMは突然終了します。 これを回避するには、クライアントがtry/catchブロック内のターゲット・メソッド・ハンドルのコードをラップして、予期しない例外を捕捉する必要があります。 これは、MethodHandles.catchException(MethodHandle, Class, MethodHandle)メソッド・ハンドル・コンビネータを使用して実行でき、対応するcatchブロックで必要に応じて例外を処理できます。

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

      パラメータ:
      target - ターゲット・メソッド・ハンドル。
      function - upcallスタブ関数記述子。
      arena - 返されたアップコール・スタブ・セグメントに関連付けられたアリーナ。
      options - このリンケージ・リクエストに関連付けられたリンカー・オプション。
      戻り値:
      アドレスがアップ・コール・スタブのアドレスである長さゼロのセグメント。
      例外:
      IllegalArgumentException - 指定された関数記述子がこのリンカーでサポートされていない場合。
      IllegalArgumentException - targetのタイプがfunctionderivedPREVIEW型と互換性がない場合。
      IllegalArgumentException - ターゲット・メソッド・ハンドルが例外をスローできると判断された場合。
      IllegalStateException - arena.scope().isAlive() == falseの場合
      WrongThreadException - arenaが限定されたアリーナで、このメソッドは、アリーナの所有者スレッド以外のスレッドTからコールされます。
      IllegalCallerException - 呼び出し元が、ネイティブ・アクセスが有効になっていないモジュール内にある場合。
    • defaultLookup

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

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

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

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

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