aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/com/jogamp/gluegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com/jogamp/gluegen')
-rw-r--r--src/java/com/jogamp/gluegen/CMethodBindingEmitter.java188
-rw-r--r--src/java/com/jogamp/gluegen/JavaConfiguration.java139
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java100
-rw-r--r--src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java66
4 files changed, 374 insertions, 119 deletions
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
index d0e0c45..d802ee7 100644
--- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
@@ -40,11 +40,14 @@
package com.jogamp.gluegen;
+import static java.util.logging.Level.INFO;
+
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.util.List;
import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
import com.jogamp.gluegen.Logging.LoggerIf;
import com.jogamp.gluegen.cgram.types.ArrayType;
import com.jogamp.gluegen.cgram.types.FunctionSymbol;
@@ -113,6 +116,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
// We need this in order to compute sizes of certain types
protected MachineDataInfo machDesc;
+ private final JavaCallbackInfo javaCallback;
+ private final String jcbNativeBasename;
+ private final CMethodBindingEmitter jcbCMethodEmitter;
+
/**
* Constructs an emitter for the specified binding, and sets a default
* comment emitter that will emit the signature of the C function that is
@@ -145,6 +152,18 @@ public class CMethodBindingEmitter extends FunctionEmitter {
this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
this.machDesc = machDesc;
+ javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ if( null != javaCallback ) {
+ jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.simpleCbClazzName.replace("_", "") );
+ jcbCMethodEmitter = new CMethodBindingEmitter(javaCallback.cbFuncBinding,
+ unit, javaPackageName, javaClassName, isOverloadedBinding,
+ isJavaMethodStatic, forImplementingMethodCall,
+ forIndirectBufferAndArrayImplementation, machDesc, configuration);
+ } else {
+ jcbNativeBasename = null;
+ jcbCMethodEmitter = null;
+ }
+
setCommentEmitter(defaultCommentEmitter);
}
@@ -308,10 +327,98 @@ public class CMethodBindingEmitter extends FunctionEmitter {
@Override
protected void emitReturnType() {
+ if( null != javaCallback ) {
+ LOG.log(INFO, "BindCFunc.R.JavaCallback: {0}: {1}", binding.getName(), javaCallback);
+ final String userParamArgName = javaCallback.cbFuncBinding.getArgumentName(javaCallback.userParamIdx);
+ final Type cReturnType = javaCallback.cbFuncBinding.getCReturnType();
+ final JavaType jretType = javaCallback.cbFuncBinding.getJavaReturnType();
+ unit.emitln("typedef struct {");
+ unit.emitln(" jobject cbFunc;");
+ unit.emitln(" jmethodID cbMethodID;");
+ unit.emitln(" jobject userParam;");
+ unit.emitln("} T_"+jcbNativeBasename+";");
+ unit.emitln();
+ // javaCallback.cbFuncCEmitter.emitSignature();
+ unit.emit("static "+cReturnType.getCName()+" func"+jcbNativeBasename+"(");
+ // javaCallback.cbFuncCEmitter.emitArguments();
+ unit.emit(javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), null).toString());
+ unit.emitln(") {");
+ // javaCallback.cbFuncCEmitter.emitBody();
+ {
+ unit.emitln(" JNIEnv* env = JVMUtil_GetJNIEnv();");
+ unit.emitln(" if( NULL == env ) {");
+ if( !cReturnType.isVoid() ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return;");
+ }
+ unit.emitln(" }");
+ // javaCallback.cbFuncCEmitter.emitBodyVariableDeclarations();
+ // javaCallback.cbFuncCEmitter.emitBodyUserVariableDeclarations();
+ // javaCallback.cbFuncCEmitter.emitBodyVariablePreCallSetup();
+ jcbCMethodEmitter.emitJavaCallbackBodyCToJavaPreCall(javaCallback);
+
+ // javaCallback.cbFuncCEmitter.emitBodyCallCFunction();
+ unit.emitln(" T_"+jcbNativeBasename+"* cb = (T_"+jcbNativeBasename+"*) "+userParamArgName+";");
+ unit.emitln(" // C Params: "+javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), null).toString());
+ unit.emitln(" // J Params: "+javaCallback.cbFuncBinding.getJavaParameterList(new StringBuilder()).toString());
+ // unit.emitln(" fprintf(stderr, \"YYY Callback01 user %p, id %ld, msg %s\\n\", cb, id, msg);");
+
+ if( !cReturnType.isVoid() ) {
+ unit.emit(" "+cReturnType.getCName()+" _res = ("+cReturnType.getCName()+") ");
+ } else {
+ unit.emit(" ");
+ }
+ unit.emit("(*env)->Call" + CodeGenUtils.capitalizeString( jretType.getName() ) +"Method(env, cb->cbFunc, cb->cbMethodID, ");
+ // javaCallback.cbFuncCEmitter.emitBodyPassCArguments();
+ if( 0 < jcbCMethodEmitter.emitJavaCallbackBodyPassJavaArguments(javaCallback) ) {
+ unit.emit(", ");
+ }
+ unit.emitln("cb->userParam);");
+
+ // javaCallback.cbFuncCEmitter.emitBodyUserVariableAssignments();
+ // javaCallback.cbFuncCEmitter.emitBodyVariablePostCallCleanup();
+ // javaCallback.cbFuncCEmitter.emitBodyMapCToJNIType(-1 /* return value */, true /* addLocalVar */)
+ if( !cReturnType.isVoid() ) {
+ unit.emitln(" return _res;");
+ }
+ }
+ unit.emitln("}");
+ unit.emitln();
+ }
unit.emit("JNIEXPORT ");
unit.emit(binding.getJavaReturnType().jniTypeName());
unit.emit(" JNICALL");
}
+ /* pp */ int emitJavaCallbackBodyCToJavaPreCall(final JavaCallbackInfo jcbi) {
+ int count = 0;
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if( i == jcbi.userParamIdx ) {
+ continue;
+ }
+ if( emitBodyMapCToJNIType(i, true /* addLocalVar */) ) {
+ ++count;
+ }
+ }
+ return count;
+ }
+ /* pp */ int emitJavaCallbackBodyPassJavaArguments(final JavaCallbackInfo jcbi) {
+ int count = 0;
+ boolean needsComma = false;
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if( i == jcbi.userParamIdx ) {
+ continue;
+ }
+ if (needsComma) {
+ unit.emit(", ");
+ needsComma = false;
+ }
+ unit.emit( binding.getArgumentName(i) + "_jni" );
+ needsComma = true;
+ ++count;
+ }
+ return count;
+ }
@Override
protected void emitName() {
@@ -385,6 +492,15 @@ public class CMethodBindingEmitter extends FunctionEmitter {
byteOffsetArrayArgName(i));
}
}
+
+ final JavaCallbackInfo jcb = this.javaCallback;
+ if( null != jcb ) {
+ LOG.log(INFO, "BindCFunc.A.JavaCallback: {0}: {1}", binding.getName(), jcb);
+ unit.emit(", jstring jcallbackSignature, jlongArray jnativeUserParam");
+ numEmitted+=2;
+ } else {
+ LOG.log(INFO, "BindCFunc.JavaCallback: {0}: NONE", binding.getName());
+ }
return numEmitted;
}
@@ -396,6 +512,50 @@ public class CMethodBindingEmitter extends FunctionEmitter {
emitBodyVariableDeclarations();
emitBodyUserVariableDeclarations();
emitBodyVariablePreCallSetup();
+ final JavaCallbackInfo jcb = this.javaCallback;
+ if( null != jcb ) {
+ LOG.log(INFO, "BindCFunc.B.JavaCallback: {0}: {1}", binding.getName(), jcb);
+ final String cbFuncArgName = binding.getArgumentName(jcb.setFuncCBParamIdx);
+ final String userParamArgName = binding.getArgumentName(jcb.setFuncUserParamIdx);
+ final String nativeCBFuncVarName = cbFuncArgName+"_native";
+ final String nativeUserParamVarName = userParamArgName+"_native";
+ unit.emitln();
+ unit.emitln(" // JavaCallback handling");
+ unit.emitln(" "+jcb.cbFuncTypeName+" "+nativeCBFuncVarName+";");
+ unit.emitln(" T_"+jcbNativeBasename+"* "+nativeUserParamVarName+";");
+ // unit.emit(", jstring jcallbackSignature, jlongArray jnativeUserParam");
+ unit.emitln(" if( NULL == jnativeUserParam ) { (*env)->FatalError(env, \"Null jnativeUserParam in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" const size_t jnativeUserParam_size = (*env)->GetArrayLength(env, jnativeUserParam);");
+ unit.emitln(" if( 1 > jnativeUserParam_size ) { (*env)->FatalError(env, \"nativeUserParam size < 1 in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" if( NULL != "+cbFuncArgName+" ) {");
+ unit.emitln(" if( NULL == "+userParamArgName+" ) { (*env)->FatalError(env, \"Null "+userParamArgName+" in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" "+nativeUserParamVarName+" = (T_"+jcbNativeBasename+"*) calloc(1, sizeof(T_"+jcbNativeBasename+"));");
+ unit.emitln(" if( NULL == "+nativeUserParamVarName+" ) { (*env)->FatalError(env, \"Can't alloc "+nativeUserParamVarName+" in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" "+nativeUserParamVarName+"->cbFunc = (*env)->NewGlobalRef(env, "+cbFuncArgName+");");
+ unit.emitln(" if( NULL == "+nativeUserParamVarName+"->cbFunc ) { (*env)->FatalError(env, \"Failed NewGlobalRef(func) in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" "+nativeUserParamVarName+"->userParam = (*env)->NewGlobalRef(env, "+userParamArgName+");");
+ unit.emitln(" if( NULL == "+nativeUserParamVarName+"->userParam ) { (*env)->FatalError(env, \"Failed NewGlobalRef(userParam) in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" {");
+ unit.emitln(" jclass cbClazz = (*env)->GetObjectClass(env, "+nativeUserParamVarName+"->cbFunc);");
+ unit.emitln(" if( NULL == cbClazz ) { (*env)->FatalError(env, \"Failed GetObjectClass in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" const char* callbackSignature = (*env)->GetStringUTFChars(env, jcallbackSignature, (jboolean*)NULL);");
+ unit.emitln(" if( NULL == callbackSignature ) { (*env)->FatalError(env, \"Failed callbackSignature in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" "+nativeUserParamVarName+"->cbMethodID = (*env)->GetMethodID(env, cbClazz, \"callback\", callbackSignature);");
+ unit.emitln(" (*env)->ReleaseStringUTFChars(env, jcallbackSignature, callbackSignature);");
+ unit.emitln(" if( NULL == "+nativeUserParamVarName+"->cbMethodID ) { (*env)->FatalError(env, \"Failed GetMethodID in '"+jcbNativeBasename+"'\"); }");
+ unit.emitln(" }");
+ unit.emitln(" "+nativeCBFuncVarName+" = func"+jcbNativeBasename+";");
+ unit.emitln(" } else {");
+ unit.emitln(" "+nativeCBFuncVarName+" = NULL;");
+ unit.emitln(" "+nativeUserParamVarName+" = NULL;");
+ unit.emitln(" }");
+ unit.emitln(" {");
+ unit.emitln(" jlong v = (jlong) (intptr_t) "+nativeUserParamVarName+";");
+ unit.emitln(" (*env)->SetLongArrayRegion(env, jnativeUserParam, 0, (jsize)1, &v);");
+ // unit.emitln(" fprintf(stderr, \"YYY MessageCallback01 user %p -> native %p\\n\", "+userParamArgName+", "+nativeUserParamVarName+");");
+ unit.emitln(" }");
+ unit.emitln();
+ }
emitBodyCallCFunction();
emitBodyUserVariableAssignments();
emitBodyVariablePostCallCleanup();
@@ -404,6 +564,19 @@ public class CMethodBindingEmitter extends FunctionEmitter {
}
unit.emitln("}");
unit.emitln();
+ if( null != jcb ) {
+ unit.emitln("JNIEXPORT void JNICALL");
+ unit.emit(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
+ unit.emitln("_release"+getInterfaceName()+"Impl(JNIEnv *env, jobject _unused, jlong jnativeUserParam) {");
+ unit.emitln(" T_"+jcbNativeBasename+"* nativeUserParam = (T_"+jcbNativeBasename+"*) (intptr_t) jnativeUserParam;");
+ unit.emitln(" if( NULL != nativeUserParam ) {");
+ unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->cbFunc);");
+ unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->userParam);");
+ unit.emitln(" free(nativeUserParam);");
+ unit.emitln(" }");
+ unit.emitln("}");
+ unit.emitln();
+ }
}
protected void emitBodyVariableDeclarations() {
@@ -953,6 +1126,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
} else {
if (javaArgType.isString()) { unit.emit(STRING_CHARS_PREFIX); }
unit.emit(binding.getArgumentName(i));
+ if( null != this.javaCallback &&
+ ( i == this.javaCallback.setFuncCBParamIdx || i == this.javaCallback.setFuncUserParamIdx ) ) {
+ unit.emit("_native");
+ }
}
}
}
@@ -1212,8 +1389,15 @@ public class CMethodBindingEmitter extends FunctionEmitter {
final StringBuilder buf = new StringBuilder();
buf.append(JavaEmitter.jniMangle(getImplName()));
buf.append(getImplSuffix());
- buf.append("__");
- return getJNIMangledArgs(binding, forIndirectBufferAndArrayImplementation, buf).toString();
+ if( null == this.javaCallback ) {
+ buf.append("__");
+ getJNIMangledArgs(binding, forIndirectBufferAndArrayImplementation, buf);
+ if( null != this.javaCallback ) {
+ getJNIMangledArg(String.class, buf, false); // to account for the additional 'jstring jcallbackSignature' parameter
+ getJNIMangledArg(long[].class, buf, false); // to account for the additional 'long[] nativeUserParam' parameter
+ }
+ }
+ return buf.toString();
}
/**
diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java
index 3faddcd..17ac547 100644
--- a/src/java/com/jogamp/gluegen/JavaConfiguration.java
+++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java
@@ -149,8 +149,26 @@ public class JavaConfiguration {
* converted to String args; value is List of Integer argument indices
*/
private final Map<String, List<Integer>> argumentsAreString = new HashMap<String, List<Integer>>();
- private final Map<String, Integer> javaCallbackUserParams = new HashMap<String, Integer>();
- private final List<String> javaCallbackList = new ArrayList<String>();
+
+ /** JavaCallback configuration definition (static) */
+ public static class JavaCallbackDef {
+ final String setFuncName;
+ final String cbFuncTypeName;
+ final int userParamIdx;
+ JavaCallbackDef(final String setFuncName, final String cbFuncTypeName, final int userParamIdx) {
+ this.setFuncName = setFuncName;
+ this.cbFuncTypeName = cbFuncTypeName;
+ this.userParamIdx = userParamIdx;
+ }
+ @Override
+ public String toString() {
+ return String.format("JavaCallbackDef[set %s, cb %s, userParamIdx %d]",
+ setFuncName, cbFuncTypeName, userParamIdx);
+ }
+ }
+ private final List<JavaCallbackDef> javaCallbackList = new ArrayList<JavaCallbackDef>();
+ private final Map<String, JavaCallbackDef> javaCallbackSetFuncToDef = new HashMap<String, JavaCallbackDef>();
+
private final Set<String> extendedIntfSymbolsIgnore = new HashSet<String>();
private final Set<String> extendedIntfSymbolsOnly = new HashSet<String>();
private final Set<String> extendedImplSymbolsIgnore = new HashSet<String>();
@@ -539,30 +557,21 @@ public class JavaConfiguration {
return returnsStringOnly.contains(functionName);
}
- public List<String> getJavaCallbackList() {
+ /** Returns the list of all configured JavaCallback definitions. */
+ public List<JavaCallbackDef> getJavaCallbackList() {
return javaCallbackList;
}
- /** Returns an <code>Integer</code> index of the <code>void*</code>
- user-param argument that should be converted to <code>Object</code>s for the Java Callback. Returns null if there are no
- such hints for the given function alias symbol. */
- public boolean isJavaCallback(final AliasedSymbol symbol) {
- return -2 < javaCallbackUserParamIdx(symbol);
- }
-
- /** Returns an <code>Integer</code> index of the <code>void*</code>
- user-param argument that should be converted to <code>Object</code>s for the Java Callback. Returns -2 if there are no
- such hints for the given function alias symbol. */
- public int javaCallbackUserParamIdx(final AliasedSymbol symbol) {
+ /** Returns the configured JavaCallback definition mapped to the JavaCallback-Set-Function name. */
+ public JavaCallbackDef javaCallbackSetFuncToDef(final AliasedSymbol symbol) {
final String name = symbol.getName();
final Set<String> aliases = symbol.getAliasedNames();
- Integer res = javaCallbackUserParams.get(name);
+ JavaCallbackDef res = javaCallbackSetFuncToDef.get(name);
if( null == res ) {
- res = oneInMap(javaCallbackUserParams, aliases);
+ res = oneInMap(javaCallbackSetFuncToDef, aliases);
}
- LOG.log(INFO, getASTLocusTag(symbol), "JavaCallbackDef: {0} -> {1}", symbol, res);
- return null != res ? res.intValue() : -2;
+ return res;
}
/**
@@ -1615,15 +1624,12 @@ public class JavaConfiguration {
protected void readJavaCallbackDef(final StringTokenizer tok, final String filename, final int lineNo) {
try {
- final String name = tok.nextToken();
- final Integer idx;
- if( tok.hasMoreTokens() ) {
- idx = Integer.valueOf(tok.nextToken());
- } else {
- idx = Integer.valueOf(-2);
- }
- javaCallbackUserParams.put(name, idx);
- javaCallbackList.add(name);
+ final String setFuncName = tok.nextToken();
+ final String cbFuncTypeName = tok.nextToken();
+ final Integer userParamIdx = Integer.valueOf(tok.nextToken());
+ final JavaCallbackDef jcd = new JavaCallbackDef(setFuncName, cbFuncTypeName, userParamIdx);
+ javaCallbackList.add(jcd);
+ javaCallbackSetFuncToDef.put(setFuncName, jcd);
} catch (final NoSuchElementException e) {
throw new RuntimeException("Error parsing \"JavaCallbackDef\" command at line " + lineNo +
" in file \"" + filename + "\"", e);
@@ -2233,53 +2239,76 @@ public class JavaConfiguration {
}
/**
- * JavaCallback information, produced by {@link JavaEmitter#beginFunctions(TypeDictionary, TypeDictionary, Map)}
+ * JavaCallback compile time information, produced by {@link JavaEmitter#beginFunctions(TypeDictionary, TypeDictionary, Map)}
* from {@link Type#isFunctionPointer() function-pointer} {@link Type}s mapped to {@link JavaConfiguration#getJavaCallbackList()} names via {@link TypeDictionary} (typedef).
* @see JavaConfiguration#funcPtrTypeToJavaCallbackMap
- * @see JavaConfiguration#bindingToJavaCallbackMap
+ * @see JavaConfiguration#setFuncToJavaCallbackMap
*/
- public static class JavaCallback {
- final String funcName;
- final String simpleClazzName;
- final String fqClazzName;
- final String methodSignature;
- final FunctionType func;
+ public static class JavaCallbackInfo {
+ final String setFuncName;
+ final String cbFuncTypeName;
+ final String simpleCbClazzName;
+ final String fqCbClazzName;
+ final String cbMethodSignature;
+ final FunctionType cbFuncType;
+ final MethodBinding cbFuncBinding;
final int userParamIdx;
final Type userParamType;
final String userParamName;
-
- public JavaCallback(final String funcName, final String simpleClazzName, final String fqClazzName, final String methodSignature,
- final FunctionType func, final int userParamIdx) {
- this.funcName = funcName;
- this.simpleClazzName = simpleClazzName;
- this.fqClazzName = fqClazzName;
- this.methodSignature = methodSignature;
- this.func = func;
+ boolean setFuncProcessed;
+ int setFuncCBParamIdx;
+ int setFuncUserParamIdx;
+
+ public JavaCallbackInfo(final String setFuncName, final String cbFuncTypeName, final String simpleClazzName, final String fqClazzName, final String methodSignature,
+ final FunctionType cbFuncType, final MethodBinding cbFuncBinding, final int userParamIdx) {
+ this.setFuncName = setFuncName;
+ this.cbFuncTypeName = cbFuncTypeName;
+ this.simpleCbClazzName = simpleClazzName;
+ this.fqCbClazzName = fqClazzName;
+ this.cbMethodSignature = methodSignature;
+ this.cbFuncType = cbFuncType;
+ this.cbFuncBinding = cbFuncBinding;
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*'
+ if( 0 <= userParamIdx && userParamIdx < cbFuncType.getNumArguments() ) {
+ final Type t = cbFuncType.getArgumentType(userParamIdx);
+ if( null != t && t.isPointer() ) {
+ // OK '<something>*'
paramIdx = userParamIdx;
- paramName = func.getArgumentName(userParamIdx);
- paramType = t;
+ paramName = cbFuncType.getArgumentName(userParamIdx);
+ paramType = t.getTargetType();
}
}
this.userParamIdx = paramIdx;
this.userParamType = paramType;
this.userParamName = paramName;
+ this.setFuncProcessed = false;
+ this.setFuncCBParamIdx = -1;
+ this.setFuncUserParamIdx = -1;
+ }
+
+ public void setFuncProcessed(final int cbParamIdx, final int userParamIdx) {
+ if( !setFuncProcessed ) {
+ if( 0 <= cbParamIdx && 0 <= userParamIdx ) {
+ setFuncProcessed = true;
+ setFuncCBParamIdx = cbParamIdx;
+ setFuncUserParamIdx = userParamIdx;
+ } else {
+ setFuncCBParamIdx = -1;
+ setFuncUserParamIdx = -1;
+ }
+ }
}
@Override
public String toString() {
- return String.format("JavaCallback[%s, %s%s, userParam[idx %d, '%s', %s], %s]", funcName, fqClazzName, methodSignature,
- userParamIdx, userParamName, userParamType.getSignature(null).toString(), func.toString(funcName, false, true));
+ return String.format("JavaCallbackInfo[set %s(ok %b, cbIdx %d, upIdx %d), cb %s%s, userParam[idx %d, '%s', %s], %s]",
+ setFuncName, setFuncProcessed, setFuncCBParamIdx, setFuncUserParamIdx,
+ cbFuncTypeName, cbMethodSignature,
+ userParamIdx, userParamName, userParamType.getSignature(null).toString(), cbFuncType.toString(cbFuncTypeName, false, true));
}
}
- /** Mapped function-pointer type name to {@link JavaCallback} */
- /* pp */ final Map<String, JavaCallback> funcPtrTypeToJavaCallbackMap = new HashMap<String, JavaCallback>();
- /** Mapped binding name to {@link JavaCallback} */
- /* pp */ final Map<String, JavaCallback> bindingToJavaCallbackMap = new HashMap<String, JavaCallback>();
+ /** Mapped binding name to {@link JavaCallbackInfo} */
+ /* pp */ final Map<String, JavaCallbackInfo> setFuncToJavaCallbackMap = new HashMap<String, JavaCallbackInfo>();
}
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index 41c5203..7dad237 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -75,6 +75,9 @@ import com.jogamp.common.os.DynamicLookupHelper;
import com.jogamp.common.os.MachineDataInfo;
import com.jogamp.common.util.ArrayHashMap;
import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.FunctionEmitter.EmissionModifier;
+import com.jogamp.gluegen.JavaConfiguration.JavaCallbackDef;
+import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
import com.jogamp.gluegen.Logging.LoggerIf;
import com.jogamp.gluegen.cgram.types.AliasedSymbol;
import com.jogamp.gluegen.cgram.types.ArrayType;
@@ -363,13 +366,13 @@ 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);
+ final List<JavaCallbackDef> javaCallbacks = cfg.getJavaCallbackList();
+ for(final JavaCallbackDef jcbd : javaCallbacks) {
+ final Type funcPtr = typedefDictionary.get(jcbd.cbFuncTypeName);
if( null != funcPtr && funcPtr.isFunctionPointer() ) {
- generateJavaCallbackCode(javaCallback, funcPtr.getTargetFunction());
+ generateJavaCallbackCode(jcbd, funcPtr.getTargetFunction());
} else {
- LOG.log(WARNING, "JavaCallback '{0}' function-pointer type not available", javaCallback);
+ LOG.log(WARNING, "JavaCallback '{0}' function-pointer type not available", jcbd);
}
}
}
@@ -1453,27 +1456,33 @@ public class JavaEmitter implements GlueEmitter {
}
}
- private void generateJavaCallbackCode(final String funcName, final FunctionType funcType) {
+ private void generateJavaCallbackCode(final JavaCallbackDef jcbd, final FunctionType funcType) {
final FunctionSymbol funcSym = new FunctionSymbol("callback", funcType);
- funcSym.addAliasedName(funcName);
- final int userParamIdx = cfg.javaCallbackUserParamIdx(funcSym);
- LOG.log(INFO, "JavaCallback: fSym {0}, userParam {1}", funcSym.getAliasedString(), userParamIdx);
+ funcSym.addAliasedName(jcbd.cbFuncTypeName);
+ LOG.log(INFO, "JavaCallback: fSym {0}, {1}", funcSym.getAliasedString(), jcbd);
- final String simpleClazzName = capitalizeString(funcName);
+ final String simpleClazzName = CodeGenUtils.capitalizeString(jcbd.cbFuncTypeName);
final String fqClazzName = cfg.packageName()+"."+cfg.className()+"."+simpleClazzName;
final StringBuilder methodSignature = new StringBuilder();
- javaUnit.emitln(" /** JavaCallback interface: "+funcName+" -> "+funcType.toString(funcName, false, true)+" */");
+ javaUnit.emitln(" /** JavaCallback interface: "+jcbd.cbFuncTypeName+" -> "+funcType.toString(jcbd.cbFuncTypeName, false, true)+" */");
javaUnit.emitln(" public static interface "+simpleClazzName+" {");
- generateFunctionInterfaceCode(javaUnit, funcSym, userParamIdx, methodSignature);
+ final List<MethodBinding> mbs = generateFunctionInterfaceCode(javaUnit, funcSym, jcbd.userParamIdx, methodSignature);
javaUnit.emitln(" }");
javaUnit.emitln();
-
- final JavaConfiguration.JavaCallback jcb = new JavaConfiguration.JavaCallback(funcName, simpleClazzName, fqClazzName,
- methodSignature.toString(), funcType, userParamIdx);
- cfg.funcPtrTypeToJavaCallbackMap.put(funcName, jcb);
- LOG.log(INFO, "JavaCallback: Added {0}", jcb);
+ if( 1 != mbs.size() ) {
+ throw new UnsupportedOperationException("Multiple bindings generated where only 1 is allowed for func "+funcType.toString(jcbd.cbFuncTypeName, false, true));
+ }
+ final MethodBinding mb = mbs.get(0);
+ if( !mb.getJavaReturnType().isVoid() && !mb.getJavaReturnType().isPrimitive() ) {
+ throw new UnsupportedOperationException("Non void or non-primitive callback return types not suppored. Java "+
+ mb.getJavaReturnType()+", func "+funcType.toString(jcbd.cbFuncTypeName, false, true));
+ }
+ final JavaCallbackInfo jcbi = new JavaCallbackInfo(jcbd.setFuncName, jcbd.cbFuncTypeName, simpleClazzName, fqClazzName,
+ methodSignature.toString(), funcType, mb, jcbd.userParamIdx);
+ cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi);
+ LOG.log(INFO, "JavaCallbackInfo: Added {0}", jcbi);
}
- private void generateFunctionInterfaceCode(final JavaCodeUnit javaUnit, final FunctionSymbol funcSym, final int userParamIdx, final StringBuilder methodSignature) {
+ private List<MethodBinding> generateFunctionInterfaceCode(final JavaCodeUnit javaUnit, final FunctionSymbol funcSym, final int userParamIdx, final StringBuilder methodSignature) {
// Emit method call and associated native code
MethodBinding mb = bindFunction(funcSym, true /* forInterface */, machDescJava, null, null);
@@ -1527,6 +1536,7 @@ public class JavaEmitter implements GlueEmitter {
emitter.addModifier(JavaMethodBindingEmitter.PUBLIC);
emitter.emit();
}
+ return bindings;
}
private void generateFunctionPointerCode(final Set<MethodBinding> methodBindingSet,
@@ -2981,7 +2991,7 @@ public class JavaEmitter implements GlueEmitter {
if (cfg.emitImpl()) {
if( !cfg.getJavaCallbackList().isEmpty() && null == cfg.libraryOnLoadName() ) {
- LOG.log(WARNING, "JavaCallback used, but no 'LibraryOnLoad' basename specified for JNI_OnLoad(..). Exactly one native code-unit for the library must specify with 'LibraryOnLoad' basename");
+ LOG.log(WARNING, "JavaCallback used, but no 'LibraryOnLoad' basename specified for JNI_OnLoad(..). Exactly one native code-unit for the library must specify 'LibraryOnLoad' basename");
}
cUnit().emitHeader(cfg.libraryOnLoadName(), getImplPackageName(), cfg.implClassName(), cfg.customCCode());
}
@@ -2991,7 +3001,6 @@ public class JavaEmitter implements GlueEmitter {
" cfg.emitImpl()=" + cfg.emitImpl() + " cfg.emitInterface()=" + cfg.emitInterface(),
e);
}
-
}
/**
@@ -3061,7 +3070,8 @@ public class JavaEmitter implements GlueEmitter {
// converted from byte[] or short[] to String
final List<JavaType> javaArgumentTypes = new ArrayList<JavaType>();
final List<Integer> stringArgIndices = cfg.stringArguments(sym);
- JavaConfiguration.JavaCallback javaCallback = null;
+ final JavaCallbackInfo jcbi = cfg.setFuncToJavaCallbackMap.get( sym.getName() );
+ int jcbiSetFuncCBParamIdx=-1, jcbiSetFuncUserParamIdx=-1;
for (int i = 0; i < sym.getNumArguments(); i++) {
final Type cArgType = sym.getArgumentType(i);
@@ -3070,29 +3080,18 @@ public class JavaEmitter implements GlueEmitter {
// System.out.println("C arg type -> \"" + cArgType + "\"" );
// System.out.println(" Java -> \"" + mappedType + "\"" );
- final boolean isJavaCallbackArg;
- if( null == javaCallback ) {
- final JavaConfiguration.JavaCallback jcb = cfg.funcPtrTypeToJavaCallbackMap.get( cArgType.getName() );
- if( null != jcb && null != jcb.userParamName ) {
- isJavaCallbackArg = true;
- javaCallback = jcb;
- cfg.bindingToJavaCallbackMap.put(sym.getName(), jcb);
- LOG.log(INFO, "BindFunc.JavaCallback: {0}: {1}, {2}", sym.getName(), sym.getType().toString(sym.getName(), false, true), jcb);
- } else {
- isJavaCallbackArg = false;
- }
- } else {
- isJavaCallbackArg = false;
- }
-
- if( isJavaCallbackArg ) {
+ if( null != jcbi && jcbi.cbFuncTypeName.equals( cArgType.getName() ) &&
+ ( !jcbi.setFuncProcessed || i == jcbi.setFuncCBParamIdx ) )
+ {
// Replace JavaCallback type with generated interface name
- mappedType = JavaType.createForNamedClass( javaCallback.fqClazzName );
- } else if( null != javaCallback && null != javaCallback.userParamName &&
- javaCallback.userParamName.equals( cArgName ) &&
- cArgType.isPointer() && cArgType.getTargetType().isVoid() )
+ jcbiSetFuncCBParamIdx=i;
+ mappedType = JavaType.createForNamedClass( jcbi.fqCbClazzName );
+ } else if( null != jcbi && jcbi.userParamName.equals( cArgName ) &&
+ ( !jcbi.setFuncProcessed || i == jcbi.setFuncUserParamIdx ) &&
+ cArgType.isPointer() && jcbi.userParamType.equals( cArgType.getTargetType() ) )
{
- // Replace optional userParam argument 'void*' with Object
+ // Replace optional userParam argument '<userParamType>*' with Object
+ jcbiSetFuncUserParamIdx=i;
mappedType = JavaType.forObjectClass();
} else if (stringArgIndices != null && stringArgIndices.contains(i)) {
// Take into account any ArgumentIsString configuration directives that apply
@@ -3124,6 +3123,10 @@ public class JavaEmitter implements GlueEmitter {
javaArgumentTypes.add(mappedType);
//System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType);
}
+ if( null != jcbi ) {
+ jcbi.setFuncProcessed(jcbiSetFuncCBParamIdx, jcbiSetFuncUserParamIdx);
+ LOG.log(INFO, "BindFunc.JavaCallback: {0}: {1}, {2}", sym.getName(), sym.getType().toString(sym.getName(), false, true), jcbi);
+ }
final MethodBinding mb = new MethodBinding(sym, delegationImplName,
javaReturnType, javaArgumentTypes,
containingType, containingCType);
@@ -3272,19 +3275,6 @@ public class JavaEmitter implements GlueEmitter {
}
}
- /**
- * Converts first letter to upper case.
- */
- private static String capitalizeString(final String string) {
- return Character.toUpperCase(string.charAt(0)) + string.substring(1);
- }
- /**
- * Converts first letter to lower case.
- */
- private static String decapitalizeString(final String string) {
- return Character.toLowerCase(string.charAt(0)) + string.substring(1);
- }
-
private static final String optStringCharsetCode =
" private static Charset _charset = StandardCharsets.UTF_8;\n" +
"\n"+
diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
index 74e18e5..1469b4f 100644
--- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
@@ -40,6 +40,7 @@
package com.jogamp.gluegen;
+import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
import com.jogamp.gluegen.cgram.HeaderParser;
import com.jogamp.gluegen.cgram.types.AliasedSymbol;
import com.jogamp.gluegen.cgram.types.ArrayType;
@@ -94,6 +95,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
private String returnedArrayLengthExpression;
private boolean returnedArrayLengthExpressionOnlyForComments = false;
+ private final JavaCallbackInfo javaCallback;
+
// A suffix used to create a temporary outgoing array of Buffers to
// represent an array of compound type wrappers
private static final String COMPOUND_ARRAY_SUFFIX = "_buf_array_copy";
@@ -131,6 +134,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
} else {
setCommentEmitter(defaultInterfaceCommentEmitter);
}
+ javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
// !forImplementingMethodCall && !isInterface
}
@@ -152,6 +156,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
epilogue = arg.epilogue;
returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments;
+ javaCallback = arg.javaCallback;
}
public boolean isNativeMethod() { return isNativeMethod; }
@@ -411,17 +416,17 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
}
if( hasModifier(JavaMethodBindingEmitter.NATIVE) &&
- null != cfg.bindingToJavaCallbackMap.get(binding.getName()) ) {
+ null != javaCallback )
+ {
if (needComma) {
unit.emit(", ");
}
- unit.emit("String callbackSignature");
+ unit.emit("String callbackSignature, long[/*1*/] nativeUserParam");
++numEmitted;
}
return numEmitted;
}
-
protected String getNativeImplMethodName() {
return binding.getImplName() + ( useNIODirectOnly ? "0" : "1" );
}
@@ -468,6 +473,40 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
unit.emitln(" }");
}
+ if( null != javaCallback && !isPrivateNativeMethod ) {
+ unit.emitln();
+ final String userParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
+ unit.emit(" public boolean is"+getInterfaceName()+"Mapped(final Object "+userParamArgName+")");
+ if( isInterface() ) {
+ unit.emitln(";");
+ } else {
+ unit.emitln(" {");
+ unit.emitln(" return null != "+javaCallback.cbFuncTypeName+"UsrMap.get("+userParamArgName+");");
+ unit.emitln(" }");
+ unit.emitln(" private final void release"+getInterfaceName()+"(final Object "+userParamArgName+") {");
+ unit.emitln(" final "+javaCallback.cbFuncTypeName+"UserParam v = "+javaCallback.cbFuncTypeName+"UsrMap.remove("+userParamArgName+");");
+ // unit.emitln(" System.err.println(\"ZZZ Release v \"+v+\", v.nativeParam 0x\"+Long.toHexString(null!=v?v.nativeParam:0));");
+ unit.emitln(" if( null != v ) {");
+ unit.emitln(" release"+getInterfaceName()+"Impl(v.nativeParam);");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln(" private static class "+javaCallback.cbFuncTypeName+"UserParam {");
+ unit.emitln(" @SuppressWarnings(\"unused\")");
+ unit.emitln(" final "+javaCallback.cbFuncTypeName+" func;");
+ unit.emitln(" @SuppressWarnings(\"unused\")");
+ unit.emitln(" final Object param;");
+ unit.emitln(" @SuppressWarnings(\"unused\")");
+ unit.emitln(" final long nativeParam;");
+ unit.emitln(" "+javaCallback.cbFuncTypeName+"UserParam("+javaCallback.cbFuncTypeName+" func, Object param, long nativeParam) {");
+ unit.emitln(" this.func = func;");
+ unit.emitln(" this.param = param;");
+ unit.emitln(" this.nativeParam = nativeParam;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln(" private final java.util.Map<Object, "+javaCallback.cbFuncTypeName+"UserParam> "+javaCallback.cbFuncTypeName+"UsrMap = new java.util.HashMap<Object, "+javaCallback.cbFuncTypeName+"UserParam>();");
+ unit.emitln(" private native void release"+getInterfaceName()+"Impl(long nativeUserParam);");
+ }
+ }
}
protected void emitPrologueOrEpilogue(final List<String> code) {
@@ -579,11 +618,14 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
protected void emitReturnVariableSetupAndCall(final MethodBinding binding) {
- unit.emit(" ");
final JavaType returnType = binding.getJavaReturnType();
boolean needsResultAssignment = false;
+ if( null != javaCallback ) {
+ unit.emitln(" final long[] nativeUserParam = { 0 };");
+ }
if (!returnType.isVoid()) {
+ unit.emit(" ");
if (returnType.isCompoundTypeWrapper() ||
returnType.isNIOBuffer()) {
unit.emitln("final ByteBuffer _res;");
@@ -612,6 +654,17 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
emitCall(binding);
unit.emitln();
+ if( null != javaCallback ) {
+ final String funcArgName = binding.getArgumentName(javaCallback.setFuncCBParamIdx);
+ final String userParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
+ // unit.emitln(" System.err.println(\"ZZZ returned nativeUserParam \"+nativeUserParam[0]);");
+ unit.emitln(" if( 0 == nativeUserParam[0] ) {");
+ unit.emitln(" release"+getInterfaceName()+"("+userParamArgName+");");
+ unit.emitln(" } else {");
+ unit.emitln(" "+javaCallback.cbFuncTypeName+"UsrMap.put("+userParamArgName+", new "+javaCallback.cbFuncTypeName+"UserParam("+funcArgName+", "+userParamArgName+", nativeUserParam[0]));");
+ unit.emitln(" }");
+ }
+
emitPostCallCleanup(binding);
emitPrologueOrEpilogue(epilogue);
if (needsResultAssignment) {
@@ -733,12 +786,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
needComma = true;
++numArgsEmitted;
}
- final JavaConfiguration.JavaCallback jcb = cfg.bindingToJavaCallbackMap.get(binding.getName());
- if( null != jcb ) {
+ if( null != javaCallback ) {
if (needComma) {
unit.emit(", ");
}
- unit.emit("\"" + jcb.methodSignature + "\"");
+ unit.emit("\"" + javaCallback.cbMethodSignature + "\", nativeUserParam");
++numArgsEmitted;
}
return numArgsEmitted;