mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8295044: Implementation of Foreign Function and Memory API (Second Preview)
Co-authored-by: Jorn Vernee <jvernee@openjdk.org> Co-authored-by: Per Minborg <pminborg@openjdk.org> Co-authored-by: Maurizio Cimadamore <mcimadamore@openjdk.org> Reviewed-by: jvernee, pminborg, psandoz, alanb, sundar
This commit is contained in:
parent
bd381886e0
commit
73baadceb6
252 changed files with 9221 additions and 7889 deletions
|
@ -26,13 +26,13 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.abi.AbstractLinker;
|
||||
import jdk.internal.foreign.abi.LinkerOptions;
|
||||
import jdk.internal.foreign.abi.SharedUtils;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
/**
|
||||
* A linker provides access to foreign functions from Java code, and access to Java code from foreign functions.
|
||||
|
@ -47,9 +47,9 @@ import java.lang.invoke.MethodType;
|
|||
* in the JVM and foreign functions in the library. In particular:
|
||||
* <ul>
|
||||
* <li>A linker allows Java code to link against foreign functions, via
|
||||
* {@linkplain #downcallHandle(Addressable, FunctionDescriptor) downcall method handles}; and</li>
|
||||
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; and</li>
|
||||
* <li>A linker allows foreign functions to call Java method handles,
|
||||
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stubs}.</li>
|
||||
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) upcall stubs}.</li>
|
||||
* </ul>
|
||||
* In addition, a linker provides a way to look up foreign functions in libraries that conform to the ABI. Each linker
|
||||
* chooses a set of libraries that are commonly used on the OS and processor combination associated with the ABI.
|
||||
|
@ -62,29 +62,16 @@ import java.lang.invoke.MethodType;
|
|||
*
|
||||
* <h2 id="downcall-method-handles">Downcall method handles</h2>
|
||||
*
|
||||
* {@linkplain #downcallHandle(FunctionDescriptor) Linking a foreign function} is a process which requires a function descriptor,
|
||||
* {@linkplain #downcallHandle(FunctionDescriptor, Option...) Linking a foreign function} is a process which requires a function descriptor,
|
||||
* a set of memory layouts which, together, specify the signature of the foreign function to be linked, and returns,
|
||||
* when complete, a downcall method handle, that is, a method handle that can be used to invoke the target foreign function.
|
||||
* <p>
|
||||
* The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is
|
||||
* {@linkplain #downcallType(FunctionDescriptor) derived} from the argument and return layouts in the function descriptor.
|
||||
* More specifically, given each layout {@code L} in the function descriptor, a corresponding carrier {@code C} is inferred,
|
||||
* as described below:
|
||||
* {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor.
|
||||
* The downcall method handle type, might then be decorated by additional leading parameters, in the given order if both are present:
|
||||
* <ul>
|
||||
* <li>if {@code L} is a {@link ValueLayout} with carrier {@code E} then there are two cases:
|
||||
* <ul>
|
||||
* <li>if {@code L} occurs in a parameter position and {@code E} is {@code MemoryAddress.class},
|
||||
* then {@code C = Addressable.class};</li>
|
||||
* <li>otherwise, {@code C = E};
|
||||
* </ul></li>
|
||||
* <li>or, if {@code L} is a {@link GroupLayout}, then {@code C} is set to {@code MemorySegment.class}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The downcall method handle type, derived as above, might be decorated by additional leading parameters,
|
||||
* in the given order if both are present:
|
||||
* <ul>
|
||||
* <li>If the downcall method handle is created {@linkplain #downcallHandle(FunctionDescriptor) without specifying a target address},
|
||||
* the downcall method handle type features a leading parameter of type {@link Addressable}, from which the
|
||||
* <li>If the downcall method handle is created {@linkplain #downcallHandle(FunctionDescriptor, Option...) without specifying a target address},
|
||||
* the downcall method handle type features a leading parameter of type {@link MemorySegment}, from which the
|
||||
* address of the target foreign function can be derived.</li>
|
||||
* <li>If the function descriptor's return layout is a group layout, the resulting downcall method handle accepts
|
||||
* an additional leading parameter of type {@link SegmentAllocator}, which is used by the linker runtime to allocate the
|
||||
|
@ -93,26 +80,15 @@ import java.lang.invoke.MethodType;
|
|||
*
|
||||
* <h2 id="upcall-stubs">Upcall stubs</h2>
|
||||
*
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) Creating an upcall stub} requires a method
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) Creating an upcall stub} requires a method
|
||||
* handle and a function descriptor; in this case, the set of memory layouts in the function descriptor
|
||||
* specify the signature of the function pointer associated with the upcall stub.
|
||||
* <p>
|
||||
* The type of the provided method handle has to {@linkplain #upcallType(FunctionDescriptor) match} the Java
|
||||
* {@linkplain java.lang.invoke.MethodType method type} associated with the upcall stub, which is derived from the argument
|
||||
* and return layouts in the function descriptor. More specifically, given each layout {@code L} in the function descriptor,
|
||||
* a corresponding carrier {@code C} is inferred, as described below:
|
||||
* <ul>
|
||||
* <li>If {@code L} is a {@link ValueLayout} with carrier {@code E} then there are two cases:
|
||||
* <ul>
|
||||
* <li>If {@code L} occurs in a return position and {@code E} is {@code MemoryAddress.class},
|
||||
* then {@code C = Addressable.class};</li>
|
||||
* <li>Otherwise, {@code C = E};
|
||||
* </ul></li>
|
||||
* <li>Or, if {@code L} is a {@link GroupLayout}, then {@code C} is set to {@code MemorySegment.class}</li>
|
||||
* </ul>
|
||||
* The type of the provided method handle's type has to match the method type associated with the upcall stub,
|
||||
* which is {@linkplain FunctionDescriptor#toMethodType() derived} from the provided function descriptor.
|
||||
* <p>
|
||||
* Upcall stubs are modelled by instances of type {@link MemorySegment}; upcall stubs can be passed by reference to other
|
||||
* downcall method handles (as {@link MemorySegment} implements the {@link Addressable} interface) and,
|
||||
* when no longer required, they can be {@linkplain MemorySession#close() released}, via their associated {@linkplain MemorySession session}.
|
||||
* downcall method handles and, they are released via their associated {@linkplain SegmentScope scope}.
|
||||
*
|
||||
* <h2 id="safety">Safety considerations</h2>
|
||||
*
|
||||
|
@ -121,23 +97,34 @@ import java.lang.invoke.MethodType;
|
|||
* the linker runtime cannot validate linkage requests. When a client interacts with a downcall method handle obtained
|
||||
* through an invalid linkage request (e.g. by specifying a function descriptor featuring too many argument layouts),
|
||||
* the result of such interaction is unspecified and can lead to JVM crashes. On downcall handle invocation,
|
||||
* the linker runtime guarantees the following for any argument that is a memory resource {@code R} (of type {@link MemorySegment}
|
||||
* or {@link VaList}):
|
||||
* the linker runtime guarantees the following for any argument {@code A} of type {@link MemorySegment} whose corresponding
|
||||
* layout is {@link ValueLayout#ADDRESS}:
|
||||
* <ul>
|
||||
* <li>The memory session of {@code R} is {@linkplain MemorySession#isAlive() alive}. Otherwise, the invocation throws
|
||||
* <li>The scope of {@code A} is {@linkplain SegmentScope#isAlive() alive}. Otherwise, the invocation throws
|
||||
* {@link IllegalStateException};</li>
|
||||
* <li>The invocation occurs in same thread as the one {@linkplain MemorySession#ownerThread() owning} the memory session of {@code R},
|
||||
* if said session is confined. Otherwise, the invocation throws {@link WrongThreadException}; and</li>
|
||||
* <li>The memory session of {@code R} is {@linkplain MemorySession#whileAlive(Runnable) kept alive} (and cannot be closed) during the invocation.</li>
|
||||
* <li>The invocation occurs in a thread {@code T} such that {@code A.scope().isAccessibleBy(T) == true}.
|
||||
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
|
||||
* <li>The scope of {@code A} is {@linkplain SegmentScope#whileAlive(Runnable) kept alive} during the invocation.</li>
|
||||
*</ul>
|
||||
* A downcall method handle created from a function descriptor whose return layout is an
|
||||
* {@linkplain ValueLayout.OfAddress address layout} returns a native segment associated with
|
||||
* the {@linkplain SegmentScope#global() global scope}. Under normal conditions, the size of the returned segment is {@code 0}.
|
||||
* However, if the return layout is an {@linkplain ValueLayout.OfAddress#asUnbounded() unbounded} address layout,
|
||||
* then the size of the returned segment is {@code Long.MAX_VALUE}.
|
||||
* <p>
|
||||
* When creating upcall stubs the linker runtime validates the type of the target method handle against the provided
|
||||
* function descriptor and report an error if any mismatch is detected. As for downcalls, JVM crashes might occur,
|
||||
* if the foreign code casts the function pointer associated with an upcall stub to a type
|
||||
* that is incompatible with the provided function descriptor. Moreover, if the target method
|
||||
* handle associated with an upcall stub returns a {@linkplain MemoryAddress memory address}, clients must ensure
|
||||
* handle associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, clients must ensure
|
||||
* that this address cannot become invalid after the upcall completes. This can lead to unspecified behavior,
|
||||
* and even JVM crashes, since an upcall is typically executed in the context of a downcall method handle invocation.
|
||||
* <p>
|
||||
* An upcall stub argument whose corresponding layout is an {@linkplain ValueLayout.OfAddress address layout}
|
||||
* is a native segment associated with the {@linkplain SegmentScope#global() global scope}.
|
||||
* Under normal conditions, the size of this segment argument is {@code 0}. However, if the layout associated with
|
||||
* the upcall stub argument is an {@linkplain ValueLayout.OfAddress#asUnbounded() unbounded} address layout,
|
||||
* then the size of the segment argument is {@code Long.MAX_VALUE}.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
|
@ -159,22 +146,22 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* and its corresponding layout is dependent on the ABI of the returned linker;
|
||||
* <li>Composite types are modelled by a {@linkplain GroupLayout group layout}. Depending on the ABI of the
|
||||
* returned linker, additional {@linkplain MemoryLayout#paddingLayout(long) padding} member layouts might be required to conform
|
||||
* to the size and alignment constraints of a composite type definition in C (e.g. using {@code struct} or {@code union}); and</li>
|
||||
* <li>Pointer types are modelled by a {@linkplain ValueLayout value layout} instance with carrier {@link MemoryAddress}.
|
||||
* to the size and alignment constraint of a composite type definition in C (e.g. using {@code struct} or {@code union}); and</li>
|
||||
* <li>Pointer types are modelled by a {@linkplain ValueLayout value layout} instance with carrier {@link MemorySegment}.
|
||||
* Examples of pointer types in C are {@code int**} and {@code int(*)(size_t*, size_t*)};</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Any layout not listed above is <em>unsupported</em>; function descriptors containing unsupported layouts
|
||||
* will cause an {@link IllegalArgumentException} to be thrown, when used to create a
|
||||
* {@link #downcallHandle(Addressable, FunctionDescriptor) downcall method handle} or an
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stub}.
|
||||
* {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handle} or an
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) upcall stub}.
|
||||
* <p>
|
||||
* Variadic functions (e.g. a C function declared with a trailing ellipses {@code ...} at the end of the formal parameter
|
||||
* list or with an empty formal parameter list) are not supported directly. However, it is possible to link a
|
||||
* variadic function by using a {@linkplain FunctionDescriptor#asVariadic(MemoryLayout...) <em>variadic</em>}
|
||||
* function descriptor, in which the specialized signature of a given variable arity callsite is described in full.
|
||||
* Alternatively, where the foreign library allows it, clients might be able to interact with variadic functions by
|
||||
* passing a trailing parameter of type {@link VaList} (e.g. as in {@code vsprintf}).
|
||||
* variadic function by using {@linkplain Linker.Option#firstVariadicArg(int) a linker option} to indicate
|
||||
* the start of the list of variadic arguments, together with a specialized function descriptor describing a
|
||||
* given variable arity callsite. Alternatively, where the foreign library allows it, clients might be able to
|
||||
* interact with variadic functions by passing a trailing parameter of type {@link VaList} (e.g. as in {@code vsprintf}).
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
|
@ -199,55 +186,60 @@ public sealed interface Linker permits AbstractLinker {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle which can be used to call a target foreign function with the given signature and address.
|
||||
* Creates a method handle which can be used to call a foreign function with the given signature and address.
|
||||
* <p>
|
||||
* If the provided method type's return type is {@code MemorySegment}, then the resulting method handle features
|
||||
* an additional prefix parameter, of type {@link SegmentAllocator}, which will be used by the linker runtime
|
||||
* to allocate structs returned by-value.
|
||||
* an additional prefix parameter, of type {@link SegmentAllocator}, which will be used by the linker to allocate
|
||||
* structs returned by-value.
|
||||
* <p>
|
||||
* Calling this method is equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* linker.downcallHandle(function).bindTo(symbol);
|
||||
* }
|
||||
*
|
||||
* @param symbol the address of the target function.
|
||||
* @param symbol the address of the target function.
|
||||
* @param function the function descriptor of the target function.
|
||||
* @param options any linker options.
|
||||
* @return a downcall method handle. The method handle type is <a href="Linker.html#downcall-method-handles"><em>inferred</em></a>
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
|
||||
* or if the symbol is {@link MemoryAddress#NULL}
|
||||
* or if the symbol is {@link MemorySegment#NULL}
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given.
|
||||
*/
|
||||
default MethodHandle downcallHandle(Addressable symbol, FunctionDescriptor function) {
|
||||
default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
|
||||
SharedUtils.checkSymbol(symbol);
|
||||
return downcallHandle(function).bindTo(symbol);
|
||||
return downcallHandle(function, options).bindTo(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle which can be used to call a target foreign function with the given signature.
|
||||
* Creates a method handle which can be used to call a foreign function with the given signature.
|
||||
* The resulting method handle features a prefix parameter (as the first parameter) corresponding to the foreign function
|
||||
* entry point, of type {@link Addressable}, which is used to specify the address of the target function
|
||||
* entry point, of type {@link MemorySegment}, which is used to specify the address of the target function
|
||||
* to be called.
|
||||
* <p>
|
||||
* If the provided function descriptor's return layout is a {@link GroupLayout}, then the resulting method handle features an
|
||||
* additional prefix parameter (inserted immediately after the address parameter), of type {@link SegmentAllocator}),
|
||||
* which will be used by the linker runtime to allocate structs returned by-value.
|
||||
* which will be used by the linker to allocate structs returned by-value.
|
||||
* <p>
|
||||
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link Addressable} parameter passed to it is
|
||||
* associated with the {@link MemoryAddress#NULL} address, or a {@link NullPointerException} if that parameter is {@code null}.
|
||||
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment} parameter passed to it is
|
||||
* associated with the {@link MemorySegment#NULL} address, or a {@link NullPointerException} if that parameter is {@code null}.
|
||||
*
|
||||
* @param function the function descriptor of the target function.
|
||||
* @param options any linker options.
|
||||
* @return a downcall method handle. The method handle type is <a href="Linker.html#downcall-method-handles"><em>inferred</em></a>
|
||||
* from the provided function descriptor.
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given.
|
||||
*/
|
||||
MethodHandle downcallHandle(FunctionDescriptor function);
|
||||
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
|
||||
|
||||
/**
|
||||
* Creates a stub which can be passed to other foreign functions as a function pointer, with the given
|
||||
* memory session. Calling such a function pointer from foreign code will result in the execution of the provided
|
||||
* Creates a stub which can be passed to other foreign functions as a function pointer, associated with the given
|
||||
* scope. Calling such a function pointer from foreign code will result in the execution of the provided
|
||||
* method handle.
|
||||
* <p>
|
||||
* The returned memory segment's base address points to the newly allocated upcall stub, and is associated with
|
||||
* the provided memory session. When such session is closed, the corresponding upcall stub will be deallocated.
|
||||
* The returned memory segment's address points to the newly allocated upcall stub, and is associated with
|
||||
* the provided scope. As such, the corresponding upcall stub will be deallocated
|
||||
* when the scope becomes not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* <p>
|
||||
* The target method handle should not throw any exceptions. If the target method handle does throw an exception,
|
||||
* the VM will exit with a non-zero exit code. To avoid the VM aborting due to an uncaught exception, clients
|
||||
|
@ -257,16 +249,16 @@ public sealed interface Linker permits AbstractLinker {
|
|||
*
|
||||
* @param target the target method handle.
|
||||
* @param function the upcall stub function descriptor.
|
||||
* @param session the upcall stub memory session.
|
||||
* @return a zero-length segment whose base address is the address of the upcall stub.
|
||||
* @param scope the scope associated with the returned upcall stub segment.
|
||||
* @return a zero-length segment whose address is the address of the upcall stub.
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
|
||||
* @throws IllegalArgumentException if it is determined that the target method handle can throw an exception, or if the target method handle
|
||||
* has a type that does not match the upcall stub <a href="Linker.html#upcall-stubs"><em>inferred type</em></a>.
|
||||
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread
|
||||
* {@linkplain MemorySession#ownerThread() owning} {@code session}.
|
||||
* @throws IllegalStateException if {@code scope} is not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code scope.isAccessibleBy(T) == false}.
|
||||
*/
|
||||
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session);
|
||||
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, SegmentScope scope);
|
||||
|
||||
/**
|
||||
* Returns a symbol lookup for symbols in a set of commonly used libraries.
|
||||
|
@ -284,22 +276,21 @@ public sealed interface Linker permits AbstractLinker {
|
|||
SymbolLookup defaultLookup();
|
||||
|
||||
/**
|
||||
* {@return the downcall method handle {@linkplain MethodType type} associated with the given function descriptor}
|
||||
* @param functionDescriptor a function descriptor.
|
||||
* @throws IllegalArgumentException if one or more layouts in the function descriptor are not supported
|
||||
* (e.g. if they are sequence layouts or padding layouts).
|
||||
* A linker option is used to indicate additional linking requirements to the linker,
|
||||
* besides what is described by a function descriptor.
|
||||
* @since 20
|
||||
*/
|
||||
static MethodType downcallType(FunctionDescriptor functionDescriptor) {
|
||||
return SharedUtils.inferMethodType(functionDescriptor, false);
|
||||
}
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface Option
|
||||
permits LinkerOptions.FirstVariadicArg {
|
||||
|
||||
/**
|
||||
* {@return the method handle {@linkplain MethodType type} associated with an upcall stub with the given function descriptor}
|
||||
* @param functionDescriptor a function descriptor.
|
||||
* @throws IllegalArgumentException if one or more layouts in the function descriptor are not supported
|
||||
* (e.g. if they are sequence layouts or padding layouts).
|
||||
*/
|
||||
static MethodType upcallType(FunctionDescriptor functionDescriptor) {
|
||||
return SharedUtils.inferMethodType(functionDescriptor, true);
|
||||
/**
|
||||
* {@return a linker option used to denote the index of the first variadic argument layout in a
|
||||
* foreign function call}
|
||||
* @param index the index of the first variadic argument in a downcall handle linkage request.
|
||||
*/
|
||||
static Option firstVariadicArg(int index) {
|
||||
return new LinkerOptions.FirstVariadicArg(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue