Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt pointer to closure #347

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions libtest/ClosureTest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/jnr/ffi/provider/ClosureManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@
public interface ClosureManager {
public abstract <T> T newClosure(Class<? extends T> closureClass, T instance);
public abstract <T> jnr.ffi.Pointer getClosurePointer(Class<? extends T> closureClass, T instance);
public abstract <T> T getClosureFromPointer(Class<? extends T> closureClass, jnr.ffi.Pointer pointer);
}
24 changes: 21 additions & 3 deletions src/main/java/jnr/ffi/provider/jffi/NativeClosureManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -48,13 +52,16 @@ <T> NativeClosureFactory<T> getClosureFactory(Class<T> 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> T newClosure(Class<? extends T> closureClass, T instance) {
Expand All @@ -69,6 +76,17 @@ public final <T> jnr.ffi.Pointer getClosurePointer(Class<? extends T> closureCla
return getClosureFactory(closureClass).getClosureReference(instance).getPointer();
}

public <T> T getClosureFromPointer(Class<? extends T> closureClass, Pointer pointer) {
FromNativeContext context = new SimpleNativeContext(runtime, Collections.emptyList());
FromNativeConverter<T, Pointer> converter = (FromNativeConverter<T, Pointer>) ClosureFromNativeConverter.getInstance(
runtime,
DefaultSignatureType.create(closureClass, context),
getAsmClassLoader(closureClass),
typeMapper
);
return converter.fromNative(pointer, context);
}

synchronized <T> NativeClosureFactory<T> initClosureFactory(Class<T> closureClass, AsmClassLoader classLoader) {
NativeClosureFactory<T> factory = factories.get(closureClass);
if (factory != null) {
Expand Down
33 changes: 33 additions & 0 deletions src/test/java/jnr/ffi/DelegateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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() {
Expand Down