Skip to content

Commit

Permalink
8292047: Consider ways to add linkage parameters to downcall handles
Browse files Browse the repository at this point in the history
Reviewed-by: mcimadamore
  • Loading branch information
JornVernee committed Sep 22, 2022
1 parent 5b63be8 commit 60a47cb
Show file tree
Hide file tree
Showing 28 changed files with 239 additions and 170 deletions.
3 changes: 2 additions & 1 deletion doc/panama_ffi.md
Expand Up @@ -416,7 +416,8 @@ public class Examples {
public static void printf() throws Throwable {
MethodHandle printf = LINKER.downcallHandle(
STDLIB.lookup("printf").get(),
FunctionDescriptor.of(JAVA_INT, ADDRESS).asVariadic(JAVA_INT, JAVA_INT, JAVA_INT)
FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT),
Linker.Option.firstVariadicArg(1) // first int is variadic
);
try (MemorySession session = MemorySession.openConfined()) {
MemorySegment s = session.allocateUtf8String("%d plus %d equals %d\n");
Expand Down
Expand Up @@ -36,7 +36,7 @@
/**
* A function descriptor is made up of zero or more argument layouts and zero or one return layout. A function descriptor
* is used to model the signature of foreign functions when creating
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor) downcall method handles} or
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} or
* {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stubs}.
*
* @implSpec
Expand All @@ -58,13 +58,6 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
*/
List<MemoryLayout> argumentLayouts();

/**
* The index of the first variadic argument layout (where defined).
* @return The index of the first variadic argument layout, or {@code -1} if this is not a
* {@linkplain #asVariadic(MemoryLayout...) variadic} layout.
*/
int firstVariadicArgumentIndex();

/**
* Returns a function descriptor with the given argument layouts appended to the argument layout array
* of this function descriptor.
Expand Down Expand Up @@ -113,17 +106,6 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
*/
MethodType toMethodType();

/**
* Creates a specialized variadic function descriptor, by appending given variadic layouts to this
* function descriptor argument layouts. The resulting function descriptor can report the position
* of the {@linkplain #firstVariadicArgumentIndex() first variadic argument}, and cannot be altered
* in any way: for instance, calling {@link #changeReturnLayout(MemoryLayout)} on the resulting descriptor
* will throw an {@link UnsupportedOperationException}.
* @param variadicLayouts the variadic argument layouts to be appended to this descriptor argument layouts.
* @return a variadic function descriptor, or this descriptor if {@code variadicLayouts.length == 0}.
*/
FunctionDescriptor asVariadic(MemoryLayout... variadicLayouts);

/**
* Creates a function descriptor with the given return and argument layouts.
* @param resLayout the return layout.
Expand All @@ -145,5 +127,4 @@ static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
// Null checks are implicit in List.of(argLayouts)
return FunctionDescriptorImpl.ofVoid(List.of(argLayouts));
}

}
48 changes: 35 additions & 13 deletions src/java.base/share/classes/java/lang/foreign/Linker.java
Expand Up @@ -26,6 +26,7 @@
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;
Expand All @@ -46,7 +47,7 @@
* 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(MemorySegment, 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>
* </ul>
Expand All @@ -61,7 +62,7 @@
*
* <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>
Expand All @@ -77,7 +78,7 @@
* 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},
* <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
Expand Down Expand Up @@ -166,15 +167,15 @@ public sealed interface Linker permits AbstractLinker {
* <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(MemorySegment, FunctionDescriptor) downcall method handle} or an
* {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handle} or an
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) 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
Expand Down Expand Up @@ -210,15 +211,17 @@ static Linker nativeLinker() {
* 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 MemorySegment#NULL}
* or if the symbol is {@link MemorySegment#NULL}
* @throws IllegalArgumentException if an invalid combination of linker options is given.
*/
default MethodHandle downcallHandle(MemorySegment 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);
}

/**
Expand All @@ -235,11 +238,13 @@ default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor fun
* 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
Expand Down Expand Up @@ -282,4 +287,21 @@ default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor fun
* @return a symbol lookup for symbols in a set of commonly used libraries.
*/
SymbolLookup defaultLookup();

/**
* A linker option that can be used to indicate additional linking requirements to the linker,
* besides what is described by a function descriptor.
*/
sealed interface Option
permits LinkerOptions.FirstVariadicArg {

/**
* {@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);
}
}
}
Expand Up @@ -55,7 +55,7 @@
* <p>
* Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate <em>where</em>
* the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance,
* {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handles} can accept an additional
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} can accept an additional
* {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively,
* the allocator parameter tells the linker runtime where to store the return value of the foreign function.
*/
Expand Down
Expand Up @@ -51,7 +51,7 @@
* The address of a symbol is modelled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
* <ul>
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which can then be used to call the foreign function at the segment's base address.</li>
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle}, as an argument to the underlying foreign function.</li>
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, as an argument to the underlying foreign function.</li>
* <li>It can be {@linkplain MemorySegment#set(ValueLayout.OfAddress, long, MemorySegment) stored} inside another memory segment.</li>
* <li>It can be used to dereference memory associated with a global variable (this might require
* {@link MemorySegment#ofAddress(long, long, MemorySession) resizing} the segment first).</li>
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/foreign/VaList.java
Expand Up @@ -48,7 +48,7 @@
* .addVarg(C_DOUBLE, 3.8d));
*}
* Once created, clients can obtain the platform-dependent {@linkplain #segment() memory segment} associated a variable
* argument list, which can then be passed to {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handles}
* argument list, which can then be passed to {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles}
* targeting native functions using the C {@code va_list} type.
* <p>
* The contents of a foreign memory segment modelling a variable argument list can be accessed by <em>unsafely</em> creating
Expand Down
Expand Up @@ -128,7 +128,7 @@
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it
* to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} the {@code strlen} symbol in the
* standard C library; a <em>downcall method handle</em> targeting said symbol is subsequently
* {@linkplain java.lang.foreign.Linker#downcallHandle(java.lang.foreign.FunctionDescriptor) obtained}.
* {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}.
* To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance,
* describing the signature of the {@code strlen} function.
* From this information, the linker will uniquely determine the sequence of steps which will turn
Expand Down Expand Up @@ -225,7 +225,7 @@
*}
*
* The {@link java.lang.foreign.FunctionDescriptor} instance created in the previous step is then used to
* {@linkplain java.lang.foreign.Linker#upcallStub(java.lang.invoke.MethodHandle, java.lang.foreign.FunctionDescriptor, java.lang.foreign.MemorySession) create}
* {@linkplain java.lang.foreign.Linker#upcallStub(java.lang.invoke.MethodHandle, FunctionDescriptor, MemorySession) create}
* a new upcall stub; the layouts in the function descriptors allow the linker to determine the sequence of steps which
* allow foreign code to call the stub for {@code intCompareHandle} according to the rules specified by the ABI of the
* underlying platform.
Expand Down

0 comments on commit 60a47cb

Please sign in to comment.