diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java
index 71ef4200eeb..ed416cf1eb1 100644
--- a/src/java.base/share/classes/java/lang/foreign/Linker.java
+++ b/src/java.base/share/classes/java/lang/foreign/Linker.java
@@ -430,11 +430,6 @@ public sealed interface Linker permits AbstractLinker {
/**
* Returns a linker for the ABI associated with the underlying native platform. The underlying native platform
* is the combination of OS and processor where the Java runtime is currently executing.
- *
- * This method is restricted.
- * Restricted methods are unsafe, and, if used incorrectly, their use might crash
- * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
- * restricted methods, and use safe and supported functionalities, where possible.
*
* @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor.
* @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup} associated with the returned
@@ -443,11 +438,8 @@ public sealed interface Linker permits AbstractLinker {
*
* @return a linker for the ABI associated with the underlying native platform.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
- * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
- @CallerSensitive
static Linker nativeLinker() {
- Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "nativeLinker");
return SharedUtils.getSystemLinker();
}
@@ -458,6 +450,11 @@ public sealed interface Linker permits AbstractLinker {
* {@snippet lang=java :
* linker.downcallHandle(function).bindTo(symbol);
* }
+ *
+ * This method is restricted.
+ * Restricted methods are unsafe, and, if used incorrectly, their use might crash
+ * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
+ * restricted methods, and use safe and supported functionalities, where possible.
*
* @param symbol the address of the target function.
* @param function the function descriptor of the target function.
@@ -466,11 +463,10 @@ public sealed interface Linker permits AbstractLinker {
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* or if the symbol is {@link MemorySegment#NULL}
* @throws IllegalArgumentException if an invalid combination of linker options is given.
+ * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
- default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
- SharedUtils.checkSymbol(symbol);
- return downcallHandle(function, options).bindTo(symbol);
- }
+ @CallerSensitive
+ MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options);
/**
* Creates a method handle which is used to call a foreign function with the given signature.
@@ -502,6 +498,11 @@ public sealed interface Linker permits AbstractLinker {
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment}
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address.
* The returned method handle will additionally throw {@link NullPointerException} if any argument passed to it is {@code null}.
+ *
+ * This method is restricted.
+ * Restricted methods are unsafe, and, if used incorrectly, their use might crash
+ * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
+ * restricted methods, and use safe and supported functionalities, where possible.
*
* @param function the function descriptor of the target function.
* @param options any linker options.
@@ -509,7 +510,9 @@ public sealed interface Linker permits AbstractLinker {
* 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.
+ * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
+ @CallerSensitive
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
/**
@@ -533,6 +536,11 @@ public sealed interface Linker permits AbstractLinker {
* could wrap all code in the target method handle in a try/catch block that catches any {@link Throwable}, for
* instance by using the {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)}
* method handle combinator, and handle exceptions as desired in the corresponding catch block.
+ *
+ * This method is restricted.
+ * Restricted methods are unsafe, and, if used incorrectly, their use might crash
+ * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
+ * restricted methods, and use safe and supported functionalities, where possible.
*
* @param target the target method handle.
* @param function the upcall stub function descriptor.
@@ -545,7 +553,9 @@ public sealed interface Linker permits AbstractLinker {
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
* thread {@code T}, other than the arena's owner thread.
+ * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
+ @CallerSensitive
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options);
/**
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java
index f7a2b9114c1..1c6ee128c2b 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java
@@ -34,6 +34,8 @@ import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
import jdk.internal.foreign.layout.AbstractLayout;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.GroupLayout;
@@ -67,7 +69,21 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
private final SoftReferenceCache UPCALL_CACHE = new SoftReferenceCache<>();
@Override
- public MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
+ @CallerSensitive
+ public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
+ Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
+ SharedUtils.checkSymbol(symbol);
+ return downcallHandle0(function, options).bindTo(symbol);
+ }
+
+ @Override
+ @CallerSensitive
+ public final MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
+ Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
+ return downcallHandle0(function, options);
+ }
+
+ private final MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) {
Objects.requireNonNull(function);
Objects.requireNonNull(options);
checkLayouts(function);
@@ -82,10 +98,13 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
return handle;
});
}
+
protected abstract MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options);
@Override
- public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options) {
+ @CallerSensitive
+ public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options) {
+ Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "upcallStub");
Objects.requireNonNull(arena);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
diff --git a/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java b/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java
index a6667d1240f..a9bcb929a25 100644
--- a/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java
+++ b/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java
@@ -24,6 +24,8 @@
package org.openjdk.foreigntest;
import java.lang.foreign.*;
+import java.lang.foreign.Linker.Option;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
@@ -36,31 +38,25 @@ public class PanamaMainUnnamedModule {
public static void main(String[] args) throws Throwable {
testReflection();
- testSetAccessible();
testInvoke();
testDirectAccess();
testJNIAccess();
}
public static void testReflection() throws Throwable {
- Method method = Linker.class.getDeclaredMethod("nativeLinker");
- method.invoke(null);
- }
-
- public static void testSetAccessible() throws Throwable {
- Method method = Linker.class.getDeclaredMethod("nativeLinker");
- method.setAccessible(true);
- method.invoke(null);
+ Linker linker = Linker.nativeLinker();
+ Method method = Linker.class.getDeclaredMethod("downcallHandle", FunctionDescriptor.class, Option[].class);
+ method.invoke(linker, FunctionDescriptor.ofVoid(), new Linker.Option[0]);
}
public static void testInvoke() throws Throwable {
- var mh = MethodHandles.lookup().findStatic(Linker.class, "nativeLinker",
- MethodType.methodType(Linker.class));
- var linker = (Linker)mh.invokeExact();
+ var mh = MethodHandles.lookup().findVirtual(Linker.class, "downcallHandle",
+ MethodType.methodType(MethodHandle.class, FunctionDescriptor.class, Linker.Option[].class));
+ var downcall = (MethodHandle)mh.invokeExact(Linker.nativeLinker(), FunctionDescriptor.ofVoid(), new Linker.Option[0]);
}
public static void testDirectAccess() {
- Linker.nativeLinker();
+ Linker.nativeLinker().downcallHandle(FunctionDescriptor.ofVoid());
}
public static void testJNIAccess() {
diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java
index f6792133a91..484341b2094 100644
--- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java
+++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java
@@ -27,8 +27,8 @@ import java.lang.foreign.*;
public class PanamaMain {
public static void main(String[] args) {
- System.out.println("Trying to get Linker");
- Linker.nativeLinker();
- System.out.println("Got Linker");
+ System.out.println("Trying to obtain a downcall handle");
+ Linker.nativeLinker().downcallHandle(FunctionDescriptor.ofVoid());
+ System.out.println("Got downcall handle");
}
}
diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainDirect.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainDirect.java
index 71a8a6bb58e..9e63af039d6 100644
--- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainDirect.java
+++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainDirect.java
@@ -33,9 +33,9 @@ public class PanamaMainDirect {
}
public static void testDirectAccessCLinker() {
- System.out.println("Trying to get Linker");
- Linker.nativeLinker();
- System.out.println("Got Linker");
+ System.out.println("Trying to obtain a downcall handle");
+ Linker.nativeLinker().downcallHandle(FunctionDescriptor.ofVoid());
+ System.out.println("Got downcall handle");
}
public static void testDirectAccessMemorySegment() {
diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java
index ef75fa822c0..991d4118afc 100644
--- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java
+++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java
@@ -34,11 +34,12 @@ public class PanamaMainInvoke {
}
public static void testInvokenativeLinker() throws Throwable {
- System.out.println("Trying to get Linker");
- var mh = MethodHandles.lookup().findStatic(Linker.class, "nativeLinker",
- MethodType.methodType(Linker.class));
- var linker = (Linker)mh.invokeExact();
- System.out.println("Got Linker");
+ Linker linker = Linker.nativeLinker();
+ System.out.println("Trying to obtain a downcall handle");
+ var mh = MethodHandles.lookup().findVirtual(Linker.class, "downcallHandle",
+ MethodType.methodType(MethodHandle.class, FunctionDescriptor.class, Linker.Option[].class));
+ var handle = (MethodHandle)mh.invokeExact(linker, FunctionDescriptor.ofVoid(), new Linker.Option[0]);
+ System.out.println("Got downcall handle");
}
public static void testInvokeMemorySegment() throws Throwable {
diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java
index cc408e2d432..164ee5852cc 100644
--- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java
+++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java
@@ -1,5 +1,8 @@
package org.openjdk.foreigntest;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.Linker;
+
public class PanamaMainJNI {
static {
@@ -11,10 +14,10 @@ public class PanamaMainJNI {
}
public static void testDirectAccessCLinker() {
- System.out.println("Trying to get Linker");
- nativeLinker0();
- System.out.println("Got Linker");
+ System.out.println("Trying to get downcall handle");
+ nativeLinker0(Linker.nativeLinker(), FunctionDescriptor.ofVoid(), new Linker.Option[0]);
+ System.out.println("Got downcall handle");
}
- static native void nativeLinker0();
+ static native void nativeLinker0(Linker linker, FunctionDescriptor desc, Linker.Option[] options);
}
diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java
index a32f3edca06..1db42d42be2 100644
--- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java
+++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java
@@ -25,6 +25,7 @@ package org.openjdk.foreigntest;
import java.lang.foreign.*;
import java.lang.foreign.Arena;
+import java.lang.foreign.Linker.Option;
import java.lang.reflect.Method;
public class PanamaMainReflection {
@@ -34,10 +35,11 @@ public class PanamaMainReflection {
}
public static void testReflectionnativeLinker() throws Throwable {
- System.out.println("Trying to get Linker");
- Method method = Linker.class.getDeclaredMethod("nativeLinker");
- method.invoke(null);
- System.out.println("Got Linker");
+ Linker linker = Linker.nativeLinker();
+ System.out.println("Trying to get downcall handle");
+ Method method = Linker.class.getDeclaredMethod("downcallHandle", FunctionDescriptor.class, Option[].class);
+ method.invoke(linker, FunctionDescriptor.ofVoid(), new Linker.Option[0]);
+ System.out.println("Got downcall handle");
}
public static void testReflectionMemorySegment() throws Throwable {
diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp
index 3358c5e3a22..474738a584d 100644
--- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp
+++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp
@@ -25,21 +25,32 @@
#include "jni.h"
#include "testlib_threads.h"
-void call(void* ctxt) {
- JavaVM *jvm = (JavaVM*) ctxt;
+typedef struct {
+ JavaVM* jvm;
+ jobject linker;
+ jobject desc;
+ jarray opts;
+} Context;
+
+void call(void* arg) {
+ Context* context = (Context*)arg;
JNIEnv* env;
- jvm->AttachCurrentThread((void**)&env, NULL);
+ context->jvm->AttachCurrentThread((void**)&env, NULL);
jclass linkerClass = env->FindClass("java/lang/foreign/Linker");
- jmethodID nativeLinkerMethod = env->GetStaticMethodID(linkerClass, "nativeLinker", "()Ljava/lang/foreign/Linker;");
- env->CallStaticVoidMethod(linkerClass, nativeLinkerMethod);
- jvm->DetachCurrentThread();
+ jmethodID nativeLinkerMethod = env->GetMethodID(linkerClass, "downcallHandle",
+ "(Ljava/lang/foreign/FunctionDescriptor;[Ljava/lang/foreign/Linker$Option;)Ljava/lang/invoke/MethodHandle;");
+ env->CallVoidMethod(context->linker, nativeLinkerMethod, context->desc, context->opts);
+ context->jvm->DetachCurrentThread();
}
extern "C" {
JNIEXPORT void JNICALL
- Java_org_openjdk_foreigntest_PanamaMainJNI_nativeLinker0(JNIEnv *env, jclass cls) {
- JavaVM* jvm;
- env->GetJavaVM(&jvm);
- run_in_new_thread_and_join(call, jvm);
+ Java_org_openjdk_foreigntest_PanamaMainJNI_nativeLinker0(JNIEnv *env, jclass cls, jobject linker, jobject desc, jarray opts) {
+ Context context;
+ env->GetJavaVM(&context.jvm);
+ context.linker = linker;
+ context.desc = desc;
+ context.opts = opts;
+ run_in_new_thread_and_join(call, &context);
}
}
diff --git a/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java b/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java
index dc212d51d09..9b696caa82d 100644
--- a/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java
+++ b/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java
@@ -59,7 +59,7 @@ public class MethodHandleInvoker {
static final Map, Object> DEFAULT_VALUES = new HashMap<>();
- static void addDefaultMapping(Class carrier, Z value) {
+ static void addDefaultMapping(Class> carrier, Object value) {
DEFAULT_VALUES.put(carrier, value);
}
@@ -67,7 +67,7 @@ public class MethodHandleInvoker {
addDefaultMapping(Linker.class, Linker.nativeLinker());
addDefaultMapping(Path.class, Path.of("nonExistent"));
addDefaultMapping(String.class, "Hello!");
- addDefaultMapping(Runnable.class, () -> {});
+ addDefaultMapping(Runnable.class, (Runnable)() -> {});
addDefaultMapping(MethodHandle.class, MethodHandles.identity(int.class));
addDefaultMapping(Charset.class, Charset.defaultCharset());
addDefaultMapping(MethodType.class, MethodType.methodType(void.class));
@@ -88,6 +88,8 @@ public class MethodHandleInvoker {
addDefaultMapping(AddressLayout.class, ValueLayout.ADDRESS);
addDefaultMapping(SymbolLookup.class, SymbolLookup.loaderLookup());
addDefaultMapping(Consumer.class, (Consumer