aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/com/jogamp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-06-30 11:36:33 +0200
committerSven Gothel <[email protected]>2023-06-30 11:36:33 +0200
commita73c992290930e617c78241bae9fe20cb18a01a9 (patch)
tree85115a5cf25d8b5018a8c2d78244272f504851e0 /src/java/com/jogamp
parentb35d62425311ec50e6c80b07372bc411aa287bb4 (diff)
GlueGen JavaCallback: Resolve key mapping of callback and associated resources via 'JavaCallbackKey' config and custom `SetCallback-KeyClass`
Updated unit test and doc accordingly. Unit tests handle OpenAL's AL_SOFT_callback_buffer and AL_SOFT_events. Tested global scope (no key, default) and 1 key (default) and 1 key (custom class). Added more query functions, which all only take the `SetCallbackFunction` key arguments as specified. Cleaned up JavaCallback* config class field naminig scheme. Added 'synchronized (..Map) { }' block in crucial `SetCallbackFunction`, rendering implementation thread safe.
Diffstat (limited to 'src/java/com/jogamp')
-rw-r--r--src/java/com/jogamp/gluegen/CMethodBindingEmitter.java32
-rw-r--r--src/java/com/jogamp/gluegen/JavaConfiguration.java98
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java62
-rw-r--r--src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java221
4 files changed, 314 insertions, 99 deletions
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
index 3975315..43d11b7 100644
--- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
@@ -154,7 +154,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
if( null != javaCallback ) {
- jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.simpleCbClazzName.replace("_", "") );
+ jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.cbSimpleClazzName.replace("_", "") );
jcbCMethodEmitter = new CMethodBindingEmitter(javaCallback.cbFuncBinding,
unit, javaPackageName, javaClassName, isOverloadedBinding,
isJavaMethodStatic, forImplementingMethodCall,
@@ -324,12 +324,13 @@ public class CMethodBindingEmitter extends FunctionEmitter {
*/
public final MachineDataInfo getMachineDataInfo() { return machDesc; }
+ private static final boolean DEBUG_JAVACALLBACK = false;
@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 String userParamArgName = javaCallback.cbFuncBinding.getArgumentName(javaCallback.cbFuncUserParamIdx);
final Type cReturnType = javaCallback.cbFuncBinding.getCReturnType();
final JavaType jretType = javaCallback.cbFuncBinding.getJavaReturnType();
unit.emitln("typedef struct {");
@@ -362,7 +363,6 @@ public class CMethodBindingEmitter extends FunctionEmitter {
unit.emitln(" T_"+jcbNativeBasename+"* cb = (T_"+jcbNativeBasename+"*) "+userParamArgName+";");
unit.emitln(" // C Params: "+javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), false, 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()+") ");
@@ -371,10 +371,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
}
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);");
+ jcbCMethodEmitter.emitJavaCallbackBodyPassJavaArguments(javaCallback, "cb->userParam");
+ unit.emitln(");");
// javaCallback.cbFuncCEmitter.emitBodyUserVariableAssignments();
// javaCallback.cbFuncCEmitter.emitBodyVariablePostCallCleanup();
@@ -393,7 +391,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
/* pp */ int emitJavaCallbackBodyCToJavaPreCall(final JavaCallbackInfo jcbi) {
int count = 0;
for (int i = 0; i < binding.getNumArguments(); i++) {
- if( i == jcbi.userParamIdx ) {
+ if( i == jcbi.cbFuncUserParamIdx ) {
continue;
}
if( emitBodyMapCToJNIType(i, true /* addLocalVar */) ) {
@@ -402,18 +400,19 @@ public class CMethodBindingEmitter extends FunctionEmitter {
}
return count;
}
- /* pp */ int emitJavaCallbackBodyPassJavaArguments(final JavaCallbackInfo jcbi) {
+ /* pp */ int emitJavaCallbackBodyPassJavaArguments(final JavaCallbackInfo jcbi, final String userParamVarName) {
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" );
+ if( i == jcbi.cbFuncUserParamIdx ) {
+ unit.emit( userParamVarName );
+ } else {
+ unit.emit( binding.getArgumentName(i) + "_jni" );
+ }
needsComma = true;
++count;
}
@@ -552,7 +551,9 @@ public class CMethodBindingEmitter extends FunctionEmitter {
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+");");
+ if( DEBUG_JAVACALLBACK ) {
+ unit.emitln(" fprintf(stderr, \"YYY user %p -> native %p\\n\", "+userParamArgName+", "+nativeUserParamVarName+");");
+ }
unit.emitln(" }");
unit.emitln();
}
@@ -565,9 +566,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
unit.emitln("}");
unit.emitln();
if( null != jcb ) {
+ final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
unit.emitln("JNIEXPORT void JNICALL");
unit.emit(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
- unit.emitln("_release"+getInterfaceName()+"Impl(JNIEnv *env, jobject _unused, jlong jnativeUserParam) {");
+ unit.emitln("_release"+capIfaceName+"MapImpl(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);");
diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java
index 17ac547..1fe2747 100644
--- a/src/java/com/jogamp/gluegen/JavaConfiguration.java
+++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java
@@ -152,18 +152,21 @@ public class JavaConfiguration {
/** 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;
+ final int cbFuncUserParamIdx;
+ final String setFuncName;
+ final List<Integer> setFuncKeyIndices = new ArrayList<Integer>();
+ final String setFuncKeyClassName; // optional
+ JavaCallbackDef(final String cbFuncTypeName, final int cbFuncUserParamIdx, final String setFuncName, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
- this.userParamIdx = userParamIdx;
+ this.cbFuncUserParamIdx = cbFuncUserParamIdx;
+ this.setFuncName = setFuncName;
+ this.setFuncKeyClassName = setFuncKeyClassName;
}
@Override
public String toString() {
- return String.format("JavaCallbackDef[set %s, cb %s, userParamIdx %d]",
- setFuncName, cbFuncTypeName, userParamIdx);
+ return String.format("JavaCallbackDef[cbFunc[type %s, userParamIdx %d], set[%s, keys %s, KeyClass %s]]",
+ cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncKeyIndices.toString(), setFuncKeyClassName);
}
}
private final List<JavaCallbackDef> javaCallbackList = new ArrayList<JavaCallbackDef>();
@@ -1377,6 +1380,8 @@ public class JavaConfiguration {
readArgumentIsString(tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("JavaCallbackDef")) {
readJavaCallbackDef(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("JavaCallbackKey")) {
+ readJavaCallbackKey(tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("ExtendedInterfaceSymbolsIgnore")) {
readExtendedIntfImplSymbols(tok, filename, lineNo, true, false, false);
} else if (cmd.equalsIgnoreCase("ExtendedInterfaceSymbolsOnly")) {
@@ -1626,8 +1631,14 @@ public class JavaConfiguration {
try {
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);
+ final Integer cbFuncUserParamIdx = Integer.valueOf(tok.nextToken());
+ final String cbFuncKeyClassName;
+ if( tok.hasMoreTokens() ) {
+ cbFuncKeyClassName = tok.nextToken();
+ } else {
+ cbFuncKeyClassName = null;
+ }
+ final JavaCallbackDef jcd = new JavaCallbackDef(cbFuncTypeName, cbFuncUserParamIdx, setFuncName, cbFuncKeyClassName);
javaCallbackList.add(jcd);
javaCallbackSetFuncToDef.put(setFuncName, jcd);
} catch (final NoSuchElementException e) {
@@ -1636,6 +1647,26 @@ public class JavaConfiguration {
}
}
+ protected void readJavaCallbackKey(final StringTokenizer tok, final String filename, final int lineNo) {
+ try {
+ final String setFuncName = tok.nextToken();
+ final JavaCallbackDef jcd = javaCallbackSetFuncToDef.get(setFuncName);
+ if( null == jcd ) {
+ throw new IllegalArgumentException("JavaCallbackDef '"+setFuncName+"\' not (yet) defined.");
+ }
+ while( tok.hasMoreTokens() ) {
+ final int idx = Integer.valueOf(tok.nextToken());
+ if( 0 > idx ) {
+ throw new IllegalArgumentException("JavaCallbackKey '"+setFuncName+"\' index "+idx+" not in range [0..n].");
+ }
+ jcd.setFuncKeyIndices.add( idx );
+ }
+ } catch (final NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"JavaCallbackKey\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
protected void readExtendedIntfImplSymbols(final StringTokenizer tok, final String filename, final int lineNo, final boolean forInterface, final boolean forImplementation, final boolean onlyList) {
File javaFile;
BufferedReader javaReader;
@@ -2245,44 +2276,53 @@ public class JavaConfiguration {
* @see JavaConfiguration#setFuncToJavaCallbackMap
*/
public static class JavaCallbackInfo {
- final String setFuncName;
final String cbFuncTypeName;
- final String simpleCbClazzName;
- final String fqCbClazzName;
+ final String cbSimpleClazzName;
+ final String cbFQClazzName;
final String cbMethodSignature;
final FunctionType cbFuncType;
final MethodBinding cbFuncBinding;
- final int userParamIdx;
+ final int cbFuncUserParamIdx;
+
final Type userParamType;
final String userParamName;
+
+ final String setFuncName;
+ final List<Integer> setFuncKeyIndices;
+ final String setFuncKeyClassName;
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;
+ public JavaCallbackInfo(final String cbFuncTypeName, final String cbSimpleClazzName, final String cbFQClazzName, final String cbMethodSignature,
+ final FunctionType cbFuncType, final MethodBinding cbFuncBinding, final int cbFuncUserParamIdx,
+ final String setFuncName, final List<Integer> setFuncKeyIndices, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
- this.simpleCbClazzName = simpleClazzName;
- this.fqCbClazzName = fqClazzName;
- this.cbMethodSignature = methodSignature;
+ this.cbSimpleClazzName = cbSimpleClazzName;
+ this.cbFQClazzName = cbFQClazzName;
+ this.cbMethodSignature = cbMethodSignature;
this.cbFuncType = cbFuncType;
this.cbFuncBinding = cbFuncBinding;
int paramIdx = -2;
Type paramType = null;
String paramName = null;
- if( 0 <= userParamIdx && userParamIdx < cbFuncType.getNumArguments() ) {
- final Type t = cbFuncType.getArgumentType(userParamIdx);
+ if( 0 <= cbFuncUserParamIdx && cbFuncUserParamIdx < cbFuncType.getNumArguments() ) {
+ final Type t = cbFuncType.getArgumentType(cbFuncUserParamIdx);
if( null != t && t.isPointer() ) {
// OK '<something>*'
- paramIdx = userParamIdx;
- paramName = cbFuncType.getArgumentName(userParamIdx);
+ paramIdx = cbFuncUserParamIdx;
+ paramName = cbFuncType.getArgumentName(cbFuncUserParamIdx);
paramType = t.getTargetType();
}
}
- this.userParamIdx = paramIdx;
+ this.cbFuncUserParamIdx = paramIdx;
+
this.userParamType = paramType;
this.userParamName = paramName;
+
+ this.setFuncName = setFuncName;
+ this.setFuncKeyIndices = setFuncKeyIndices;
+ this.setFuncKeyClassName = setFuncKeyClassName;
this.setFuncProcessed = false;
this.setFuncCBParamIdx = -1;
this.setFuncUserParamIdx = -1;
@@ -2303,12 +2343,16 @@ public class JavaConfiguration {
@Override
public String toString() {
- 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,
+ return String.format("JavaCallbackInfo[cbFunc[%s%s, userParam[idx %d, '%s', %s], set[%s(ok %b, cbIdx %d, upIdx %d, keys %s, KeyClass '%s'], %s]",
cbFuncTypeName, cbMethodSignature,
- userParamIdx, userParamName, userParamType.getSignature(null).toString(), cbFuncType.toString(cbFuncTypeName, false, true));
+ cbFuncUserParamIdx, userParamName, userParamType.getSignature(null).toString(),
+ setFuncName, setFuncProcessed, setFuncCBParamIdx, setFuncUserParamIdx,
+ setFuncKeyIndices.toString(), setFuncKeyClassName,
+ cbFuncType.toString(cbFuncTypeName, false, true));
}
}
/** Mapped binding name to {@link JavaCallbackInfo} */
/* pp */ final Map<String, JavaCallbackInfo> setFuncToJavaCallbackMap = new HashMap<String, JavaCallbackInfo>();
+ final Set<String> emittedJavaCallbackUserParamClasses = new HashSet<String>();
+
}
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index 7dad237..7674e1f 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -75,7 +75,6 @@ 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;
@@ -1461,27 +1460,46 @@ public class JavaEmitter implements GlueEmitter {
funcSym.addAliasedName(jcbd.cbFuncTypeName);
LOG.log(INFO, "JavaCallback: fSym {0}, {1}", funcSym.getAliasedString(), jcbd);
- final String simpleClazzName = CodeGenUtils.capitalizeString(jcbd.cbFuncTypeName);
- final String fqClazzName = cfg.packageName()+"."+cfg.className()+"."+simpleClazzName;
- final StringBuilder methodSignature = new StringBuilder();
- javaUnit.emitln(" /** JavaCallback interface: "+jcbd.cbFuncTypeName+" -> "+funcType.toString(jcbd.cbFuncTypeName, false, true)+" */");
- javaUnit.emitln(" public static interface "+simpleClazzName+" {");
- final List<MethodBinding> mbs = generateFunctionInterfaceCode(javaUnit, funcSym, jcbd.userParamIdx, methodSignature);
- javaUnit.emitln(" }");
- javaUnit.emitln();
- 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);
+ final String cbSimpleClazzName = CodeGenUtils.capitalizeString(jcbd.cbFuncTypeName);
+ final String cbFQClazzName = cfg.packageName()+"."+cfg.className()+"."+cbSimpleClazzName;
+
+ final JavaCallbackInfo jcbi0 = javaCallbackInterfaceMap.get(cbFQClazzName);
+ if( null != jcbi0 ) {
+ // Reuse callback-func interface, can't duplicate
+ if( jcbi0.cbFuncUserParamIdx != jcbd.cbFuncUserParamIdx ) {
+ throw new UnsupportedOperationException("Reused FuncTypeName "+jcbd.cbFuncTypeName+" used with different FuncUserParamIdx "+jcbi0.cbFuncUserParamIdx+" -> "+jcbd.cbFuncUserParamIdx+". Func "+
+ funcType.toString(jcbd.cbFuncTypeName, false, true));
+ }
+ final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, jcbi0.cbMethodSignature,
+ funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx,
+ jcbd.setFuncName, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
+ cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
+ LOG.log(INFO, "JavaCallbackInfo: Reusing {0} -> {1}", jcbd.setFuncName, jcbi0);
+ } else {
+ final StringBuilder cbMethodSignature = new StringBuilder();
+ javaUnit.emitln(" /** JavaCallback interface: "+jcbd.cbFuncTypeName+" -> "+funcType.toString(jcbd.cbFuncTypeName, false, true)+" */");
+ javaUnit.emitln(" public static interface "+cbSimpleClazzName+" {");
+ final List<MethodBinding> mbs = generateFunctionInterfaceCode(javaUnit, funcSym, jcbd.cbFuncUserParamIdx, cbMethodSignature);
+ javaUnit.emitln(" }");
+ javaUnit.emitln();
+ 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 cbFuncBinding = mbs.get(0);
+ if( !cbFuncBinding.getJavaReturnType().isVoid() && !cbFuncBinding.getJavaReturnType().isPrimitive() ) {
+ throw new UnsupportedOperationException("Non void or non-primitive callback return types not suppored. Java "+
+ cbFuncBinding.getJavaReturnType()+", func "+funcType.toString(jcbd.cbFuncTypeName, false, true));
+ }
+ final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, cbMethodSignature.toString(),
+ funcType, cbFuncBinding, jcbd.cbFuncUserParamIdx,
+ jcbd.setFuncName, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
+ cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
+ javaCallbackInterfaceMap.put(cbFQClazzName, jcbi1);
+ LOG.log(INFO, "JavaCallbackInfo: Added {0} -> {1}", jcbd.setFuncName, jcbi1);
+ }
}
+ private final Map<String, JavaCallbackInfo> javaCallbackInterfaceMap = new HashMap<String, JavaCallbackInfo>();
+
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);
@@ -3085,7 +3103,7 @@ public class JavaEmitter implements GlueEmitter {
{
// Replace JavaCallback type with generated interface name
jcbiSetFuncCBParamIdx=i;
- mappedType = JavaType.createForNamedClass( jcbi.fqCbClazzName );
+ mappedType = JavaType.createForNamedClass( jcbi.cbFQClazzName );
} else if( null != jcbi && jcbi.userParamName.equals( cArgName ) &&
( !jcbi.setFuncProcessed || i == jcbi.setFuncUserParamIdx ) &&
cArgType.isPointer() && jcbi.userParamType.equals( cArgType.getTargetType() ) )
diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
index 047a637..2bc453d 100644
--- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
@@ -50,6 +50,8 @@ import com.jogamp.gluegen.cgram.types.Type;
import java.io.PrintWriter;
import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -455,6 +457,114 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
return getArgumentName(i) + "_offset";
}
+ private static final boolean DEBUG_JAVACALLBACK = false;
+
+ private final void emitJavaCallbackKeyClass(final String KeyClassName) {
+ unit.emitln(" private static class "+KeyClassName+" {");
+ binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
+ unit.emitln(" private final "+jType+" "+name+";");
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(" "+KeyClassName+"("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+") {");
+ binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
+ unit.emitln(" this."+name+" = "+name+";");
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(" }");
+ unit.emitln(" @Override");
+ unit.emitln(" public boolean equals(final Object o) {");
+ unit.emitln(" if( this == o ) {");
+ unit.emitln(" return true;");
+ unit.emitln(" }");
+ unit.emitln(" if( !(o instanceof "+KeyClassName+") ) {");
+ unit.emitln(" return false;");
+ unit.emitln(" }");
+ {
+ final int count = binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
+ if( 0 == consumedCount ) {
+ unit.emitln(" final "+KeyClassName+" o2 = ("+KeyClassName+")o;");
+ unit.emit (" return ");
+ } else {
+ unit.emitln(" &&");
+ unit.emit (" ");
+ }
+ if( jType.isPrimitive() || idx == javaCallback.setFuncUserParamIdx ) {
+ unit.emit(name+" == o2."+name);
+ } else {
+ unit.emit(name+".equals( o2."+name+" )");
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ if( 0 == count ) {
+ unit.emit(" return true");
+ }
+ unit.emitln(";");
+ }
+ unit.emitln(" }");
+ unit.emitln(" @Override");
+ unit.emitln(" public int hashCode() {");
+ {
+ final int count = binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
+ if( 0 == consumedCount ) {
+ unit.emitln(" // 31 * x == (x << 5) - x");
+ unit.emit (" int hash = ");
+ } else {
+ unit.emit (" hash = ((hash << 5) - hash) + ");
+ }
+ if( jType.isPrimitive() ) {
+ if( jType.isLong() ) {
+ unit.emitln("Long.valueOf( "+name+" ).hashCode();");
+ } else {
+ unit.emitln(name+";");
+ }
+ } else {
+ if( idx == javaCallback.setFuncUserParamIdx ) {
+ unit.emitln("System.identityHashCode( "+name+" );");
+ } else {
+ unit.emitln(name+".hashCode();");
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ if( 0 == count ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return hash;");
+ }
+ }
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+ private final void emitJavaCallbackUsrParamClass(final String UsrParamClassName) {
+ unit.emitln(" private static class "+UsrParamClassName+" {");
+ unit.emitln(" final "+javaCallback.cbFuncTypeName+" func;");
+ unit.emitln(" final Object param;");
+ unit.emitln(" final long nativeParam;");
+ unit.emitln(" "+UsrParamClassName+"("+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(" }");
+ }
+
@Override
protected void emitBody() {
if (!emitBody) {
@@ -474,37 +584,68 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
unit.emitln(" }");
}
if( null != javaCallback && !isPrivateNativeMethod ) {
+ final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
+ final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
unit.emitln();
- final String userParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
- unit.emit(" public boolean is"+getInterfaceName()+"Mapped(final Object "+userParamArgName+")");
if( isInterface() ) {
- unit.emitln(";");
+ unit.emitln(" public boolean is"+capIfaceName+"Mapped("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" public "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" public Object get"+capIfaceName+"UserParam("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
} else {
- unit.emitln(" {");
- unit.emitln(" return null != "+javaCallback.cbFuncTypeName+"UsrMap.get("+userParamArgName+");");
+ final String usrMapInstanceName = lowIfaceName+"UsrMap";
+ final boolean customKeyClass;
+ final String KeyClassName;
+ if( null != javaCallback.setFuncKeyClassName ) {
+ customKeyClass = true;;
+ KeyClassName = javaCallback.setFuncKeyClassName;
+ } else {
+ customKeyClass = false;
+ KeyClassName = CodeGenUtils.capitalizeString(capIfaceName+"Key");
+ }
+ final String UsrParamClassName = CodeGenUtils.capitalizeString( javaCallback.cbFuncTypeName+"UserParam" );
+ final String fqUsrParamClassName = cfg.packageName()+"."+cfg.className()+"."+UsrParamClassName;
+ unit.emitln(" public final boolean is"+capIfaceName+"Mapped("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+") {");
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" return null != "+usrMapInstanceName+".get(key);");
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(" public final "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+") {");
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" final "+UsrParamClassName+" value = "+usrMapInstanceName+".get(key);");
+ unit.emitln(" return null != value ? value.func : null;");
+ unit.emitln(" }");
+ unit.emitln(" public final Object get"+capIfaceName+"UserParam("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+") {");
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" final "+UsrParamClassName+" value = "+usrMapInstanceName+".get(key);");
+ unit.emitln(" return null != value ? value.param : null;");
+ unit.emitln(" }");
+ unit.emitln(" private final void add"+capIfaceName+"Map("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, true).toString()+UsrParamClassName+" value) {");
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" "+usrMapInstanceName+".put(key, value);");
+ if( DEBUG_JAVACALLBACK ) {
+ unit.emitln(" System.err.println(\"ZZZ Map \"+key+\" -> value.nativeParam 0x\"+Long.toHexString(null!=value?value.nativeParam:0));");
+ }
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(" private final void release"+capIfaceName+"Map("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+") {");
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" final "+UsrParamClassName+" value = "+usrMapInstanceName+".remove(key);");
+ if( DEBUG_JAVACALLBACK ) {
+ unit.emitln(" System.err.println(\"ZZZ Release \"+key+\" -> value.nativeParam 0x\"+Long.toHexString(null!=value?value.nativeParam:0));");
+ }
+ unit.emitln(" if( null != value ) {");
+ unit.emitln(" release"+capIfaceName+"MapImpl(value.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);");
+ unit.emitln(" private native void release"+capIfaceName+"MapImpl(long nativeUserParam);");
+ unit.emitln();
+ if( !customKeyClass ) {
+ emitJavaCallbackKeyClass(KeyClassName);
+ }
+ if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) {
+ emitJavaCallbackUsrParamClass(UsrParamClassName);
+ cfg.emittedJavaCallbackUserParamClasses.add(fqUsrParamClassName);
+ }
+ unit.emitln(" private final java.util.Map<"+KeyClassName+", "+UsrParamClassName+"> "+usrMapInstanceName+" = new java.util.HashMap<"+KeyClassName+", "+UsrParamClassName+">();");
+ unit.emitln();
}
}
}
@@ -620,14 +761,18 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
protected void emitReturnVariableSetupAndCall(final MethodBinding binding) {
final JavaType returnType = binding.getJavaReturnType();
boolean needsResultAssignment = false;
+ final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
if( null != javaCallback ) {
- final String userParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
- unit.emitln(" release"+getInterfaceName()+"("+userParamArgName+"); // Ensure a previously mapped instance is released");
- unit.emitln(" final long[] nativeUserParam = { 0 };");
+ final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
+ final String usrMapInstanceName = lowIfaceName+"UsrMap";
+ unit.emitln(" synchronized( "+usrMapInstanceName+" ) {");
+ unit.emitln(" final long[] nativeUserParam = { 0 };");
+ unit.emitln(" release"+capIfaceName+"Map("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+"); // Ensure a previously mapped instance is released");
+ unit.emitln();
}
if (!returnType.isVoid()) {
- unit.emit(" ");
+ unit.emit(" ");
if (returnType.isCompoundTypeWrapper() ||
returnType.isNIOBuffer()) {
unit.emitln("final ByteBuffer _res;");
@@ -645,9 +790,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
if (needsResultAssignment) {
- unit.emit(" _res = ");
+ unit.emit(" _res = ");
} else {
- unit.emit(" ");
+ unit.emit(" ");
if (!returnType.isVoid()) {
unit.emit("return ");
}
@@ -659,10 +804,16 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
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(" "+javaCallback.cbFuncTypeName+"UsrMap.put("+userParamArgName+", new "+javaCallback.cbFuncTypeName+"UserParam("+funcArgName+", "+userParamArgName+", nativeUserParam[0]));");
- unit.emitln(" }");
+ final String UsrParamClassName = CodeGenUtils.capitalizeString( javaCallback.cbFuncTypeName+"UserParam" );
+ if( DEBUG_JAVACALLBACK ) {
+ unit.emitln(" System.err.println(\"ZZZ returned nativeUserParam 0x\"+Long.toHexString(nativeUserParam[0]));");
+ }
+ unit.emitln();
+ unit.emitln(" if( 0 != nativeUserParam[0] ) {");
+ unit.emitln(" add"+capIfaceName+"Map("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, true).toString()+
+ "new "+UsrParamClassName+"("+funcArgName+", "+userParamArgName+", nativeUserParam[0]));");
+ unit.emitln(" }");
+ unit.emitln(" } // synchronized ");
}
emitPostCallCleanup(binding);