4343import java .lang .invoke .MethodHandles ;
4444import java .lang .invoke .MethodType ;
4545import java .util .concurrent .atomic .AtomicReference ;
46+ import java .util .function .BiConsumer ;
4647import java .util .function .Consumer ;
4748
4849import static org .testng .Assert .assertFalse ;
50+ import static org .testng .Assert .assertTrue ;
51+ import static org .testng .Assert .assertEquals ;
4952
5053public class TestUpcallStructScope extends NativeTestHelper {
5154 static final MethodHandle MH_do_upcall ;
55+ static final MethodHandle MH_do_upcall_ptr ;
5256 static final MethodHandle MH_Consumer_accept ;
57+ static final MethodHandle MH_BiConsumer_accept ;
5358
5459 static {
5560 System .loadLibrary ("TestUpcallStructScope" );
5661 MH_do_upcall = LINKER .downcallHandle (
5762 findNativeOrThrow ("do_upcall" ),
5863 FunctionDescriptor .ofVoid (C_POINTER , S_PDI_LAYOUT )
5964 );
65+ MH_do_upcall_ptr = LINKER .downcallHandle (
66+ findNativeOrThrow ("do_upcall_ptr" ),
67+ FunctionDescriptor .ofVoid (C_POINTER , S_PDI_LAYOUT , C_POINTER )
68+ );
6069
6170 try {
6271 MH_Consumer_accept = MethodHandles .publicLookup ().findVirtual (Consumer .class , "accept" ,
6372 MethodType .methodType (void .class , Object .class ));
73+ MH_BiConsumer_accept = MethodHandles .publicLookup ().findVirtual (BiConsumer .class , "accept" ,
74+ MethodType .methodType (void .class , Object .class , Object .class ));
6475 } catch (NoSuchMethodException | IllegalAccessException e ) {
6576 throw new RuntimeException (e );
6677 }
6778 }
6879
69- private static MethodHandle methodHandle (Consumer <MemorySegment > callback ) {
70- return MH_Consumer_accept .bindTo (callback ).asType (MethodType .methodType (void .class , MemorySegment .class ));
80+ private static MethodHandle methodHandle (Consumer <MemorySegment > callback ) {
81+ return MH_Consumer_accept .bindTo (callback )
82+ .asType (MethodType .methodType (void .class , MemorySegment .class ));
83+ }
84+
85+ private static MethodHandle methodHandle (BiConsumer <MemorySegment , MemorySegment > callback ) {
86+ return MH_BiConsumer_accept .bindTo (callback )
87+ .asType (MethodType .methodType (void .class , MemorySegment .class , MemorySegment .class ));
7188 }
7289
7390 @ Test
@@ -85,4 +102,22 @@ public void testUpcall() throws Throwable {
85102 assertFalse (captured .scope ().isAlive ());
86103 }
87104
105+ @ Test
106+ public void testOtherPointer () throws Throwable {
107+ AtomicReference <MemorySegment > capturedSegment = new AtomicReference <>();
108+ MethodHandle target = methodHandle ((_ , addr ) -> capturedSegment .set (addr ));
109+ FunctionDescriptor upcallDesc = FunctionDescriptor .ofVoid (S_PDI_LAYOUT , C_POINTER );
110+ MemorySegment argAddr = MemorySegment .ofAddress (42 );
111+ try (Arena arena = Arena .ofConfined ()) {
112+ MemorySegment upcallStub = LINKER .upcallStub (target , upcallDesc , arena );
113+ MemorySegment argSegment = arena .allocate (S_PDI_LAYOUT );
114+ MH_do_upcall_ptr .invoke (upcallStub , argSegment , argAddr );
115+ }
116+
117+ // We've captured the address '42' from the upcall. This should have
118+ // the global scope, so it should still be alive here.
119+ MemorySegment captured = capturedSegment .get ();
120+ assertEquals (argAddr , captured );
121+ assertTrue (captured .scope ().isAlive ());
122+ }
88123}
0 commit comments