From 61ce36d429325e8e9848d84c233bec62f930665b Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Fri, 23 Aug 2024 13:43:08 +0200 Subject: [PATCH 1/2] Adapt pointer to closure --- .../java/jnr/ffi/provider/ClosureManager.java | 1 + .../ffi/provider/jffi/NativeClosureManager.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/main/java/jnr/ffi/provider/ClosureManager.java b/src/main/java/jnr/ffi/provider/ClosureManager.java index 32c56c3a1..7076c46af 100644 --- a/src/main/java/jnr/ffi/provider/ClosureManager.java +++ b/src/main/java/jnr/ffi/provider/ClosureManager.java @@ -24,4 +24,5 @@ public interface ClosureManager { public abstract T newClosure(Class closureClass, T instance); public abstract jnr.ffi.Pointer getClosurePointer(Class closureClass, T instance); + public abstract T getClosureFromPointer(Class closureClass, jnr.ffi.Pointer pointer); } diff --git a/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java b/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java index 862ce8567..15257544f 100644 --- a/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java +++ b/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java @@ -21,11 +21,15 @@ import jnr.ffi.Pointer; import jnr.ffi.mapper.CachingTypeMapper; import jnr.ffi.mapper.CompositeTypeMapper; +import jnr.ffi.mapper.DefaultSignatureType; +import jnr.ffi.mapper.FromNativeContext; +import jnr.ffi.mapper.FromNativeConverter; import jnr.ffi.mapper.SignatureTypeMapper; import jnr.ffi.mapper.ToNativeContext; import jnr.ffi.mapper.ToNativeConverter; import jnr.ffi.provider.ClosureManager; +import java.util.Collections; import java.util.IdentityHashMap; import java.util.Map; @@ -69,6 +73,17 @@ public final jnr.ffi.Pointer getClosurePointer(Class closureCla return getClosureFactory(closureClass).getClosureReference(instance).getPointer(); } + public T getClosureFromPointer(Class closureClass, Pointer pointer) { + FromNativeContext context = new SimpleNativeContext(runtime, Collections.emptyList()); + FromNativeConverter converter = (FromNativeConverter) ClosureFromNativeConverter.getInstance( + runtime, + DefaultSignatureType.create(closureClass, context), + asmClassLoaders.get(closureClass.getClassLoader()), + typeMapper + ); + return converter.fromNative(pointer, context); + } + synchronized NativeClosureFactory initClosureFactory(Class closureClass, AsmClassLoader classLoader) { NativeClosureFactory factory = factories.get(closureClass); if (factory != null) { From cc9251ead121fe17ada47f19516418f00fa4e1e6 Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Fri, 18 Oct 2024 21:41:21 +0200 Subject: [PATCH 2/2] implement a test case --- libtest/ClosureTest.c | 11 +++++++ .../provider/jffi/NativeClosureManager.java | 11 ++++--- src/test/java/jnr/ffi/DelegateTest.java | 33 +++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/libtest/ClosureTest.c b/libtest/ClosureTest.c index c9bb9e836..2f8fdf364 100644 --- a/libtest/ClosureTest.c +++ b/libtest/ClosureTest.c @@ -80,6 +80,17 @@ void testStructClosureIrV(struct StructClosureIrV *s, int a1) { (*s->closure)(a1); } + +extern int gvar_int_st; +int gvar_int_st = -1; +int gvar_int_st_get() {return gvar_int_st;} +void gvar_int_st_set(int v) {gvar_int_st = v;} + +void testClosureFPrV(void (*closure)(void (*setter)(int), int (*getter)(), int), int a1) +{ + (*closure)(&gvar_int_st_set, &gvar_int_st_get, a1); +} + // // These macros produce functions of the form: // testClosureBIrV(void (*closure)(char, int), char a1, int a2) {} diff --git a/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java b/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java index 15257544f..0a3a8c50a 100644 --- a/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java +++ b/src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java @@ -52,13 +52,16 @@ NativeClosureFactory getClosureFactory(Class closureClass) { if (factory != null) { return factory; } + return initClosureFactory(closureClass, getAsmClassLoader(closureClass)); + } + + AsmClassLoader getAsmClassLoader(Class closureClass) { AsmClassLoader asmCl = asmClassLoaders.get(closureClass.getClassLoader()); if (asmCl==null) { - asmCl = new AsmClassLoader( closureClass.getClassLoader()); + asmCl = new AsmClassLoader(closureClass.getClassLoader()); asmClassLoaders.put(closureClass.getClassLoader(), asmCl); } - - return initClosureFactory(closureClass, asmCl); + return asmCl; } public T newClosure(Class closureClass, T instance) { @@ -78,7 +81,7 @@ public T getClosureFromPointer(Class closureClass, Pointer poin FromNativeConverter converter = (FromNativeConverter) ClosureFromNativeConverter.getInstance( runtime, DefaultSignatureType.create(closureClass, context), - asmClassLoaders.get(closureClass.getClassLoader()), + getAsmClassLoader(closureClass), typeMapper ); return converter.fromNative(pointer, context); diff --git a/src/test/java/jnr/ffi/DelegateTest.java b/src/test/java/jnr/ffi/DelegateTest.java index 4876d8afc..1c2d55b32 100644 --- a/src/test/java/jnr/ffi/DelegateTest.java +++ b/src/test/java/jnr/ffi/DelegateTest.java @@ -20,6 +20,7 @@ import jnr.ffi.annotations.Delegate; import jnr.ffi.annotations.LongLong; +import jnr.ffi.provider.ClosureManager; import jnr.ffi.types.u_int32_t; import jnr.ffi.util.EnumMapper; @@ -142,6 +143,17 @@ public ClosureStruct(Runtime runtime) { void testStructClosureIrV(ClosureStruct closure, int a1); + public static interface FunGetter { + @Delegate public int get(); + } + public static interface FunSetter { + @Delegate public void set(int v); + } + public static interface CallableFPrV { + @Delegate public void call(Pointer setter, Pointer getter, int a1); + } + void testClosureFPrV(CallableFPrV closure, int a1); + // void testClosureBrV(Callable closure, byte a1); // void testClosureSrV(Callable closure, short a1); @@ -415,6 +427,27 @@ public TestEnum call() { assertEquals(MAGIC.intValue(), retVal, "Incorrect return value from closure"); } + @Test + public void closureFPrV() { + final boolean[] called = { false }; + final int MAGIC = 0xdeadbeef; + TestLib.CallableFPrV closure = new TestLib.CallableFPrV() { + @Override + public void call(Pointer setterPointer, Pointer getterPointer, int a1) { + ClosureManager closureManager = Runtime.getSystemRuntime().getClosureManager(); + TestLib.FunSetter setter = closureManager.getClosureFromPointer(TestLib.FunSetter.class, setterPointer); + TestLib.FunGetter getter = closureManager.getClosureFromPointer(TestLib.FunGetter.class, getterPointer); + + setter.set(a1); + assertEquals(getter.get(), a1); + + called[0] = true; + } + }; + lib.testClosureFPrV(closure, MAGIC); + assertTrue(called[0], "Callable not called"); + } + @Test public void reuseClosure() { TestLib.ReusableCallable closure = new TestLib.ReusableCallable() {