Интерфейс Linker
public sealed interface Linker
Linker — это предварительный API платформы Java. Внешние функции обычно находятся в библиотеках, которые могут загружаться по требованию. Каждая библиотека соответствует определенному ABI (Application Binary Interface). ABI — это набор соглашений о вызовах и типов данных, связанных с компилятором, ОС и процессором, на котором была построена библиотека. Например, C-компилятор на Linux/x64 обычно строит библиотеки, соответствующие SystemV ABI.
Линкер обладает подробными знаниями о соглашениях о вызовах и типах данных, используемых определенным ABI. Для любой библиотеки, соответствующей этому ABI, линкер может выступать в качестве посредника между кодом Java, выполняемым в JVM, и внешними функциями в библиотеке. В частности:
- Линкер позволяет коду Java связаться с внешними функциями через обработчики вызовов вниз; и
- Линкер позволяет внешним функциям вызывать обработчики методов Java, сгенерировав заглушки вызовов вверх.
libc и libm. Функции в этих библиотеках доступны через поиск символов. Вызов функций нативного кода
Нативный линкер может использоваться для связи с функциями, определенными в C-библиотеках (нативные функции). Предположим, мы хотим сделать вызов вниз из Java к функцииstrlen в стандартной C-библиотеке: 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)
);
strlen. Этот адрес затем передаётся вместе с зависимой от платформы спецификацией сигнатуры функции, выраженной как FunctionDescriptorПРЕВЬЮ (подробнее об этом ниже) методу нативного линкера downcallHandle(MemorySegment, FunctionDescriptor, Option...). Полученный обработчик метода вызова вниз затем вызывается следующим образом: try (Arena arena = Arena.ofConfined()) {
MemorySegment str = arena.allocateUtf8String("Hello");
long len = (long) strlen.invokeExact(str); // 5
}
Описание сигнатур C
При взаимодействии с нативным линкером клиенты должны предоставить зависимую от платформы спецификацию сигнатуры C-функции, к которой они хотят связаться. Это описание,function descriptorПРЕВЬЮ, определяет макеты, связанные с типами параметров и возвращаемым типом (если таковой имеется) C-функции. Скалярные типы C, такие как bool, int, моделируются как макеты значенийПРЕВЬЮ подходящего носителя. Сопоставление между скалярным типом и соответствующим макетом зависит от ABI, реализованного нативным линкером. Например, тип C long сопоставляется со значением макета ValueLayout.JAVA_LONGПРЕВЬЮ на Linux/x64, но со значением макета ValueLayout.JAVA_INTПРЕВЬЮ на Windows/x64. Аналогично, тип C size_t сопоставляется со значением макета ValueLayout.JAVA_LONGПРЕВЬЮ на 64-битных платформах, но со значением макета ValueLayout.JAVA_INTПРЕВЬЮ на 32-битных платформах.
Составные типы моделируются как макеты группПРЕВЬЮ. Более конкретно, тип C struct сопоставляется с структурным макетомПРЕВЬЮ, а тип C union сопоставляется с union
layoutПРЕВЬЮ. При определении макета структуры или объединения клиенты должны учитывать ограничения размера и выравнивания соответствующего определения составного типа в C. Например, отступы между двумя полями структуры должны быть явно смоделированы, путем добавления члена макета заполненияПРЕВЬЮ соответствующего размера в результирующий макет структуры.
Наконец, типы указателей, такие как int** и int(*)(size_t*, size_t*), моделируются как макеты адресовПРЕВЬЮ. Если пространственные границы типа указателя известны статически, макет адреса может быть связан с целевым макетомПРЕВЬЮ. Например, указатель, который, как известно, указывает на массив C int[2], может быть смоделирован как макет адреса, целевой макет которого является последовательным макетом с количеством элементов 2 и типом элемента ValueLayout.JAVA_INTПРЕВЬЮ.
В следующей таблице приведены примеры моделирования типов C на Linux/x64:
Тип C Макет Тип Java boolValueLayout.JAVA_BOOLEANПРЕВЬЮbooleancharValueLayout.JAVA_BYTEПРЕВЬЮbyteshortValueLayout.JAVA_SHORTПРЕВЬЮshortintValueLayout.JAVA_INTПРЕВЬЮintlongValueLayout.JAVA_LONGПРЕВЬЮlonglong longValueLayout.JAVA_LONGПРЕВЬЮlongfloatValueLayout.JAVA_FLOATПРЕВЬЮfloatdoubleValueLayout.JAVA_DOUBLEПРЕВЬЮdoublesize_tValueLayout.JAVA_LONGПРЕВЬЮlongchar*,int**,struct Point*ValueLayout.ADDRESSПРЕВЬЮMemorySegmentПРЕВЬЮint (*ptr)[10]ValueLayout.ADDRESS.withTargetLayout( MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_INT) );MemorySegmentПРЕВЬЮstruct Point { int x; long y; };MemoryLayout.structLayout( ValueLayout.JAVA_INT.withName("x"), MemoryLayout.paddingLayout(32), ValueLayout.JAVA_LONG.withName("y") );MemorySegmentПРЕВЬЮunion Choice { float a; int b; }MemoryLayout.unionLayout( ValueLayout.JAVA_FLOAT.withName("a"), ValueLayout.JAVA_INT.withName("b") );MemorySegmentПРЕВЬЮ
Все реализации нативных линков работают с подмножеством макетов памяти. Более формально, макет L поддерживается нативным линком NL если:
-
L— это макет значенияVиV.withoutName()равенравенПРЕВЬЮ одному из следующих констант макетов: -
L— это макет адресаAиA.withoutTargetLayout().withoutName()равенравенПРЕВЬЮValueLayout.ADDRESSПРЕВЬЮ -
L— это макет последовательностиSи выполняются все следующие условия:- ограничение выравнивания
Sустановлено в его естественное выравнивание, и -
S.elementLayout()— это макет, поддерживаемыйNL.
- ограничение выравнивания
-
L— это макет группыGи выполняются все следующие условия:- ограничение выравнивания
Gустановлено в его естественное выравнивание; - размер
Gкратен его ограничению выравнивания; - каждый макет элемента в
G.memberLayouts()— это либо макет заполнения, либо макет, поддерживаемыйNL, и -
Gне содержит заполнение, кроме строго необходимого для выравнивания элементов макета без заполнения или для удовлетворения (2).
- ограничение выравнивания
Указатели на функции
Иногда бывает полезно передавать код Java как указатель на функцию некоторой нативной функции; это достигается с помощью вызова по переходу. Чтобы продемонстрировать это, рассмотрим следующую функцию из стандартной библиотеки C:void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
qsort может использоваться для сортировки содержимого массива, используя пользовательскую функцию сравнения, которая передаётся как указатель на функцию (параметр compar). Чтобы вызвать функцию qsort из Java, необходимо сначала создать обработчик вызова для неё, как показано ниже: Linker linker = Linker.nativeLinker();
MethodHandle qsort = linker.downcallHandle(
linker.defaultLookup().find("qsort").orElseThrow(),
FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
);
ValueLayout.JAVA_LONGПРЕВЬЮ для сопоставления типа C size_t, а ValueLayout.ADDRESSПРЕВЬЮ — для первого параметра-указателя (указателя на массив) и последнего параметра (указателя на функцию). Чтобы вызвать полученный выше обработчик вызова qsort, нам нужно передать указатель на функцию в качестве последнего параметра. Для этого нужно создать указатель на функцию из существующего обработчика метода. Сначала напишем метод Java, который может сравнивать два элемента int, переданных как указатели (т.е. как сегменты памятиПРЕВЬЮ):
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());
int[], мы можем указать ValueLayout.JAVA_INTПРЕВЬЮ в качестве целевого макета для макетов адресов обоих параметров. Это позволит методу компаратора получать доступ к содержимому элементов массива, которые необходимо сравнить. Затем мы преобразуемПРЕВЬЮ этот описатель функции в соответствующий тип метода метода, который мы затем используем для поиска обработчика метода компаратора. Теперь мы можем создать вызов по переходу, который указывает на этот метод, и передать его как указатель на функцию обработчику вызова 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 ]
}
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, равен нулю. Кроме того, область возвращаемого сегмента — это новая область, которая всегда жива. Чтобы предоставить безопасный доступ к сегменту, мы должны, не безбезопасно, изменить размер сегмента на желаемый размер (100 в данном случае). Также может быть желательно привязать сегмент к некоторому существующему объёму памятиПРЕВЬЮ, чтобы время жизни области памяти, подчинённой сегменту, можно было управлять автоматически, как для любого другого нативного сегмента, созданного непосредственно из Java-кода. Оба эти действия выполняются с помощью ограниченного метода MemorySegment.reinterpret(long, Arena, Consumer)ПРЕВЬЮ, как показано ниже: 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 принимает два параметра: размер и объём памяти. Метод вызывает обработчик вызова malloc и, не гарантируя безопасности, переинтерпретирует возвращённый сегмент, присваивая ему новый размер (размер, переданный методу allocateMemory) и новую область (область предоставленного объёма памяти). Метод также указывает действие очистки, которое должно выполняться при закрытии предоставленного объёма памяти. Неудивительно, что действие очистки передаёт сегмент обработчику вызова free для освобождения подчинённой области памяти. Мы можем использовать метод allocateMemory следующим образом: try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = allocateMemory(100, arena);
} // 'free' called here
allocateMemory, действует как любой другой сегмент, управляемый ограниченным объёмом памяти. Более конкретно, полученный сегмент имеет нужный размер, к нему может получить доступ только один поток (поток, создавший ограниченный объём памяти), и его время жизни связано с окружающим блоком try-with-resources. Функции с переменным числом параметров
Функции с переменным числом параметров — это функции C, которые могут принимать переменное количество и тип аргументов. Они объявляются:- С заключительным многоточием (
...) в конце списка формальных параметров, например:void foo(int x, ...); - Со списком формальных параметров, называемым функцией без прототипа, например:
void foo();
Следует отметить, что значения, переданные как аргументы с переменным числом параметров, подвергаются стандартной обработке аргументов в C. Например, применяются следующие преобразования аргументов:
-
_Bool->unsigned int -
[signed] char->[signed] int -
[signed] short->[signed] int -
float->double
Собственный линковщик поддерживает только специализированную форму вариадной функции. Вариадную функцию в специализированной форме можно связать с помощью дескриптора функции, описывающего специализированную форму. Кроме того, необходимо указать параметр линковщика Linker.Option.firstVariadicArg(int)ПРОСМОТР для указания первого вариадного параметра в списке параметров. Соответствующая структура аргументов (если она есть), а также все последующие структуры аргументов в дескрипторе специализированной функции называются структурами вариадных аргументов. Для функции без прототипа индекс, переданный Linker.Option.firstVariadicArg(int)ПРОСМОТР, должен всегда быть 0.
Собственный линковщик отклонит попытку связать дескриптор специализированной функции с любыми структурами вариадных аргументов, соответствующими типу C, который подвергнется стандартному продвижению аргументов (как описано выше). Точно, какие структуры будут отклонены, зависит от платформы, но, например, на Linux/x64 будут отклонены структуры ValueLayout.JAVA_BOOLEANПРОСМОТР, ValueLayout.JAVA_BYTEПРОСМОТР, ValueLayout.JAVA_CHARПРОСМОТР, ValueLayout.JAVA_SHORTПРОСМОТР и ValueLayout.JAVA_FLOATПРОСМОТР.
Известной вариадной функцией является функция printf, определённая в стандартной библиотеке C:
int printf(const char *format, ...);
printf("%d plus %d equals %d", 2, 2, 4);
(char*, int, int, int), так как строка формата принимает три целочисленных параметра. Затем нам нужно использовать параметр линковщика параметр линковщикаПРОСМОТР, чтобы указать позицию первой вариадной структуры в предоставленном дескрипторе функции (начиная с 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, если внешние код приведёт указатель функции, связанный с вызовом вверх, к типу, несовместимому с типом вызова вверх, а затем попытается вызвать функцию с помощью полученного указателя функции. Кроме того, если обработчик метода, связанный с вызовом вверх, возвращает сегмент памятиПРОСМОТР, клиенты должны гарантировать, что этот адрес не может стать недействительным после завершения вызова вверх. Это может привести к неопределенному поведению и даже к сбою JVM, поскольку вызов вверх обычно выполняется в контексте вызова обработчика метода вниз.
- Требования к реализации:
- Реализации этого интерфейса являются неизменяемыми, потокобезопасными и базирующимися на значении.
- С:
- 19
Краткое описание вложенных классов
| Модификатор и тип | Интерфейс | Описание |
|---|---|---|
static interface |
Linker.OptionPREVIEW |
Просмотр. Параметр линковщика используется для предоставления дополнительных параметров запросу на связывание. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
SymbolLookupPREVIEW |
defaultLookup() |
Возвращает поиск символов для символов в наборе часто используемых библиотек. |
MethodHandle |
downcallHandle |
Создаёт обработчик метода, который используется для вызова внешней функции с заданной сигнатурой. |
MethodHandle |
downcallHandle |
Создаёт обработчик метода, который используется для вызова внешней функции с заданной сигнатурой и адресом. |
static LinkerPREVIEW |
nativeLinker() |
Возвращает линковщик для ABI, связанного с базовой платформой. |
MemorySegmentPREVIEW |
upcallStub |
Создаёт заглушку вызова вверх, которая может передаваться другим внешним функциям в качестве указателя функции, связанной с заданным ареной. |
Подробное описание методов
nativeLinker
static LinkerPREVIEW nativeLinker()
- Примечание API:
- В настоящее время невозможно получить линковщик для другого сочетания ОС и процессора.
- Примечание реализации:
- Библиотеки, экспонируемые с помощью поиска по умолчанию, связанного с возвращенным линковщиком, — это библиотеки нативного кода, загруженные в процессе, где в данный момент выполняется Java-среда выполнения. Например, в Linux эти библиотеки обычно включают
libc,libmиlibdl. - Возвращает:
- линковщик для ABI, связанного с базовой платформой нативного кода
- Имеет исключения:
-
UnsupportedOperationException— если базовая платформа нативного кода не поддерживается.
downcallHandle
MethodHandle downcallHandle(MemorySegmentPREVIEW address, FunctionDescriptorPREVIEW function, Linker.OptionPREVIEW... options)
Вызов этого метода эквивалентен следующему коду:
linker.downcallHandle(function).bindTo(symbol);
Этот метод ограничен. Ограниченные методы небезопасны, и, если их использовать неправильно, их использование может привести к аварийному завершению JVM или, что ещё хуже, к скрытой ошибке повреждения памяти. Таким образом, клиенты должны избегать зависимости от ограниченных методов и по возможности использовать безопасные и поддерживаемые функции.
- Параметры:
-
address— сегмент памяти нативного кода, чьё базовое значение адресаПРЕДПРОСМОТР является адресом целевой внешней функции. -
function— описание функции целевой внешней функции. -
options— параметры линковщика, связанные с этим запросом на связывание. - Возвращает:
- обработчик вызова.
- Имеет исключения:
-
IllegalArgumentException— если предоставленное описание функции не поддерживается этим линковщиком. -
IllegalArgumentException— если!address.isNative(), или еслиaddress.equals(MemorySegment.NULL). -
IllegalArgumentException— если задана некорректная комбинация параметров линковщика. -
IllegalCallerException— Если вызывающий элемент находится в модуле, для которого не включён доступ к нативному коду. - См. также:
downcallHandle
MethodHandle downcallHandle(FunctionDescriptorPREVIEW function, Linker.OptionPREVIEW... options)
Тип метода Java метода, связанный с возвращённым обработчиком, выводитсяПРЕДПРОСМОТР из расположения аргументов и возвращаемого значения в описании функции, но содержит дополнительный ведущий параметр типа MemorySegmentПРЕДПРОСМОТР, из которого выводится адрес целевой внешней функции. Кроме того, если расположение возвращаемого значения в описании функции является групповым расположением, возвращаемый обработчик вызова принимает дополнительный ведущий параметр типа SegmentAllocatorПРЕДПРОСМОТР, который используется во время выполнения линковщика для выделения области памяти, связанной со структурой, возвращаемой обработчиком вызова.
При вызове обработчика вызова линковщик гарантирует следующее для любого аргумента A типа MemorySegmentПРЕДПРОСМОТР, чьё соответствующее расположение — расположение адресаПРЕДПРОСМОТР:
-
A.scope().isAlive() == true. В противном случае вызов приводит к исключениюIllegalStateException; - Вызов происходит в потоке
Tтаким образом, чтоA.isAccessibleBy(T) == true. В противном случае вызов приводит к исключениюWrongThreadException; и -
Aсохраняется во время вызова. Например, еслиAполучено с использованием разделяемой областиПРЕДПРОСМОТР, любая попытка закрытьПРЕДПРОСМОТР область в то время, когда обработчик вызова всё ещё выполняется, приведёт к исключениюIllegalStateException.
Кроме того, если расположение возвращаемого значения в описании функции является расположением адресаПРЕДПРОСМОТР, вызов возвращённого обработчика вернёт сегмент нативного кода, связанный со свежим контекстом, который всегда существует. В обычных условиях размер возвращаемого сегмента составляет 0. Однако, если расположение возвращаемого значения в описании функции имеет целевое расположениеПРЕДПРОСМОТР T, размер возвращаемого сегмента устанавливается в T.byteSize().
Возвращаемый обработчик вызовов выбросит IllegalArgumentException, если MemorySegmentПРЕДПРОСМОТР, представляющий целевой адрес внешней функции, — это адрес MemorySegment.NULLПРЕДПРОСМОТР. Возвращаемый обработчик вызовов дополнительно выбросит NullPointerException, если какой-либо переданный в него аргумент null.
Этот метод ограничен. Ограниченные методы небезопасны, и, если их использовать неправильно, их использование может привести к аварийному завершению JVM или, что ещё хуже, к скрытой ошибке повреждения памяти. Таким образом, клиенты должны избегать зависимости от ограниченных методов и по возможности использовать безопасные и поддерживаемые функции.
- Параметры:
-
function— описание функции целевой внешней функции. -
options— параметры линковщика, связанные с этим запросом на связывание. - Возвращает:
- обработчик вызова.
- Имеет исключения:
-
IllegalArgumentException— если предоставленное описание функции не поддерживается этим линковщиком. -
IllegalArgumentException— если задана некорректная комбинация параметров линковщика. -
IllegalCallerException— Если вызывающий элемент находится в модуле, для которого не включён доступ к нативному коду.
upcallStub
MemorySegmentPREVIEW upcallStub(MethodHandle target, FunctionDescriptorPREVIEW function, ArenaPREVIEW arena, Linker.OptionPREVIEW... options)
Адрес возвращаемого сегмента памяти указывает на только что созданную заглушку вызова и связан с предоставленной областью. Таким образом, срок жизни возвращаемого сегмента заглушки вызова контролируется предоставленной областью. Например, если предоставленная область — это ограниченная область, возвращаемый сегмент заглушки вызова будет удалён, когда предоставленная ограниченная область будет закрытаPREVIEW.
Аргумент заглушки вызова, расположение которого — расположение адресаPREVIEW, является нативным сегментом, связанным со свежим, всегда активным, пространством. В обычных условиях размер этого сегмента-аргумента равен 0. Однако, если расположение адреса имеет целевое расположениеPREVIEW T, то размер сегмента-аргумента устанавливается в T.byteSize().
Целевой обработчик метода не должен генерировать исключения. Если целевой обработчик метода генерирует исключение, JVM прекратит работу внезапно. Чтобы избежать этого, клиенты должны обернуть код в целевом обработчике метода в блок try/catch, чтобы перехватить любые неожиданные исключения. Это можно сделать с помощью комбинатора MethodHandles.catchException(MethodHandle, Class, MethodHandle) обработчиков методов, и обработать исключения по своему усмотрению в соответствующем блоке catch.
Этот метод ограничен. Ограниченные методы небезопасны, и, если их использовать неправильно, их использование может привести к аварийной остановке JVM или, что ещё хуже, к молчаливому повреждению памяти. Поэтому клиенты должны избегать зависимости от ограниченных методов и использовать безопасные и поддерживаемые функции, где это возможно.
- Параметры:
-
target- целевой обработчик метода. -
function- описание функции заглушки вызова. -
arena- область, связанная с возвращаемым сегментом заглушки вызова. -
options- опции линковщика, связанные с этим запросом связи. - Возвращает:
- сегмент нулевой длины, чей адрес — адрес заглушки вызова.
- Исключения:
-
IllegalArgumentException- если предоставленное описание функции не поддерживается этим линковщиком. -
IllegalArgumentException- если типtargetнесовместим с типом, полученнымPREVIEW изfunction. -
IllegalArgumentException- если установлено, что целевой обработчик метода может генерировать исключение. -
IllegalStateException- еслиarena.scope().isAlive() == false -
WrongThreadException- еслиarena— это ограниченная область, а этот метод вызывается из потокаT, отличного от потока-владельца области. -
IllegalCallerException- Если вызывающий находится в модуле, у которого не включен доступ к нативным функциям.
defaultLookup
SymbolLookupPREVIEW defaultLookup()
Каждый LinkerPREVIEW отвечает за выбор библиотек, которые широко признаны полезными на комбинации ОС и процессора, поддерживаемой LinkerPREVIEW. Соответственно, точный набор символов, экспонируемых поиском символов, не определён; он отличается от одного LinkerPREVIEW к другому.
- Примечание к реализации:
- Настоятельно рекомендуется, чтобы результат
defaultLookup()экспонировал набор символов, стабильный во времени. КлиентыdefaultLookup()могут потерпеть неудачу, если символ, ранее экспонированный поиском символов, больше не экспонируется.Если реализатор предоставляет реализации
LinkerPREVIEW для нескольких комбинаций ОС и процессоров, то настоятельно рекомендуется, чтобы результатdefaultLookup()по возможности экспонировал согласованный набор символов во всех комбинациях ОС и процессоров. - Возвращает:
- поиск символов для символов в наборе часто используемых библиотек.
© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/foreign/Linker.html
Linkerтолько при включенных предварительных функциях.