aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-06-25 08:03:23 +0200
committerSven Gothel <[email protected]>2023-06-25 08:03:23 +0200
commit5a130ab0c6db44225692e362e41e7b45481f9392 (patch)
tree29ee4d05fec554d33a839a02b582d936c9ffe21a
parent7caf66ccae2dea53b82fb6552cb9144d4146259f (diff)
GlueGen JavaCallback: Add preliminary implementation (WIP): Produces proper interfaces, TODO implementation
Note: JavaCallbackDef is commented out on test2.cfg example, since implementation is missing.
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java139
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg9
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.h7
3 files changed, 146 insertions, 9 deletions
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index 636927d..59ca290 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -81,6 +81,7 @@ import com.jogamp.gluegen.cgram.types.ArrayType;
import com.jogamp.gluegen.cgram.types.CompoundType;
import com.jogamp.gluegen.cgram.types.Field;
import com.jogamp.gluegen.cgram.types.FunctionSymbol;
+import com.jogamp.gluegen.cgram.types.FunctionType;
import com.jogamp.gluegen.cgram.types.PointerType;
import com.jogamp.gluegen.cgram.types.SizeThunk;
import com.jogamp.gluegen.cgram.types.StructLayout;
@@ -361,6 +362,17 @@ public class JavaEmitter implements GlueEmitter {
if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
javaUnit().emitln();
+ if( !cfg.getJavaCallbackList().isEmpty() ) {
+ final List<String> javaCallbacks = cfg.getJavaCallbackList();
+ for(final String javaCallback : javaCallbacks) {
+ final Type funcPtr = typedefDictionary.get(javaCallback);
+ if( null != funcPtr && funcPtr.isFunctionPointer() ) {
+ generateJavaCallbackCode(javaCallback, funcPtr.getTargetFunction());
+ } else {
+ LOG.log(WARNING, "JavaCallback '{0}' function-pointer type not available", javaCallback);
+ }
+ }
+ }
}
}
@@ -1441,6 +1453,100 @@ public class JavaEmitter implements GlueEmitter {
}
}
+ static class JavaCallback {
+ final String funcName;
+ final FunctionType func;
+ final int userParamIdx;
+ final Type userParamType;
+ final String userParamName;
+
+ JavaCallback(final String funcName, final FunctionType func, final int userParamIdx) {
+ this.funcName = funcName;
+ this.func = func;
+ int paramIdx = -2;
+ Type paramType = null;
+ String paramName = null;
+ if( 0 <= userParamIdx && userParamIdx < func.getNumArguments() ) {
+ final Type t = func.getArgumentType(userParamIdx);
+ if( null != t && t.isPointer() && t.getTargetType().isVoid() ) {
+ // OK 'void*'
+ paramIdx = userParamIdx;
+ paramName = func.getArgumentName(userParamIdx);
+ paramType = t;
+ }
+ }
+ this.userParamIdx = paramIdx;
+ this.userParamType = paramType;
+ this.userParamName = paramName;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("JavaCallback[%s, userParam[idx %d, '%s', %s], %s]", funcName,
+ userParamIdx, userParamName, userParamType.getSignature(null).toString(), func.toString(funcName, false, true));
+ }
+ }
+ private final Map<String, JavaCallback> javaCallbackMap = new HashMap<String, JavaCallback>();
+
+ private void generateJavaCallbackCode(final String funcName, final FunctionType funcType) {
+ final FunctionSymbol funcSym = new FunctionSymbol("callback", funcType);
+ funcSym.addAliasedName(funcName);
+ final int userParamIdx = cfg.javaCallbackUserParamIdx(funcSym);
+ final JavaCallback jcb = new JavaCallback(funcName, funcType, userParamIdx);
+ javaCallbackMap.put(funcName, jcb);
+ LOG.log(INFO, "JavaCallback: fSym {0}, userParam {1}", funcSym.getAliasedString(), userParamIdx);
+ LOG.log(INFO, "JavaCallback: Added {0}", jcb);
+
+ javaUnit.emitln(" /** JavaCallback interface: "+funcName+" -> "+funcType.toString(funcName, false, true)+" */");
+ javaUnit.emitln(" public static interface "+funcName+" {");
+ generateFunctionInterfaceCode(javaUnit, funcSym, jcb);
+ javaUnit.emitln(" }");
+ javaUnit.emitln();
+ }
+ private void generateFunctionInterfaceCode(final JavaCodeUnit javaUnit, final FunctionSymbol funcSym, final JavaCallback jcb) {
+ // Emit method call and associated native code
+ MethodBinding mb = bindFunction(funcSym, true /* forInterface */, machDescJava, null, null);
+
+ // Replace optional userParam argument 'void*' with Object
+ if( 0 <= jcb.userParamIdx && jcb.userParamIdx < mb.getNumArguments() ) {
+ final JavaType t = mb.getJavaArgumentType(jcb.userParamIdx);
+ if ( t.isCVoidPointerType() ) {
+ mb = mb.replaceJavaArgumentType(jcb.userParamIdx, JavaType.forObjectClass());
+ }
+ }
+ // JavaTypes representing C pointers in the initial
+ // MethodBinding have not been lowered yet to concrete types
+ final List<MethodBinding> bindings = expandMethodBinding(mb);
+
+ final boolean useNIOOnly = true;
+ final boolean useNIODirectOnly = true;
+
+ for (final MethodBinding binding : bindings) {
+ // Emit public Java entry point for calling this function pointer
+ final JavaMethodBindingEmitter emitter = new JavaMethodBindingEmitter(binding,
+ javaUnit,
+ cfg.runtimeExceptionType(),
+ cfg.unsupportedExceptionType(),
+ false, // emitBody
+ cfg.tagNativeBinding(),
+ false, // eraseBufferAndArrayTypes
+ useNIOOnly,
+ useNIODirectOnly,
+ false, // forDirectBufferImplementation
+ false, // forIndirectBufferAndArrayImplementation
+ true, // isUnimplemented
+ true, // isInterface
+ false, // isNativeMethod
+ false, // isPrivateNativeMethod
+ cfg) {
+ @Override
+ protected String getBaseIndentString() { return " "; }
+ };
+ emitter.addModifier(JavaMethodBindingEmitter.PUBLIC);
+ emitter.emit();
+ }
+ }
+
private void generateFunctionPointerCode(final Set<MethodBinding> methodBindingSet,
final JavaCodeUnit javaUnit, final CCodeUnit jniUnit,
final String structCTypeName, final Type containingCType, final JavaType containingJType,
@@ -1757,7 +1863,6 @@ public class JavaEmitter implements GlueEmitter {
LOG.log(WARNING, structCType.getASTLocusTag(), msg);
return;
}
-
baseIsPointer = baseElemType.isPointer();
isConstValue = baseElemType.isConst();
if( baseIsPointer ) {
@@ -2947,7 +3052,6 @@ public class JavaEmitter implements GlueEmitter {
sym = FunctionSymbol.cloneWithDeepAliases(sym);
sym.addAliasedName(delegationImplName);
}
- final String name = sym.getName();
final JavaType javaReturnType;
if (cfg.returnsString(sym)) {
@@ -2973,16 +3077,41 @@ public class JavaEmitter implements GlueEmitter {
// List of the indices of the arguments in this function that should be
// converted from byte[] or short[] to String
final List<JavaType> javaArgumentTypes = new ArrayList<JavaType>();
- final List<Integer> stringArgIndices = cfg.stringArguments(name);
+ final List<Integer> stringArgIndices = cfg.stringArguments(sym);
+ JavaCallback javaCallback = null;
for (int i = 0; i < sym.getNumArguments(); i++) {
final Type cArgType = sym.getArgumentType(i);
+ final String cArgName = sym.getArgumentName(i);
JavaType mappedType = typeToJavaType(cArgType, curMachDesc);
// System.out.println("C arg type -> \"" + cArgType + "\"" );
// System.out.println(" Java -> \"" + mappedType + "\"" );
- // Take into account any ArgumentIsString configuration directives that apply
- if (stringArgIndices != null && stringArgIndices.contains(i)) {
+ final boolean isJavaCallbackArg;
+ if( null == javaCallback ) {
+ final JavaCallback jcb = javaCallbackMap.get( cArgType.getName() );
+ if( null != jcb && null != jcb.userParamName ) {
+ isJavaCallbackArg = true;
+ javaCallback = jcb;
+ LOG.log(INFO, "BindFunc.JavaCallback: Found {0} for {1}", jcb, sym.getType().toString(sym.getName(), false, true));
+ } else {
+ isJavaCallbackArg = false;
+ }
+ } else {
+ isJavaCallbackArg = false;
+ }
+
+ if( isJavaCallbackArg ) {
+ // Replace JavaCallback type with generated interface name
+ mappedType = JavaType.createForCStruct(cArgType.getName());
+ } else if( null != javaCallback && null != javaCallback.userParamName &&
+ javaCallback.userParamName.equals( cArgName ) &&
+ cArgType.isPointer() && cArgType.getTargetType().isVoid() )
+ {
+ // Replace optional userParam argument 'void*' with Object
+ mappedType = JavaType.forObjectClass();
+ } else if (stringArgIndices != null && stringArgIndices.contains(i)) {
+ // Take into account any ArgumentIsString configuration directives that apply
// System.out.println("Forcing conversion of " + binding.getName() + " arg #" + i + " from byte[] to String ");
if (mappedType.isCVoidPointerType() ||
mappedType.isCCharPointerType() ||
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
index d40ac9a..77a8433 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
@@ -19,7 +19,7 @@ ForceProcAddressGen __ALL__
# pointer typedefs for these routines to MYAPIENTRY
# LocalProcAddressCallingConvention __ALL__ MYAPIENTRY
-Opaque long void*
+# Opaque long void*
# Undefined struct forward declaration, implementation secret: 'struct T2_UndefStruct;'
Opaque long T2_UndefStruct*
@@ -43,6 +43,13 @@ ReturnsStringOnly T2_InitializeOptions.ProductVersion
# ReturnedArrayLength T2_InitializeOptions.OverrideThreadAffinity 1
MaxOneElement T2_InitializeOptions.OverrideThreadAffinity
+# typedef int32_t ( * T2_CallbackFunc)(size_t id, const char* msg, void* userParam);
+# void InjectMessageCallback(size_t id, const char* msg);
+ArgumentIsString T2_CallbackFunc 1
+ArgumentIsString InjectMessageCallback 1
+# Define a JavaCallback, enacted on a function-pointer argument `T2_CallbackFunc` and a user-param `void*` for Java Object mapping
+# JavaCallbackDef T2_CallbackFunc 2
+
CustomCCode #include "test2.h"
Import com.jogamp.gluegen.test.junit.generation.Bindingtest2
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
index 75c7ffa..78bdf87 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
@@ -6,7 +6,7 @@
// struct T2_UndefStruct; // undefined struct forward declaration, implementation secret
typedef struct T2_UndefStruct* T2_UndefStructPtr;
-typedef int32_t ( * T2_CustomFuncA)(void* aptr);
+typedef int32_t ( * T2_CustomFuncA)(T2_UndefStructPtr aptr);
typedef struct {
int32_t balance;
@@ -58,8 +58,9 @@ typedef struct {
extern int Initialize(T2_InitializeOptions* Options);
extern int Release(T2_InitializeOptions* Options);
-typedef int32_t ( * T2_CallbackFunc)(size_t id, size_t msg_len, const char* msg, void* userParam);
+typedef int32_t ( * T2_CallbackFunc)(size_t id, const char* msg, void* userParam);
void AddMessageCallback(T2_CallbackFunc func, void* userParam);
void RemoveMessageCallback(T2_CallbackFunc func, void* userParam);
-void InjectMessageCallback(size_t id, size_t msg_len, const char* msg);
+void InjectMessageCallback(size_t id, const char* msg);
+