From 62ba14a697c66615a9aeb3cb9b1f0ed64a632a81 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 14 Jul 2025 15:41:28 +0200 Subject: [PATCH 1/3] add test --- .../java/foreign/TestUpcallStructScope.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/foreign/TestUpcallStructScope.java b/test/jdk/java/foreign/TestUpcallStructScope.java index 14809139dff92..b4791931e898a 100644 --- a/test/jdk/java/foreign/TestUpcallStructScope.java +++ b/test/jdk/java/foreign/TestUpcallStructScope.java @@ -43,13 +43,17 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; import java.util.function.Consumer; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; public class TestUpcallStructScope extends NativeTestHelper { static final MethodHandle MH_do_upcall; static final MethodHandle MH_Consumer_accept; + static final MethodHandle MH_BiConsumer_accept; static { System.loadLibrary("TestUpcallStructScope"); @@ -61,13 +65,21 @@ public class TestUpcallStructScope extends NativeTestHelper { try { MH_Consumer_accept = MethodHandles.publicLookup().findVirtual(Consumer.class, "accept", MethodType.methodType(void.class, Object.class)); + MH_BiConsumer_accept = MethodHandles.publicLookup().findVirtual(BiConsumer.class, "accept", + MethodType.methodType(void.class, Object.class, Object.class)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new RuntimeException(e); } } - private static MethodHandle methodHandle (Consumer callback) { - return MH_Consumer_accept.bindTo(callback).asType(MethodType.methodType(void.class, MemorySegment.class)); + private static MethodHandle methodHandle(Consumer callback) { + return MH_Consumer_accept.bindTo(callback) + .asType(MethodType.methodType(void.class, MemorySegment.class)); + } + + private static MethodHandle methodHandle(BiConsumer callback) { + return MH_Consumer_accept.bindTo(callback) + .asType(MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); } @Test @@ -85,4 +97,22 @@ public void testUpcall() throws Throwable { assertFalse(captured.scope().isAlive()); } + @Test + public void testOtherPointer() throws Throwable { + AtomicReference capturedSegment = new AtomicReference<>(); + MethodHandle target = methodHandle((_, addr) -> capturedSegment.set(addr)); + FunctionDescriptor upcallDesc = FunctionDescriptor.ofVoid(S_PDI_LAYOUT, C_POINTER); + MemorySegment argAddr = MemorySegment.ofAddress(42); + try (Arena arena = Arena.ofConfined()) { + MemorySegment upcallStub = LINKER.upcallStub(target, upcallDesc, arena); + MemorySegment argSegment = arena.allocate(S_PDI_LAYOUT); + MH_do_upcall.invoke(upcallStub, argSegment, argAddr); + } + + // We've captured the address '42' from the upcall. This should have + // the global scope, so it should still be alive here. + MemorySegment captured = capturedSegment.get(); + assertEquals(argAddr, captured); + assertTrue(captured.scope().isAlive()); + } } From 9ec332ced427ba85d186b75a749f23e3b7b8225f Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 14 Jul 2025 14:07:01 +0000 Subject: [PATCH 2/3] fix test --- test/jdk/java/foreign/TestUpcallStructScope.java | 9 +++++++-- test/jdk/java/foreign/libTestUpcallStructScope.c | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/foreign/TestUpcallStructScope.java b/test/jdk/java/foreign/TestUpcallStructScope.java index b4791931e898a..d9729cb8f3be7 100644 --- a/test/jdk/java/foreign/TestUpcallStructScope.java +++ b/test/jdk/java/foreign/TestUpcallStructScope.java @@ -52,6 +52,7 @@ public class TestUpcallStructScope extends NativeTestHelper { static final MethodHandle MH_do_upcall; + static final MethodHandle MH_do_upcall_ptr; static final MethodHandle MH_Consumer_accept; static final MethodHandle MH_BiConsumer_accept; @@ -61,6 +62,10 @@ public class TestUpcallStructScope extends NativeTestHelper { findNativeOrThrow("do_upcall"), FunctionDescriptor.ofVoid(C_POINTER, S_PDI_LAYOUT) ); + MH_do_upcall_ptr = LINKER.downcallHandle( + findNativeOrThrow("do_upcall_ptr"), + FunctionDescriptor.ofVoid(C_POINTER, S_PDI_LAYOUT, C_POINTER) + ); try { MH_Consumer_accept = MethodHandles.publicLookup().findVirtual(Consumer.class, "accept", @@ -78,7 +83,7 @@ private static MethodHandle methodHandle(Consumer callback) { } private static MethodHandle methodHandle(BiConsumer callback) { - return MH_Consumer_accept.bindTo(callback) + return MH_BiConsumer_accept.bindTo(callback) .asType(MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); } @@ -106,7 +111,7 @@ public void testOtherPointer() throws Throwable { try (Arena arena = Arena.ofConfined()) { MemorySegment upcallStub = LINKER.upcallStub(target, upcallDesc, arena); MemorySegment argSegment = arena.allocate(S_PDI_LAYOUT); - MH_do_upcall.invoke(upcallStub, argSegment, argAddr); + MH_do_upcall_ptr.invoke(upcallStub, argSegment, argAddr); } // We've captured the address '42' from the upcall. This should have diff --git a/test/jdk/java/foreign/libTestUpcallStructScope.c b/test/jdk/java/foreign/libTestUpcallStructScope.c index e778133b496de..e18543d5b1ae2 100644 --- a/test/jdk/java/foreign/libTestUpcallStructScope.c +++ b/test/jdk/java/foreign/libTestUpcallStructScope.c @@ -28,3 +28,7 @@ struct S_PDI { void* p0; double p1; int p2; }; EXPORT void do_upcall(void (*cb)(struct S_PDI), struct S_PDI a0) { cb(a0); } + +EXPORT void do_upcall_ptr(void (*cb)(struct S_PDI, void*), struct S_PDI a0, void* ptr) { + cb(a0, ptr); +} From 0b3aa10a4daefd60a18e26ad2ce11c6aaaeaf5ce Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 14 Jul 2025 15:30:30 +0000 Subject: [PATCH 3/3] fix --- .../jdk/internal/foreign/abi/BindingSpecializer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java index a1323e16945aa..20ccec61fd2ed 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java @@ -297,7 +297,7 @@ private void specialize() { if (callingSequence.allocationSize() != 0) { cb.loadConstant(callingSequence.allocationSize()) .invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA); - } else if (callingSequence.forUpcall() && needsSession()) { + } else if (callingSequence.forUpcall() && anyArgNeedsScope()) { cb.invokestatic(CD_SharedUtils, "newEmptyArena", MTD_NEW_EMPTY_ARENA); } else { cb.getstatic(CD_SharedUtils, "DUMMY_ARENA", CD_Arena); @@ -437,7 +437,7 @@ private void specialize() { cb.exceptionCatchAll(tryStart, tryEnd, catchStart); } - private boolean needsSession() { + private boolean anyArgNeedsScope() { return callingSequence.argumentBindings() .filter(BoxAddress.class::isInstance) .map(BoxAddress.class::cast) @@ -590,7 +590,7 @@ private void emitBoxAddress(BoxAddress boxAddress) { popType(long.class); cb.loadConstant(boxAddress.size()) .loadConstant(boxAddress.align()); - if (needsSession()) { + if (boxAddress.needsScope()) { emitLoadInternalSession(); cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_SCOPE); } else {