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/CCodeUnit.java15
-rw-r--r--src/java/com/jogamp/gluegen/CMethodBindingEmitter.java355
-rw-r--r--src/java/com/jogamp/gluegen/FunctionEmitter.java57
-rw-r--r--src/java/com/jogamp/gluegen/JavaCallbackEmitter.java666
-rw-r--r--src/java/com/jogamp/gluegen/JavaConfiguration.java87
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java36
-rw-r--r--src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java437
-rw-r--r--src/java/com/jogamp/gluegen/JavaType.java109
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java13
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java9
10 files changed, 1016 insertions, 768 deletions
diff --git a/src/java/com/jogamp/gluegen/CCodeUnit.java b/src/java/com/jogamp/gluegen/CCodeUnit.java
index c70df79..5c0db27 100644
--- a/src/java/com/jogamp/gluegen/CCodeUnit.java
+++ b/src/java/com/jogamp/gluegen/CCodeUnit.java
@@ -84,11 +84,6 @@ public class CCodeUnit extends CodeUnit {
emitln( getJNIOnLoadJNIEnvCode(libraryBasename) );
}
- /** Emits {@link #JavaCallbackGlueDataDecl}. */
- public void emitJavaCallbackGlueDataDecl() {
- emitln( JavaCallbackGlueDataDecl );
- }
-
@Override
public String toString() { return "CCodeUnit[unit "+cUnitName+", file "+filename+"]"; }
@@ -113,16 +108,6 @@ public class CCodeUnit extends CodeUnit {
" return jbyteBuffer;\n"+
"}\n";
- /** JavaCallback Glue Data typedef struct */
- public static final String JavaCallbackGlueDataDecl =
- "typedef struct {\n"+
- " jobject lockObj;\n"+
- " jobject cbFunc;\n"+
- " jmethodID cbMethodID;\n"+
- " jobject userParam;\n"+
- "} T_JavaCallbackGlueData;\n"+
- "\n";
-
/**
* Returns native JNI declarations for `JavaVM* {libraryBasename}_jvmHandle`
* and `JVMUtil_GetJNIEnv(..)`.
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
index 00cae13..9c7ed0b 100644
--- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
@@ -113,15 +113,11 @@ public class CMethodBindingEmitter extends FunctionEmitter {
protected static final String STRING_CHARS_PREFIX = "_strchars_";
- protected static final String T_JavaCallbackGlueData = "T_JavaCallbackGlueData";
-
// We need this in order to compute sizes of certain types
protected MachineDataInfo machDesc;
- private final JavaCallbackInfo javaCallback;
- private final String jcbNativeBasename;
- private final String jcbFriendlyBasename;
private final CMethodBindingEmitter jcbCMethodEmitter;
+ private final JavaCallbackEmitter javaCallbackEmitter;
/**
* Constructs an emitter for the specified binding, and sets a default
@@ -155,18 +151,17 @@ public class CMethodBindingEmitter extends FunctionEmitter {
this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
this.machDesc = machDesc;
- javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ final JavaCallbackInfo javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
if( null != javaCallback ) {
- jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.cbSimpleClazzName.replace("_", "") );
- jcbFriendlyBasename = javaCallback.setFuncName+"("+javaCallback.cbSimpleClazzName+")";
+ // jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.cbSimpleClazzName.replace("_", "") );
jcbCMethodEmitter = new CMethodBindingEmitter(javaCallback.cbFuncBinding,
unit, javaPackageName, javaClassName, isOverloadedBinding,
isJavaMethodStatic, forImplementingMethodCall,
forIndirectBufferAndArrayImplementation, machDesc, configuration);
+ javaCallbackEmitter = new JavaCallbackEmitter(cfg, binding, javaCallback, null);
} else {
- jcbNativeBasename = null;
- jcbFriendlyBasename = null;
jcbCMethodEmitter = null;
+ javaCallbackEmitter = null;
}
setCommentEmitter(defaultCommentEmitter);
}
@@ -328,145 +323,25 @@ 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 staticCallbackName = "func"+jcbNativeBasename;
-
- final Type userParamType = javaCallback.cbFuncBinding.getCArgumentType(javaCallback.cbFuncUserParamIdx);
- final String userParamArgName = javaCallback.cbFuncBinding.getArgumentName(javaCallback.cbFuncUserParamIdx);
- final Type cReturnType = javaCallback.cbFuncBinding.getCReturnType();
- final JavaType jretType = javaCallback.cbFuncBinding.getJavaReturnType();
- unit.emitln();
- // javaCallback.cbFuncCEmitter.emitSignature();
- unit.emit("static "+cReturnType.getCName()+" "+staticCallbackName+"(");
- // javaCallback.cbFuncCEmitter.emitArguments();
- unit.emit(javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), false, 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_JavaCallbackGlueData+"* cb = ("+T_JavaCallbackGlueData+"*) "+userParamArgName+";");
- unit.emitln(" // C Params: "+javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
- unit.emitln(" // J Params: "+javaCallback.cbFuncBinding.getJavaParameterList(new StringBuilder()).toString());
-
- final String returnStatement;
- if( !cReturnType.isVoid() ) {
- unit.emit(" "+cReturnType.getCName()+" _res = 0;");
- returnStatement = "return _res;";
- } else {
- returnStatement = "return;";
- }
- unit.emitln(" if( NULL == cb ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': NULL "+userParamArgName+", skipping!\\n\"); "+returnStatement+" }");
- unit.emitln();
- unit.emitln(" // Use-after-free of '*cb' possible up until after GetObjectRefType() check for a brief moment!");
- unit.emitln(" // Use a copy to avoid data-race between GetObjectRefType() and MonitorEnter()\");");
- unit.emitln(" jobject lockObj = cb->lockObj;");
- unit.emitln(" if( 0 == lockObj ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': NULL lock, skipping!\\n\"); "+returnStatement+" }");
- unit.emitln();
- unit.emitln(" jobjectRefType refType = (*env)->GetObjectRefType(env, lockObj);");
- unit.emitln(" if( 0 == refType ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': User after free(lock), skipping!\\n\"); "+returnStatement+" }");
- unit.emitln(" jint lockRes = (*env)->MonitorEnter(env, lockObj);");
- unit.emitln(" if( 0 != lockRes ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': MonitorEnter failed %d, skipping!\\n\", lockRes); "+returnStatement+" }");
- unit.emitln(" // synchronized block");
- /**
- * Since we have acquired the lock, in-sync w/ our Java code, cb->cbFunc and cb->userParam could not have been changed!
- *
- unit.emitln(" refType = (*env)->GetObjectRefType(env, cb->userParam);");
- unit.emitln(" if( 0 == refType ) {");
- unit.emitln(" fprintf(stderr, \"Info: Callback '"+staticCallbackName+"(..)': User after free(userParam), skipping!\\n\");");
- unit.emitln(" lockRes = (*env)->MonitorExit(env, cb->lockObj);");
- unit.emitln(" if( 0 != lockRes ) { fprintf(stderr, \"Info: Callback '"+staticCallbackName+"(..)': MonitorExit failed %d\\n\", lockRes); }");
- unit.emitln(" "+returnStatement);
- unit.emitln(" }");
- */
- if( !cReturnType.isVoid() ) {
- unit.emit(" _res = ("+cReturnType.getCName()+") ");
- } else {
- unit.emit(" ");
- }
- unit.emit("(*env)->Call" + CodeGenUtils.capitalizeString( jretType.getName() ) +"Method(env, cb->cbFunc, cb->cbMethodID, ");
- // javaCallback.cbFuncCEmitter.emitBodyPassCArguments();
- jcbCMethodEmitter.emitJavaCallbackBodyPassJavaArguments(javaCallback, "cb->userParam");
- unit.emitln(");");
- unit.emitln(" if( (*env)->ExceptionCheck(env) ) {");
- unit.emitln(" fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': Exception in Java Callback caught:\\n\");");
- unit.emitln(" (*env)->ExceptionDescribe(env);");
- unit.emitln(" (*env)->ExceptionClear(env);");
- unit.emitln(" }");
-
- // javaCallback.cbFuncCEmitter.emitBodyUserVariableAssignments();
- // javaCallback.cbFuncCEmitter.emitBodyVariablePostCallCleanup();
- // javaCallback.cbFuncCEmitter.emitBodyMapCToJNIType(-1 /* return value */, true /* addLocalVar */)
-
- unit.emitln(" lockRes = (*env)->MonitorExit(env, cb->lockObj);");
- unit.emitln(" if( 0 != lockRes ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': MonitorExit failed %d\\n\", lockRes); }");
- unit.emitln(" "+returnStatement);
- }
- 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.cbFuncUserParamIdx ) {
- continue;
- }
- if( emitBodyMapCToJNIType(i, true /* addLocalVar */) ) {
- ++count;
- }
- }
- return count;
- }
- /* pp */ int emitJavaCallbackBodyPassJavaArguments(final JavaCallbackInfo jcbi, final String userParamVarName) {
- int count = 0;
- boolean needsComma = false;
- for (int i = 0; i < binding.getNumArguments(); i++) {
- if (needsComma) {
- unit.emit(", ");
- needsComma = false;
- }
- if( i == jcbi.cbFuncUserParamIdx ) {
- unit.emit( userParamVarName );
- } else {
- unit.emit( binding.getArgumentName(i) + "_jni" );
- }
- needsComma = true;
- ++count;
- }
- return count;
+ protected StringBuilder appendReturnType(final StringBuilder buf) {
+ buf.append("JNIEXPORT ");
+ buf.append(binding.getJavaReturnType().jniTypeName());
+ buf.append(" JNICALL");
+ return buf;
}
@Override
- protected void emitName() {
- unit.emitln(); // start name on new line
- unit.emit(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
- unit.emit("_");
+ protected StringBuilder appendName(final StringBuilder buf) {
+ buf.append(System.lineSeparator()); // start name on new line
+ buf.append(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
+ buf.append("_");
if (isOverloadedBinding) {
- unit.emit(jniMangle(binding));
+ buf.append(jniMangle(binding));
} else {
- unit.emit(JavaEmitter.jniMangle(getImplName()));
+ buf.append(JavaEmitter.jniMangle(getImplName()));
}
+ return buf;
}
protected String getImplSuffix() {
@@ -481,24 +356,24 @@ public class CMethodBindingEmitter extends FunctionEmitter {
}
@Override
- protected int emitArguments() {
- unit.emit("JNIEnv *env, ");
+ protected int appendArguments(final StringBuilder buf) {
+ buf.append("JNIEnv *env, ");
int numEmitted = 1; // initially just the JNIEnv
if (isJavaMethodStatic && !binding.hasContainingType()) {
- unit.emit("jclass");
+ buf.append("jclass");
} else {
- unit.emit("jobject");
+ buf.append("jobject");
}
- unit.emit(" _unused");
+ buf.append(" _unused");
++numEmitted;
if( binding.isReturnCompoundByValue() ) {
- unit.emit(", jclass _clazzBuffers");
+ buf.append(", jclass _clazzBuffers");
++numEmitted;
}
if (binding.hasContainingType()) {
// "this" argument always comes down in argument 0 as direct buffer
- unit.emit(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
+ buf.append(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
}
for (int i = 0; i < binding.getNumArguments(); i++) {
final JavaType javaArgType = binding.getJavaArgumentType(i);
@@ -512,91 +387,47 @@ public class CMethodBindingEmitter extends FunctionEmitter {
if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
continue;
}
- unit.emit(", ");
- unit.emit(javaArgType.jniTypeName());
- unit.emit(" ");
- unit.emit(binding.getArgumentName(i));
+ buf.append(", ");
+ buf.append(javaArgType.jniTypeName());
+ buf.append(" ");
+ buf.append(binding.getArgumentName(i));
++numEmitted;
if (javaArgType.isPrimitiveArray() ||
javaArgType.isNIOBuffer()) {
- unit.emit(", jint " + byteOffsetArgName(i));
+ buf.append(", jint " + byteOffsetArgName(i));
if(forIndirectBufferAndArrayImplementation) {
- unit.emit(", jboolean " + isNIOArgName(i));
+ buf.append(", jboolean " + isNIOArgName(i));
}
} else if (javaArgType.isNIOBufferArray()) {
- unit.emit(", jintArray " +
+ buf.append(", jintArray " +
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, jobject jlockObj, jlongArray jnativeUserParam");
- numEmitted+=2;
- } else {
- LOG.log(INFO, "BindCFunc.JavaCallback: {0}: NONE", binding.getName());
+ if( null != javaCallbackEmitter ) {
+ numEmitted += javaCallbackEmitter.appendCAdditionalParameter(buf);
}
return numEmitted;
}
@Override
+ protected void emitAdditionalCode() {
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitCAdditionalCode(unit, jcbCMethodEmitter);
+ }
+ }
+
+ @Override
protected void emitBody() {
unit.emitln(" {");
// unit().emitln("printf(\" - - - - "+ getName() + getImplSuffix() +" - - - -\\n\");");
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_JavaCallbackGlueData+"* "+nativeUserParamVarName+";");
- // unit.emit(", jstring jcallbackSignature, jobject jlockObj, jlongArray jnativeUserParam");
- unit.emitln(" if( NULL == jlockObj ) { (*env)->FatalError(env, \"Null jlockObj in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" if( NULL == jnativeUserParam ) { (*env)->FatalError(env, \"Null jnativeUserParam in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" const size_t jnativeUserParam_size = (*env)->GetArrayLength(env, jnativeUserParam);");
- unit.emitln(" if( 1 > jnativeUserParam_size ) { (*env)->FatalError(env, \"nativeUserParam size < 1 in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" if( NULL != "+cbFuncArgName+" ) {");
- unit.emitln(" if( NULL == "+userParamArgName+" ) { (*env)->FatalError(env, \"Null "+userParamArgName+" in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+" = ("+T_JavaCallbackGlueData+"*) calloc(1, sizeof("+T_JavaCallbackGlueData+"));");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+" ) { (*env)->FatalError(env, \"Can't alloc "+nativeUserParamVarName+" in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->lockObj = (*env)->NewGlobalRef(env, jlockObj);");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->lockObj ) { (*env)->FatalError(env, \"Failed NewGlobalRef(lock) in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->cbFunc = (*env)->NewGlobalRef(env, "+cbFuncArgName+");");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->cbFunc ) { (*env)->FatalError(env, \"Failed NewGlobalRef(func) in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->userParam = (*env)->NewGlobalRef(env, "+userParamArgName+");");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->userParam ) { (*env)->FatalError(env, \"Failed NewGlobalRef(userParam) in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" {");
- unit.emitln(" jclass cbClazz = (*env)->GetObjectClass(env, "+nativeUserParamVarName+"->cbFunc);");
- unit.emitln(" if( NULL == cbClazz ) { (*env)->FatalError(env, \"Failed GetObjectClass in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" const char* callbackSignature = (*env)->GetStringUTFChars(env, jcallbackSignature, (jboolean*)NULL);");
- unit.emitln(" if( NULL == callbackSignature ) { (*env)->FatalError(env, \"Failed callbackSignature in '"+jcbFriendlyBasename+"'\"); }");
- 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 '"+jcbFriendlyBasename+"'\"); }");
- 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);");
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" fprintf(stderr, \"YYY user %p -> native %p\\n\", "+userParamArgName+", "+nativeUserParamVarName+");");
- }
- unit.emitln(" }");
- unit.emitln();
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitCSetFuncPreCall(unit);
}
emitBodyCallCFunction();
emitBodyUserVariableAssignments();
@@ -606,24 +437,6 @@ 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"+capIfaceName+"Impl(JNIEnv *env, jobject _unused, jlong jnativeUserParam) {");
- unit.emitln(" // already locked");
- unit.emitln(" "+T_JavaCallbackGlueData+"* nativeUserParam = ("+T_JavaCallbackGlueData+"*) (intptr_t) jnativeUserParam;");
- unit.emitln(" if( NULL != nativeUserParam ) {");
- unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->lockObj);");
- unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->cbFunc);");
- unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->userParam);");
- unit.emitln(" // Ensure even w/ use-after-free jobject refs are NULL and invalid to avoid accidental reuse.");
- unit.emitln(" memset(nativeUserParam, 0, sizeof("+T_JavaCallbackGlueData+"));");
- unit.emitln(" free(nativeUserParam);");
- unit.emitln(" }");
- unit.emitln("}");
- unit.emitln();
- }
}
protected void emitBodyVariableDeclarations() {
@@ -1173,9 +986,8 @@ 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");
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitCOptArgumentSuffix(unit, i);
}
}
}
@@ -1241,7 +1053,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
* @param addLocalVar if true, emit instantiating the local JNI variable.
* @return true if a non-void result has been produced, otherwise false
*/
- protected boolean emitBodyMapCToJNIType(final int argIdx, final boolean addLocalVar)
+ public boolean emitBodyMapCToJNIType(final int argIdx, final boolean addLocalVar)
{
// WARNING: this code assumes that the return type has already been
// typedef-resolved.
@@ -1436,12 +1248,11 @@ public class CMethodBindingEmitter extends FunctionEmitter {
final StringBuilder buf = new StringBuilder();
buf.append(JavaEmitter.jniMangle(getImplName()));
buf.append(getImplSuffix());
- if( null == this.javaCallback ) {
+ if( null == javaCallbackEmitter ) {
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
+ appendJNIMangledArgs(binding, forIndirectBufferAndArrayImplementation, buf);
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.appendCAdditionalJNIDescriptor(buf);
}
}
return buf.toString();
@@ -1454,13 +1265,13 @@ public class CMethodBindingEmitter extends FunctionEmitter {
* @param buf
* @return
*/
- public static StringBuilder getJNIMangledArgs(final MethodBinding binding, final boolean forIndirectBufferAndArrayImplementation, final StringBuilder buf) {
+ public static StringBuilder appendJNIMangledArgs(final MethodBinding binding, final boolean forIndirectBufferAndArrayImplementation, final StringBuilder buf) {
if (binding.isReturnCompoundByValue()) {
- getJNIMangledArg(Class.class, buf, true);
+ JavaType.appendJNIDescriptor(buf, Class.class, true);
}
if (binding.hasContainingType()) {
// "this" argument always comes down in argument 0 as direct buffer
- getJNIMangledArg(java.nio.ByteBuffer.class, buf, true);
+ JavaType.appendJNIDescriptor(buf, java.nio.ByteBuffer.class, true);
}
for (int i = 0; i < binding.getNumArguments(); i++) {
if (binding.isArgumentThisPointer(i)) {
@@ -1477,31 +1288,31 @@ public class CMethodBindingEmitter extends FunctionEmitter {
} else {
Class<?> c = type.getJavaClass();
if (c != null) {
- getJNIMangledArg(c, buf, false);
+ JavaType.appendJNIDescriptor(buf, c, false);
// If Buffer offset arguments were added, we need to mangle the JNI for the
// extra arguments
if (type.isNIOBuffer()) {
- getJNIMangledArg(Integer.TYPE, buf, false);
+ JavaType.appendJNIDescriptor(buf, Integer.TYPE, false);
if(forIndirectBufferAndArrayImplementation) {
- getJNIMangledArg(Boolean.TYPE, buf, false);
+ JavaType.appendJNIDescriptor(buf, Boolean.TYPE, false);
}
} else if (type.isNIOBufferArray()) {
final int[] intArrayType = new int[0];
c = intArrayType.getClass();
- getJNIMangledArg(c , buf, true);
+ JavaType.appendJNIDescriptor(buf, c , true);
}
if (type.isPrimitiveArray()) {
- getJNIMangledArg(Integer.TYPE, buf, false);
+ JavaType.appendJNIDescriptor(buf, Integer.TYPE, false);
}
} else if (type.isNamedClass()) {
buf.append(type.getJNIMethodDesciptor());
} else if (type.isCompoundTypeWrapper()) {
// Mangle wrappers for C structs as ByteBuffer
- getJNIMangledArg(java.nio.ByteBuffer.class, buf, true);
+ JavaType.appendJNIDescriptor(buf, java.nio.ByteBuffer.class, true);
} else if (type.isArrayOfCompoundTypeWrappers()) {
// Mangle arrays of C structs as ByteBuffer[]
final java.nio.ByteBuffer[] tmp = new java.nio.ByteBuffer[0];
- getJNIMangledArg(tmp.getClass(), buf, true);
+ JavaType.appendJNIDescriptor(buf, tmp.getClass(), true);
} else if (type.isJNIEnv()) {
// These are not exposed at the Java level
} else {
@@ -1514,54 +1325,6 @@ public class CMethodBindingEmitter extends FunctionEmitter {
return buf;
}
- public static void getJNIMangledArg(final Class<?> c, final StringBuilder res, final boolean syntheticArgument) {
- if (c.isPrimitive()) {
- if (c == Boolean.TYPE) res.append("Z");
- else if (c == Byte.TYPE) res.append("B");
- else if (c == Character.TYPE) res.append("C");
- else if (c == Short.TYPE) res.append("S");
- else if (c == Integer.TYPE) res.append("I");
- else if (c == Long.TYPE) res.append("J");
- else if (c == Float.TYPE) res.append("F");
- else if (c == Double.TYPE) res.append("D");
- else throw new RuntimeException("Illegal primitive type \"" + c.getName() + "\"");
- } else {
- // Arrays and NIO Buffers are always passed down as java.lang.Object.
- // The only arrays that show up as true arrays in the signature
- // are the synthetic byte offset arrays created when passing
- // down arrays of direct Buffers. Compound type wrappers are
- // passed down as ByteBuffers (no good reason, just to avoid
- // accidental conflation) so we mangle them differently.
- if (syntheticArgument) {
- if (c.isArray()) {
- res.append("_3");
- final Class<?> componentType = c.getComponentType();
- // Handle arrays of compound type wrappers differently for
- // convenience of the Java-level glue code generation
- getJNIMangledArg(componentType, res,
- (componentType == java.nio.ByteBuffer.class));
- } else {
- res.append("L");
- res.append(c.getName().replace('.', '_'));
- res.append("_2");
- }
- } else {
- if (c.isArray()) {
- res.append("_3");
- getJNIMangledArg(c.getComponentType(), res, false);
- } else if (c == java.lang.String.class) {
- res.append("L");
- res.append(c.getName().replace('.', '_'));
- res.append("_2");
- } else {
- res.append("L");
- res.append("java_lang_Object");
- res.append("_2");
- }
- }
- }
- }
-
private void emitOutOfMemoryCheck(final String varName, final String errorMessage) {
unit.emitln(" if ( NULL == " + varName + " ) {");
unit.emitln(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryError\"),");
diff --git a/src/java/com/jogamp/gluegen/FunctionEmitter.java b/src/java/com/jogamp/gluegen/FunctionEmitter.java
index a089a41..5037fc4 100644
--- a/src/java/com/jogamp/gluegen/FunctionEmitter.java
+++ b/src/java/com/jogamp/gluegen/FunctionEmitter.java
@@ -114,6 +114,7 @@ public abstract class FunctionEmitter {
* Emit the function to the {@link #getUnit()}
*/
public final void emit() {
+ emitAdditionalCode();
emitDocComment();
//output.println(" // Emitter: " + getClass().getName());
emitSignature();
@@ -139,6 +140,7 @@ public abstract class FunctionEmitter {
*/
public CommentEmitter getCommentEmitter() { return commentEmitter; }
+ protected void emitAdditionalCode() { }
protected void emitDocComment() {
if (commentEmitter != null) {
@@ -154,32 +156,42 @@ public abstract class FunctionEmitter {
}
}
- protected void emitSignature() {
+ protected final void emitSignature() {
+ unit.emit(appendSignature(new StringBuilder()).toString());
+ }
- unit.emit(getBaseIndentString()); // indent method
+ protected StringBuilder appendSignature(final StringBuilder buf) {
+ buf.append(getBaseIndentString()); // indent method
- final int numEmitted = emitModifiers();
+ final int numEmitted = appendModifiers(buf);
if (numEmitted > 0) {
- unit.emit(" ");
+ buf.append(" ");
}
- emitReturnType();
- unit.emit(" ");
+ appendReturnType(buf);
+ buf.append(" ");
- emitName();
- unit.emit("(");
+ appendName(buf);
+ buf.append("(");
- emitArguments();
- unit.emit(")");
+ appendArguments(buf);
+ buf.append(")");
+ return buf;
}
- protected int emitModifiers() {
+ protected final int emitModifiers() {
+ final StringBuilder buf = new StringBuilder();
+ final int n = appendModifiers(buf);
+ unit.emit(buf.toString());
+ return n;
+ }
+ protected int appendModifiers(final StringBuilder buf) {
int numEmitted = 0;
for (final Iterator<EmissionModifier> it = getModifiers(); it.hasNext(); ) {
- unit.emit(it.next().toString());
+ buf.append(it.next().toString());
++numEmitted;
if (it.hasNext()) {
- unit.emit(" ");
+ buf.append(" ");
}
}
return numEmitted;
@@ -190,10 +202,23 @@ public abstract class FunctionEmitter {
protected String getCommentStartString() { return "/* "; }
protected String getCommentEndString() { return " */"; }
- protected abstract void emitReturnType();
- protected abstract void emitName();
+ protected final void emitReturnType() {
+ unit.emit(appendReturnType(new StringBuilder()).toString());
+ }
+ protected abstract StringBuilder appendReturnType(StringBuilder buf);
+ protected final void emitName() {
+ unit.emit(appendName(new StringBuilder()).toString());
+ }
+ protected abstract StringBuilder appendName(StringBuilder buf);
+ /** Returns the number of arguments emitted. */
+ protected final int emitArguments() {
+ final StringBuilder buf = new StringBuilder();
+ final int n = appendArguments(buf);
+ unit.emit(buf.toString());
+ return n;
+ }
/** Returns the number of arguments emitted. */
- protected abstract int emitArguments();
+ protected abstract int appendArguments(StringBuilder buf);
protected abstract void emitBody();
public static class EmissionModifier {
diff --git a/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
new file mode 100644
index 0000000..96e1e77
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
@@ -0,0 +1,666 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.gluegen;
+
+import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
+import com.jogamp.gluegen.cgram.types.Type;
+
+public final class JavaCallbackEmitter {
+ final JavaConfiguration cfg;
+ final MethodBinding binding;
+ final String setFuncSignature;
+ final JavaCallbackInfo info;
+ final String capIfaceName;
+ final String lowIfaceName;
+ final String lockInstanceName;
+ final String dataMapInstanceName;
+ final String dataInstanceName;
+ final String DataClassName;
+ final String fqUsrParamClassName;
+ final JavaType cbFuncJavaReturnType;
+ final String jcbNextIDVarName;
+
+ final String setFuncCBArgName;
+ final Type setFuncUserParamCType;
+ final JavaType setFuncUserParamJType;
+ final String setFuncUserParamTypeName;
+ final String setFuncUserParamArgName;
+
+ final boolean customKeyClass;
+ final String KeyClassName;
+ final boolean useDataMap;
+
+ public JavaCallbackEmitter(final JavaConfiguration cfg, final MethodBinding mb, final JavaCallbackInfo javaCallback, final String setFuncSignature) {
+ this.cfg = cfg;
+ this.binding = mb;
+ this.setFuncSignature = setFuncSignature;
+ this.info = javaCallback;
+
+ capIfaceName = CodeGenUtils.capitalizeString( mb.getInterfaceName() );
+ lowIfaceName = CodeGenUtils.decapitalizeString( mb.getInterfaceName() );
+ lockInstanceName = lowIfaceName+"Lock";
+ dataMapInstanceName = lowIfaceName+"DataMap";
+ dataInstanceName = lowIfaceName+"Data";
+ DataClassName = capIfaceName+"Data";
+ fqUsrParamClassName = cfg.packageName()+"."+cfg.className()+"."+DataClassName;
+ cbFuncJavaReturnType = javaCallback.cbFuncBinding.getJavaReturnType();
+ jcbNextIDVarName = "NEXT_"+capIfaceName+"_ID";
+
+ setFuncCBArgName = binding.getArgumentName(javaCallback.setFuncCBParamIdx);
+ setFuncUserParamCType = mb.getCArgumentType(javaCallback.setFuncUserParamIdx);
+ setFuncUserParamJType = mb.getJavaArgumentType(javaCallback.setFuncUserParamIdx);
+ setFuncUserParamTypeName = setFuncUserParamJType.getName();
+ setFuncUserParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
+
+ if( null != javaCallback.setFuncKeyClassName ) {
+ customKeyClass = true;;
+ KeyClassName = javaCallback.setFuncKeyClassName;
+ useDataMap = true;
+ } else {
+ customKeyClass = false;
+ KeyClassName = capIfaceName+"Key";
+ useDataMap = javaCallback.setFuncKeyIndices.size() > 0;
+ }
+ }
+
+ public void emitJavaSetFuncPreCall(final CodeUnit unit) {
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emit (" final long nativeUserParam = ");
+ if( setFuncUserParamJType.isLong() ) {
+ unit.emitln(" "+setFuncUserParamArgName+";");
+ } else if( setFuncUserParamJType.isCompoundTypeWrapper() ) {
+ unit.emitln(" null != "+setFuncUserParamArgName+" ? "+setFuncUserParamArgName+".getDirectBufferAddress() : 0;");
+ } else {
+ unit.emitln(""+jcbNextIDVarName+"++;");
+ unit.emitln(" if( 0 >= "+jcbNextIDVarName+" ) { "+jcbNextIDVarName+" = 1; }");
+ }
+ unit.emitln(" if( null != "+setFuncCBArgName+" ) {");
+ unit.emitln(" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, true).toString()+
+ "new "+DataClassName+"("+setFuncCBArgName+", "+setFuncUserParamArgName+"));");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+
+ public void emitJavaSetFuncPostCall(final CodeUnit unit) {
+ unit.emitln(" if( null == "+setFuncCBArgName+" ) {");
+ unit.emitln(" // callback released (null func) -> release a previously mapped instance ");
+ if( useDataMap ) {
+ unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" ) );");
+ } else {
+ unit.emitln(" release"+capIfaceName+"();");
+ }
+ unit.emitln(" }");
+ unit.emitln(" } // synchronized ");
+ }
+
+ public void emitJavaAdditionalCode(final CodeUnit unit, final boolean isInterface) {
+ if( isInterface ) {
+ if( useDataMap ) {
+ if( !customKeyClass && !info.keyClassEmitted ) {
+ emitJavaKeyClass(unit);
+ unit.emitln();
+ info.keyClassEmitted = true;
+ }
+ emitJavaBriefAPIDoc(unit, "Returns ", "set of ", "", "for ");
+ unit.emitln(" public Set<"+KeyClassName+"> get"+capIfaceName+"Keys();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public boolean is"+capIfaceName+"Mapped("+KeyClassName+" key);");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public "+info.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key);");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public Object get"+capIfaceName+"UserParam("+KeyClassName+" key);");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public int releaseAll"+capIfaceName+"();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public void release"+capIfaceName+"("+KeyClassName+" key);");
+ unit.emitln();
+ } else {
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public boolean is"+capIfaceName+"Mapped();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public "+info.cbFuncTypeName+" get"+capIfaceName+"();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public Object get"+capIfaceName+"UserParam();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public void release"+capIfaceName+"();");
+ unit.emitln();
+ }
+ } else {
+ if( useDataMap ) {
+ if( !customKeyClass && !info.keyClassEmitted ) {
+ emitJavaKeyClass(unit);
+ unit.emitln();
+ info.keyClassEmitted = true;
+ }
+ emitJavaBriefAPIDoc(unit, "Returns ", "set of ", "", "for ");
+ unit.emitln(" public final Set<"+KeyClassName+"> get"+capIfaceName+"Keys() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" return "+dataMapInstanceName+".keySet();");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public final boolean is"+capIfaceName+"Mapped("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" return null != "+dataMapInstanceName+".get(key);");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public final "+info.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
+ unit.emitln(" return null != value ? value.func : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public final Object get"+capIfaceName+"UserParam("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
+ unit.emitln(" return null != value ? value.param : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public final int releaseAll"+capIfaceName+"() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final Set<"+KeyClassName+"> keySet = "+dataMapInstanceName+".keySet();");
+ unit.emitln(" final "+KeyClassName+"[] keys = keySet.toArray(new "+KeyClassName+"[keySet.size()]);");
+ unit.emitln(" for(int i=0; i<keys.length; ++i) {");
+ unit.emitln(" final "+KeyClassName+" key = keys[i];");
+ unit.emitln(" release"+capIfaceName+"(key);");
+ unit.emitln(" }");
+ unit.emitln(" return keys.length;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public final void release"+capIfaceName+"("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" /* final "+DataClassName+" value = */ "+dataMapInstanceName+".remove(key);");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ } else {
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public final boolean is"+capIfaceName+"Mapped() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" return null != "+dataInstanceName+";");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public final "+info.cbFuncTypeName+" get"+capIfaceName+"() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
+ unit.emitln(" return null != value ? value.func : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public final Object get"+capIfaceName+"UserParam() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
+ unit.emitln(" return null != value ? value.param : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public final void release"+capIfaceName+"() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" // final "+DataClassName+" value = "+dataInstanceName+";");
+ unit.emitln(" "+dataInstanceName+" = null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+ unit.emitln(" private final void add"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, true).toString()+DataClassName+" value) {");
+ if( useDataMap ) {
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" /* final "+DataClassName+" old = */ "+dataMapInstanceName+".put(key, value);");
+ } else {
+ unit.emitln(" // final "+DataClassName+" old = "+dataInstanceName+";");
+ unit.emitln(" "+dataInstanceName+" = value;");
+ }
+ unit.emitln(" }");
+ unit.emitln();
+ if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) {
+ emitJavaDataClass(unit);
+ cfg.emittedJavaCallbackUserParamClasses.add(fqUsrParamClassName);
+ }
+ if( useDataMap ) {
+ unit.emitln(" private static final Map<"+KeyClassName+", "+DataClassName+"> "+dataMapInstanceName+" = new HashMap<"+KeyClassName+", "+DataClassName+">();");
+ } else {
+ unit.emitln(" private static "+DataClassName+" "+dataInstanceName+" = null;");
+ }
+ unit.emitln(" private static long "+jcbNextIDVarName+" = 1;");
+ unit.emitln(" private static final Object "+lockInstanceName+" = new Object();");
+ unit.emitln();
+ emitJavaStaticCallback(unit);
+ }
+ }
+
+ private final void emitJavaBriefAPIDoc(final CodeUnit unit, final String actionText, final String relationToKey, final String noKeyText, final String relationToFunc) {
+ unit.emit(" /** "+actionText);
+ if( info.setFuncKeyIndices.size() > 0 ) {
+ unit.emit(relationToKey);
+ unit.emit("Key { "+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" } ");
+ } else {
+ unit.emit(noKeyText);
+ }
+ unit.emit(relationToFunc);
+ unit.emitln("<br> <code>"+setFuncSignature+"</code> */");
+ }
+
+ private final void emitJavaKeyClass(final CodeUnit unit) {
+ emitJavaBriefAPIDoc(unit, "", "", "", "for ");
+ unit.emitln(" public static class "+KeyClassName+" {");
+ binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && info.setFuncKeyIndices.contains(idx) ) {
+ unit.emitln(" public final "+jType+" "+name+";");
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(" public "+KeyClassName+"("+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, false).toString()+") {");
+ binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && info.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() && info.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 == info.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() && info.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("HashUtil.getAddrHash32_EqualDist( "+name+" );");
+ } else {
+ unit.emitln(name+";");
+ }
+ } else {
+ if( idx == info.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(" }");
+ }
+
+ private final void emitJavaDataClass(final CodeUnit unit) {
+ unit.emitln(" private static class "+DataClassName+" {");
+ unit.emitln(" // userParamArgCType "+setFuncUserParamCType);
+ unit.emitln(" // userParamArgJType "+setFuncUserParamJType);
+ unit.emitln(" final "+info.cbFuncTypeName+" func;");
+ unit.emitln(" final "+setFuncUserParamTypeName+" param;");
+ unit.emitln(" "+DataClassName+"("+info.cbFuncTypeName+" func, "+setFuncUserParamTypeName+" param) {");
+ unit.emitln(" this.func = func;");
+ unit.emitln(" this.param = param;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ }
+
+ public final String getJavaStaticCallbackSignature() {
+ final StringBuilder buf = new StringBuilder();
+ buf.append("(");
+ info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() ) {
+ if( idx == info.cbFuncUserParamIdx ) {
+ buf.append("J");
+ } else {
+ buf.append(jType.getDescriptor());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ buf.append(")");
+ buf.append(cbFuncJavaReturnType.getDescriptor());
+ return buf.toString();
+ }
+
+ public final int appendJavaAdditionalJNIParameter(final StringBuilder buf) {
+ buf.append("Class<?> clazz, String callbackSignature, long nativeUserParam");
+ return 3;
+ }
+ public final int appendJavaAdditionalJNIArguments(final StringBuilder buf) {
+ buf.append("this.getClass(), \"" + getJavaStaticCallbackSignature()+ "\", nativeUserParam");
+ return 3;
+ }
+ private final void emitJavaStaticCallback(final CodeUnit unit) {
+ unit.emitln(" /** Static callback invocation, dispatching to "+info.cbSimpleClazzName+" for callback <br> <code>"+
+ info.cbFuncType.toString(info.cbFuncTypeName, false, true)+"</code> */");
+ unit.emit (" /* pp */ static "+cbFuncJavaReturnType.getName()+" invoke"+capIfaceName+"(");
+ final boolean[] mapNativePtrToCompound = { false };
+ final JavaType[] origUserParamJType = { null };
+ info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() ) {
+ if( 0 < consumedCount ) { unit.emit(", "); }
+ if( idx == info.cbFuncUserParamIdx ) {
+ unit.emit("long nativeUserParamPtr");
+ if( jType.isCompoundTypeWrapper() ) {
+ mapNativePtrToCompound[0] = true;
+ origUserParamJType[0] = jType;
+ }
+ } else {
+ unit.emit(jType+" "+name);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(") {");
+ if( mapNativePtrToCompound[0] ) {
+ unit.emitln(" final "+origUserParamJType[0]+" "+info.cbFuncUserParamName+" = "+origUserParamJType[0]+".derefPointer(nativeUserParamPtr);");
+ }
+ if( useDataMap ) {
+ unit.emitln(" final "+DataClassName+" value;");
+ } else {
+ unit.emitln(" final "+DataClassName+" value;");
+ }
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ if( useDataMap ) {
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" value = "+dataMapInstanceName+".get(key);");
+ } else {
+ unit.emitln(" value = "+dataInstanceName+";");
+ }
+ unit.emitln(" }");
+ unit.emitln(" if( null == value ) {");
+ if( !cbFuncJavaReturnType.isVoid() ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return;");
+ }
+ unit.emitln(" }");
+ if( !cbFuncJavaReturnType.isVoid() ) {
+ unit.emit(" return ");
+ } else {
+ unit.emit(" ");
+ }
+ unit.emit("value.func.callback(");
+ info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() ) {
+ if( 0 < consumedCount ) { unit.emit(", "); }
+ if( idx == info.cbFuncUserParamIdx && !mapNativePtrToCompound[0] ) {
+ unit.emit("value.param");
+ } else {
+ unit.emit(name);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(");");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+
+ //
+ // C JNI Code ..
+ //
+
+ public int appendCAdditionalParameter(final StringBuilder buf) {
+ buf.append(", jclass clazz, jstring jcallbackSignature, jlong jnativeUserParam");
+ return 3;
+ }
+
+ public void emitCOptArgumentSuffix(final CodeUnit unit, final int argIdx) {
+ if( ( argIdx == info.setFuncCBParamIdx || argIdx == info.setFuncUserParamIdx ) ) {
+ unit.emit("_native");
+ }
+ }
+
+ public void appendCAdditionalJNIDescriptor(final StringBuilder buf) {
+ JavaType.appendJNIDescriptor(buf, Class.class, false); // to account for the additional 'jclass clazz' parameter
+ JavaType.appendJNIDescriptor(buf, String.class, false); // to account for the additional 'jstring jcallbackSignature' parameter
+ JavaType.appendJNIDescriptor(buf, long.class, false); // to account for the additional 'long nativeUserParam' parameter
+ }
+
+ public void emitCSetFuncPreCall(final CodeUnit unit) {
+ final String jcbNativeBasename = CodeGenUtils.capitalizeString( info.setFuncName );
+ final String jcbFriendlyBasename = info.setFuncName+"("+info.cbSimpleClazzName+")";
+ final String staticBindingMethodName = "invoke"+jcbNativeBasename;
+ final String staticBindingClazzVarName = "clazz"+jcbNativeBasename;
+ final String staticBindingMethodIDVarName = "method"+jcbNativeBasename;
+ final String cbFuncArgName = binding.getArgumentName(info.setFuncCBParamIdx);
+ final String userParamTypeName = info.cbFuncUserParamType.getCName();
+ final String userParamArgName = binding.getArgumentName(info.setFuncUserParamIdx);
+ final String nativeCBFuncVarName = cbFuncArgName+"_native";
+ final String nativeUserParamVarName = userParamArgName+"_native";
+ unit.emitln();
+ unit.emitln(" // JavaCallback handling");
+ unit.emitln(" if( NULL == clazz ) { (*env)->FatalError(env, \"NULL clazz passed to '"+jcbFriendlyBasename+"'\"); }");
+ unit.emitln(" "+info.cbFuncTypeName+" "+nativeCBFuncVarName+";");
+ unit.emitln(" "+userParamTypeName+"* "+nativeUserParamVarName+";");
+ unit.emitln(" if( NULL != "+cbFuncArgName+" ) {");
+ unit.emitln(" const char* callbackSignature = (*env)->GetStringUTFChars(env, jcallbackSignature, (jboolean*)NULL);");
+ unit.emitln(" if( NULL == callbackSignature ) { (*env)->FatalError(env, \"Failed callbackSignature in '"+jcbFriendlyBasename+"'\"); }");
+ unit.emitln(" jmethodID cbMethodID = (*env)->GetStaticMethodID(env, clazz, \""+staticBindingMethodName+"\", callbackSignature);");
+ unit.emitln(" if( NULL == cbMethodID ) {");
+ unit.emitln(" char cmsg[400];");
+ unit.emitln(" snprintf(cmsg, 400, \"Failed GetStaticMethodID of '"+staticBindingMethodName+"(%s)' in '"+jcbFriendlyBasename+"'\", callbackSignature);");
+ unit.emitln(" (*env)->FatalError(env, cmsg);");
+ unit.emitln(" }");
+ unit.emitln(" (*env)->ReleaseStringUTFChars(env, jcallbackSignature, callbackSignature);");
+ unit.emitln(" "+staticBindingClazzVarName+" = clazz;");
+ unit.emitln(" "+staticBindingMethodIDVarName+" = cbMethodID;");
+ unit.emitln(" "+nativeCBFuncVarName+" = func"+jcbNativeBasename+";");
+ unit.emitln(" "+nativeUserParamVarName+" = ("+userParamTypeName+"*) jnativeUserParam;");
+ unit.emitln(" } else {");
+ unit.emitln(" "+nativeCBFuncVarName+" = NULL;");
+ unit.emitln(" "+nativeUserParamVarName+" = NULL;");
+ unit.emitln(" }");
+ unit.emitln();
+
+ }
+
+ public void emitCAdditionalCode(final CodeUnit unit, final CMethodBindingEmitter jcbCMethodEmitter) {
+ final String jcbNativeBasename = CodeGenUtils.capitalizeString( info.setFuncName );
+ final String jcbFriendlyBasename = info.setFuncName+"("+info.cbSimpleClazzName+")";
+ final String staticBindingClazzVarName = "clazz"+jcbNativeBasename;
+ final String staticBindingMethodIDVarName = "method"+jcbNativeBasename;
+ final String staticCallbackName = "func"+jcbNativeBasename;
+ // final Type userParamType = javaCallback.cbFuncBinding.getCArgumentType(javaCallback.cbFuncUserParamIdx);
+ final String userParamTypeName = info.cbFuncUserParamType.getCName();
+ final String userParamArgName = info.cbFuncBinding.getArgumentName(info.cbFuncUserParamIdx);
+ final Type cReturnType = info.cbFuncBinding.getCReturnType();
+ final JavaType jretType = info.cbFuncBinding.getJavaReturnType();
+ unit.emitln();
+ unit.emitln("static jclass "+staticBindingClazzVarName+" = NULL;");
+ unit.emitln("static jmethodID "+staticBindingMethodIDVarName+" = NULL;");
+ unit.emitln();
+ // javaCallback.cbFuncCEmitter.emitSignature();
+ unit.emit("static "+cReturnType.getCName()+" "+staticCallbackName+"(");
+ // javaCallback.cbFuncCEmitter.emitArguments();
+ unit.emit(info.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
+ unit.emitln(") {");
+ // javaCallback.cbFuncCEmitter.emitBody();
+ {
+ unit.emitln(" JNIEnv* env = JVMUtil_GetJNIEnv();");
+ unit.emitln(" jclass cbClazz = "+staticBindingClazzVarName+";");
+ unit.emitln(" jmethodID cbMethod = "+staticBindingMethodIDVarName+";");
+ unit.emitln(" if( NULL == env || NULL == cbClazz || NULL == cbMethod ) {");
+ if( !cReturnType.isVoid() ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return;");
+ }
+ unit.emitln(" }");
+ // javaCallback.cbFuncCEmitter.emitBodyVariableDeclarations();
+ // javaCallback.cbFuncCEmitter.emitBodyUserVariableDeclarations();
+ // javaCallback.cbFuncCEmitter.emitBodyVariablePreCallSetup();
+ emitJavaCallbackBodyCToJavaPreCall(jcbCMethodEmitter);
+
+ // javaCallback.cbFuncCEmitter.emitBodyCallCFunction();
+ unit.emitln(" "+userParamTypeName+"* "+userParamArgName+"_jni = ("+userParamTypeName+"*) "+userParamArgName+";");
+ unit.emitln(" // C Params: "+info.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
+ unit.emitln(" // J Params: "+info.cbFuncBinding.getJavaParameterList(new StringBuilder()).toString());
+
+ final String returnStatement;
+ if( !cReturnType.isVoid() ) {
+ unit.emit(" "+cReturnType.getCName()+" _res = 0;");
+ returnStatement = "return _res;";
+ } else {
+ returnStatement = "return;";
+ }
+ if( !cReturnType.isVoid() ) {
+ unit.emit(" _res = ("+cReturnType.getCName()+") ");
+ } else {
+ unit.emit(" ");
+ }
+ unit.emit("(*env)->CallStatic" + CodeGenUtils.capitalizeString( jretType.getName() ) +"Method(env, cbClazz, cbMethod, ");
+ // javaCallback.cbFuncCEmitter.emitBodyPassCArguments();
+ emitJavaCallbackBodyPassJavaArguments(unit, jcbCMethodEmitter.binding, null); //"NULL");
+ unit.emitln(");");
+ unit.emitln(" if( (*env)->ExceptionCheck(env) ) {");
+ unit.emitln(" fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': Exception in Java Callback caught:\\n\");");
+ unit.emitln(" (*env)->ExceptionDescribe(env);");
+ unit.emitln(" (*env)->ExceptionClear(env);");
+ unit.emitln(" }");
+
+ // javaCallback.cbFuncCEmitter.emitBodyUserVariableAssignments();
+ // javaCallback.cbFuncCEmitter.emitBodyVariablePostCallCleanup();
+ // javaCallback.cbFuncCEmitter.emitBodyMapCToJNIType(-1 /* return value */, true /* addLocalVar */)
+
+ unit.emitln(" "+returnStatement);
+ }
+ unit.emitln("}");
+ unit.emitln();
+ }
+
+ /* pp */ int emitJavaCallbackBodyCToJavaPreCall(final CMethodBindingEmitter ce) {
+ int count = 0;
+ for (int i = 0; i < ce.binding.getNumArguments(); i++) {
+ if( i == info.cbFuncUserParamIdx ) {
+ continue;
+ }
+ if( ce.emitBodyMapCToJNIType(i, true /* addLocalVar */) ) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ /* pp */ int emitJavaCallbackBodyPassJavaArguments(final CodeUnit unit, final MethodBinding binding, final String userParamVarName) {
+ int count = 0;
+ boolean needsComma = false;
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if (needsComma) {
+ unit.emit(", ");
+ needsComma = false;
+ }
+ if( i == info.cbFuncUserParamIdx && null != userParamVarName ) {
+ unit.emit( userParamVarName );
+ } else {
+ unit.emit( binding.getArgumentName(i) + "_jni" );
+ }
+ needsComma = true;
+ ++count;
+ }
+ return count;
+ }
+
+
+}
diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java
index 3e2e680..10f43a7 100644
--- a/src/java/com/jogamp/gluegen/JavaConfiguration.java
+++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java
@@ -156,17 +156,19 @@ public class JavaConfiguration {
final int cbFuncUserParamIdx;
final String setFuncName;
final List<Integer> setFuncKeyIndices = new ArrayList<Integer>();
+ final int setFuncUserParamIdx; // optional
final String setFuncKeyClassName; // optional
- JavaCallbackDef(final String cbFuncTypeName, final int cbFuncUserParamIdx, final String setFuncName, final String setFuncKeyClassName) {
+ JavaCallbackDef(final String cbFuncTypeName, final int cbFuncUserParamIdx, final String setFuncName, final int setFuncUserParamIdx, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
this.cbFuncUserParamIdx = cbFuncUserParamIdx;
this.setFuncName = setFuncName;
+ this.setFuncUserParamIdx = setFuncUserParamIdx;
this.setFuncKeyClassName = setFuncKeyClassName;
}
@Override
public String toString() {
- return String.format("JavaCallbackDef[cbFunc[type %s, userParamIdx %d], set[%s, keys %s, KeyClass %s]]",
- cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncKeyIndices.toString(), setFuncKeyClassName);
+ return String.format("JavaCallbackDef[cbFunc[type %s, userParamIdx %d], set[%s, keys %s, userParamIdx %d, KeyClass %s]]",
+ cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncKeyIndices.toString(), setFuncUserParamIdx, setFuncKeyClassName);
}
}
private final List<JavaCallbackDef> javaCallbackList = new ArrayList<JavaCallbackDef>();
@@ -1630,7 +1632,25 @@ public class JavaConfiguration {
protected void readJavaCallbackDef(final StringTokenizer tok, final String filename, final int lineNo) {
try {
final String setFuncName = tok.nextToken();
- final String cbFuncTypeName = tok.nextToken();
+ final int setFuncUserParamIdx;
+ final String cbFuncTypeName;
+ {
+ final String stok = tok.nextToken();
+ int ival = -1;
+ String sval = null;
+ try {
+ ival = Integer.valueOf(stok);
+ } catch(final NumberFormatException nfe) {
+ sval = stok;
+ }
+ if( null == sval ) {
+ setFuncUserParamIdx = ival;
+ cbFuncTypeName = tok.nextToken();
+ } else {
+ setFuncUserParamIdx = -1;
+ cbFuncTypeName = sval;
+ }
+ }
final Integer cbFuncUserParamIdx = Integer.valueOf(tok.nextToken());
final String cbFuncKeyClassName;
if( tok.hasMoreTokens() ) {
@@ -1638,7 +1658,7 @@ public class JavaConfiguration {
} else {
cbFuncKeyClassName = null;
}
- final JavaCallbackDef jcd = new JavaCallbackDef(cbFuncTypeName, cbFuncUserParamIdx, setFuncName, cbFuncKeyClassName);
+ final JavaCallbackDef jcd = new JavaCallbackDef(cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncUserParamIdx, cbFuncKeyClassName);
javaCallbackList.add(jcd);
javaCallbackSetFuncToDef.put(setFuncName, jcd);
} catch (final NoSuchElementException e) {
@@ -2279,13 +2299,12 @@ public class JavaConfiguration {
final String cbFuncTypeName;
final String cbSimpleClazzName;
final String cbFQClazzName;
- final String cbMethodSignature;
+ final String staticCBMethodSignature;
final FunctionType cbFuncType;
final MethodBinding cbFuncBinding;
final int cbFuncUserParamIdx;
-
- final Type userParamType;
- final String userParamName;
+ final String cbFuncUserParamName;
+ final Type cbFuncUserParamType;
final String setFuncName;
final List<Integer> setFuncKeyIndices;
@@ -2295,38 +2314,38 @@ public class JavaConfiguration {
int setFuncUserParamIdx;
boolean keyClassEmitted;
- public JavaCallbackInfo(final String cbFuncTypeName, final String cbSimpleClazzName, final String cbFQClazzName, final String cbMethodSignature,
+ public JavaCallbackInfo(final String cbFuncTypeName, final String cbSimpleClazzName, final String cbFQClazzName, final String staticCBMethodSignature,
final FunctionType cbFuncType, final MethodBinding cbFuncBinding, final int cbFuncUserParamIdx,
- final String setFuncName, final List<Integer> setFuncKeyIndices, final String setFuncKeyClassName) {
+ final String setFuncName, final int setFuncUserParamIdx, final List<Integer> setFuncKeyIndices, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
this.cbSimpleClazzName = cbSimpleClazzName;
this.cbFQClazzName = cbFQClazzName;
- this.cbMethodSignature = cbMethodSignature;
+ this.staticCBMethodSignature = staticCBMethodSignature;
this.cbFuncType = cbFuncType;
this.cbFuncBinding = cbFuncBinding;
- int paramIdx = -2;
- Type paramType = null;
- String paramName = null;
- if( 0 <= cbFuncUserParamIdx && cbFuncUserParamIdx < cbFuncType.getNumArguments() ) {
- final Type t = cbFuncType.getArgumentType(cbFuncUserParamIdx);
- if( null != t && t.isPointer() ) {
- // OK '<something>*'
- paramIdx = cbFuncUserParamIdx;
- paramName = cbFuncType.getArgumentName(cbFuncUserParamIdx);
- paramType = t.getTargetType();
+ {
+ int paramIdx = -2;
+ Type paramType = null;
+ String paramName = null;
+ if( 0 <= cbFuncUserParamIdx && cbFuncUserParamIdx < cbFuncType.getNumArguments() ) {
+ final Type t = cbFuncType.getArgumentType(cbFuncUserParamIdx);
+ if( null != t && t.isPointer() ) {
+ // OK '<something>*'
+ paramIdx = cbFuncUserParamIdx;
+ paramName = cbFuncType.getArgumentName(cbFuncUserParamIdx);
+ paramType = t.getTargetType();
+ }
}
+ this.cbFuncUserParamIdx = paramIdx;
+ this.cbFuncUserParamName = paramName;
+ this.cbFuncUserParamType = paramType;
}
- 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;
+ this.setFuncUserParamIdx = setFuncUserParamIdx;
this.keyClassEmitted = false;
}
@@ -2335,7 +2354,13 @@ public class JavaConfiguration {
if( 0 <= cbParamIdx && 0 <= userParamIdx ) {
setFuncProcessed = true;
setFuncCBParamIdx = cbParamIdx;
- setFuncUserParamIdx = userParamIdx;
+ if( 0 <= setFuncUserParamIdx ) {
+ if( setFuncUserParamIdx != userParamIdx ) {
+ throw new IllegalArgumentException("Mismatch pre-set setFuncUserParamIdx "+setFuncUserParamIdx+", given "+userParamIdx+": "+toString());
+ }
+ } else {
+ setFuncUserParamIdx = userParamIdx;
+ }
} else {
setFuncCBParamIdx = -1;
setFuncUserParamIdx = -1;
@@ -2346,8 +2371,8 @@ public class JavaConfiguration {
@Override
public String toString() {
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,
- cbFuncUserParamIdx, userParamName, userParamType.getSignature(null).toString(),
+ cbFuncTypeName, staticCBMethodSignature,
+ cbFuncUserParamIdx, cbFuncUserParamName, cbFuncUserParamType.getSignature(null).toString(),
setFuncName, setFuncProcessed, setFuncCBParamIdx, setFuncUserParamIdx,
setFuncKeyIndices.toString(), setFuncKeyClassName,
cbFuncType.toString(cbFuncTypeName, false, true));
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index 2ea8d30..4a81a01 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -1471,9 +1471,9 @@ public class JavaEmitter implements GlueEmitter {
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,
+ final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, jcbi0.staticCBMethodSignature,
funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx,
- jcbd.setFuncName, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
+ jcbd.setFuncName, jcbd.setFuncUserParamIdx, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
LOG.log(INFO, "JavaCallbackInfo: Reusing {0} -> {1}", jcbd.setFuncName, jcbi0);
} else {
@@ -1493,7 +1493,7 @@ public class JavaEmitter implements GlueEmitter {
}
final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, cbMethodSignature.toString(),
funcType, cbFuncBinding, jcbd.cbFuncUserParamIdx,
- jcbd.setFuncName, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
+ jcbd.setFuncName, jcbd.setFuncUserParamIdx, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
javaCallbackInterfaceMap.put(cbFQClazzName, jcbi1);
LOG.log(INFO, "JavaCallbackInfo: Added {0} -> {1}", jcbd.setFuncName, jcbi1);
@@ -3019,9 +3019,6 @@ public class JavaEmitter implements GlueEmitter {
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());
- if( cfg.getJavaCallbackList().size() > 0 ) {
- cUnit().emitJavaCallbackGlueDataDecl();
- }
}
} catch (final Exception e) {
throw new RuntimeException(
@@ -3114,13 +3111,29 @@ public class JavaEmitter implements GlueEmitter {
// Replace JavaCallback type with generated interface name
jcbiSetFuncCBParamIdx=i;
mappedType = JavaType.createForNamedClass( jcbi.cbFQClazzName );
- } else if( null != jcbi && jcbi.userParamName.equals( cArgName ) &&
+ } else if( null != jcbi && i == jcbi.setFuncUserParamIdx && cArgType.isPointer() ) {
+ // Replace userParam argument '<userParamType>*' if 'void*' with Object
+ jcbiSetFuncUserParamIdx=i;
+ if( cArgType.getTargetType().isVoid() ) {
+ if( jcbi.cbFuncUserParamType.isCompound() ) {
+ mappedType = JavaType.createForClass(long.class);
+ } else {
+ mappedType = JavaType.forObjectClass();
+ }
+ }
+ } else if( null != jcbi && jcbi.cbFuncUserParamName.equals( cArgName ) &&
( !jcbi.setFuncProcessed || i == jcbi.setFuncUserParamIdx ) &&
- cArgType.isPointer() && jcbi.userParamType.equals( cArgType.getTargetType() ) )
+ cArgType.isPointer() && jcbi.cbFuncUserParamType.equals( cArgType.getTargetType() ) )
{
- // Replace optional userParam argument '<userParamType>*' with Object
+ // Replace userParam argument '<userParamType>*' if 'void*' with Object
jcbiSetFuncUserParamIdx=i;
- mappedType = JavaType.forObjectClass();
+ if( cArgType.getTargetType().isVoid() ) {
+ if( jcbi.cbFuncUserParamType.isCompound() ) {
+ mappedType = JavaType.createForClass(long.class);
+ } else {
+ 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 ");
@@ -3153,7 +3166,8 @@ public class JavaEmitter implements GlueEmitter {
}
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);
+ LOG.log(INFO, "BindFunc.JavaCallback: {0}: set[cbParamIdx {1}, userParamIdx {2}], {3}, {4}",
+ sym.getName(), jcbiSetFuncCBParamIdx, jcbiSetFuncUserParamIdx, sym.getType().toString(sym.getName(), false, true), jcbi);
}
final MethodBinding mb = new MethodBinding(sym, delegationImplName,
javaReturnType, javaArgumentTypes,
diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
index 6a93973..fe4f82a 100644
--- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
@@ -95,7 +95,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
private String returnedArrayLengthExpression;
private boolean returnedArrayLengthExpressionOnlyForComments = false;
- private final JavaCallbackInfo javaCallback;
+ private final JavaCallbackEmitter javaCallbackEmitter;
// A suffix used to create a temporary outgoing array of Buffers to
// represent an array of compound type wrappers
@@ -134,7 +134,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
} else {
setCommentEmitter(defaultInterfaceCommentEmitter);
}
- javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ final JavaCallbackInfo javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ if( null != javaCallback ) {
+ javaCallbackEmitter = new JavaCallbackEmitter(cfg, binding, javaCallback, appendSignature(new StringBuilder()).toString());
+ } else {
+ javaCallbackEmitter = null;
+ }
// !forImplementingMethodCall && !isInterface
}
@@ -156,7 +161,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
epilogue = arg.epilogue;
returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments;
- javaCallback = arg.javaCallback;
+ javaCallbackEmitter = arg.javaCallbackEmitter;
}
public boolean isNativeMethod() { return isNativeMethod; }
@@ -262,8 +267,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
@Override
- protected void emitReturnType() {
- unit.emit(getReturnTypeString(false));
+ protected StringBuilder appendReturnType(final StringBuilder buf) {
+ return buf.append(getReturnTypeString(false));
}
protected String erasedTypeString(final JavaType type, final boolean skipBuffers) {
@@ -335,33 +340,34 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
@Override
- protected void emitName() {
+ protected StringBuilder appendName(final StringBuilder buf) {
if (isPrivateNativeMethod) {
- unit.emit(getNativeImplMethodName());
+ buf.append(getNativeImplMethodName());
} else if( isInterface()) {
- unit.emit(getInterfaceName());
+ buf.append(getInterfaceName());
} else {
- unit.emit(getImplName());
+ buf.append(getImplName());
}
+ return buf;
}
@Override
- protected int emitArguments() {
+ protected int appendArguments(final StringBuilder buf) {
boolean needComma = false;
int numEmitted = 0;
if( hasModifier(JavaMethodBindingEmitter.NATIVE) && binding.isReturnCompoundByValue() ) {
- unit.emit("final Class<?> _clazzBuffers");
+ buf.append("final Class<?> _clazzBuffers");
++numEmitted;
needComma = true;
}
if (isPrivateNativeMethod && binding.hasContainingType()) {
// Always emit outgoing "this" argument
if (needComma) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit("ByteBuffer ");
- unit.emit(javaThisArgumentName());
+ buf.append("ByteBuffer ");
+ buf.append(javaThisArgumentName());
++numEmitted;
needComma = true;
}
@@ -385,12 +391,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
if (needComma) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit(erasedTypeString(type, false));
- unit.emit(" ");
- unit.emit(getArgumentName(i));
+ buf.append(erasedTypeString(type, false));
+ buf.append(" ");
+ buf.append(getArgumentName(i));
++numEmitted;
needComma = true;
@@ -398,12 +404,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
// Add Buffer and array index offset arguments after each associated argument
if (forDirectBufferImplementation || forIndirectBufferAndArrayImplementation) {
if (type.isNIOBuffer()) {
- unit.emit(", int " + byteOffsetArgName(i));
+ buf.append(", int " + byteOffsetArgName(i));
if(!useNIODirectOnly) {
- unit.emit(", boolean " + isNIOArgName(i));
+ buf.append(", boolean " + isNIOArgName(i));
}
} else if (type.isNIOBufferArray()) {
- unit.emit(", int[] " + byteOffsetArrayArgName(i));
+ buf.append(", int[] " + byteOffsetArrayArgName(i));
}
}
@@ -412,17 +418,16 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
if(useNIOOnly) {
throw new RuntimeException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array");
}
- unit.emit(", int " + offsetArgName(i));
+ buf.append(", int " + offsetArgName(i));
}
}
if( hasModifier(JavaMethodBindingEmitter.NATIVE) &&
- null != javaCallback )
+ null != javaCallbackEmitter )
{
if (needComma) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit("String callbackSignature, Object lockObj, long[/*1*/] nativeUserParam");
- ++numEmitted;
+ numEmitted += javaCallbackEmitter.appendJavaAdditionalJNIParameter(buf);
}
return numEmitted;
}
@@ -455,125 +460,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
return getArgumentName(i) + "_offset";
}
- private static final boolean DEBUG_JAVACALLBACK = false;
-
- private final void emitJavaCallbackBirefAPIDoc(final String actionText, final String relationToKey, final String noKeyText, final String relationToFunc) {
- unit.emit(" /** "+actionText);
- if( javaCallback.setFuncKeyIndices.size() > 0 ) {
- unit.emit(relationToKey);
- unit.emit("Key { "+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+" } ");
- } else {
- unit.emit(noKeyText);
- }
- unit.emit(relationToFunc);
- unit.emit("<br> <code>");
- emitSignature();
- unit.emitln("</code> **/");
- }
- private final void emitJavaCallbackKeyClass(final String capIfaceName, final String keyClassName) {
- emitJavaCallbackBirefAPIDoc("", "", "", "for ");
- unit.emitln(" public 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(" public final "+jType+" "+name+";");
- return true;
- } else {
- return false;
- }
- } );
- unit.emitln(" public "+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("HashUtil.getAddrHash32_EqualDist( "+name+" );");
- } 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(" }");
- }
- private final void emitJavaCallbackDataClass(final String capIfaceName, final String dataClassName) {
- unit.emitln(" private static class "+dataClassName+" {");
- unit.emitln(" final "+javaCallback.cbFuncTypeName+" func;");
- unit.emitln(" final Object param;");
- unit.emitln(" final long nativeParam;");
- unit.emitln(" "+dataClassName+"("+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 emitAdditionalCode() {
+ if( null != javaCallbackEmitter && !isPrivateNativeMethod ) {
+ javaCallbackEmitter.emitJavaAdditionalCode(unit, isInterface());
+ }
}
@Override
@@ -594,201 +485,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
unit.emitln(" }");
}
- if( null != javaCallback && !isPrivateNativeMethod ) {
- final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
- final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
- final String lockInstanceName = lowIfaceName+"Lock";
- final String dataMapInstanceName = lowIfaceName+"DataMap";
- final String dataInstanceName = lowIfaceName+"Data";
- final boolean customKeyClass;
- final String KeyClassName;
- final boolean useDataMap;
- if( null != javaCallback.setFuncKeyClassName ) {
- customKeyClass = true;;
- KeyClassName = javaCallback.setFuncKeyClassName;
- useDataMap = true;
- } else {
- customKeyClass = false;
- KeyClassName = CodeGenUtils.capitalizeString(capIfaceName+"Key");
- useDataMap = javaCallback.setFuncKeyIndices.size() > 0;
- }
- final String DataClassName = CodeGenUtils.capitalizeString( javaCallback.cbFuncTypeName+"Data" );
- final String fqUsrParamClassName = cfg.packageName()+"."+cfg.className()+"."+DataClassName;
- unit.emitln();
- if( isInterface() ) {
- if( useDataMap ) {
- if( !customKeyClass && !javaCallback.keyClassEmitted ) {
- emitJavaCallbackKeyClass(capIfaceName, KeyClassName);
- unit.emitln();
- javaCallback.keyClassEmitted = true;
- }
- emitJavaCallbackBirefAPIDoc("Returns ", "set of ", "", "for ");
- unit.emitln(" public Set<"+KeyClassName+"> get"+capIfaceName+"Keys();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public boolean is"+capIfaceName+"Mapped("+KeyClassName+" key);");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key);");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public Object get"+capIfaceName+"UserParam("+KeyClassName+" key);");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public int releaseAll"+capIfaceName+"();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public void release"+capIfaceName+"("+KeyClassName+" key);");
- unit.emitln();
- } else {
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public boolean is"+capIfaceName+"Mapped();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public Object get"+capIfaceName+"UserParam();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public void release"+capIfaceName+"();");
- unit.emitln();
- }
- } else {
- if( useDataMap ) {
- if( !customKeyClass && !javaCallback.keyClassEmitted ) {
- emitJavaCallbackKeyClass(capIfaceName, KeyClassName);
- unit.emitln();
- javaCallback.keyClassEmitted = true;
- }
- emitJavaCallbackBirefAPIDoc("Returns ", "set of ", "", "for ");
- unit.emitln(" public final Set<"+KeyClassName+"> get"+capIfaceName+"Keys() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" return "+dataMapInstanceName+".keySet();");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public final boolean is"+capIfaceName+"Mapped("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" return null != "+dataMapInstanceName+".get(key);");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public final "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
- unit.emitln(" return null != value ? value.func : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public final Object get"+capIfaceName+"UserParam("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
- unit.emitln(" return null != value ? value.param : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public final int releaseAll"+capIfaceName+"() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final Set<"+KeyClassName+"> keySet = "+dataMapInstanceName+".keySet();");
- unit.emitln(" final "+KeyClassName+"[] keys = keySet.toArray(new "+KeyClassName+"[keySet.size()]);");
- unit.emitln(" for(int i=0; i<keys.length; ++i) {");
- unit.emitln(" final "+KeyClassName+" key = keys[i];");
- unit.emitln(" release"+capIfaceName+"(key);");
- unit.emitln(" }");
- unit.emitln(" return keys.length;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public final void release"+capIfaceName+"("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".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+"Impl(value.nativeParam);");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln(" }");
- } else {
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public final boolean is"+capIfaceName+"Mapped() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" return null != "+dataInstanceName+";");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public final "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
- unit.emitln(" return null != value ? value.func : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public final Object get"+capIfaceName+"UserParam() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
- unit.emitln(" return null != value ? value.param : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public final void release"+capIfaceName+"() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
- unit.emitln(" "+dataInstanceName+" = null;");
- 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+"Impl(value.nativeParam);");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln(" }");
- }
- unit.emitln(" private native void release"+capIfaceName+"Impl(long nativeUserParam);");
- unit.emitln();
- unit.emitln(" private final void add"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, true).toString()+DataClassName+" value) {");
- if( useDataMap ) {
- unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
- unit.emitln(" final "+DataClassName+" old = "+dataMapInstanceName+".put(key, value);");
- } else {
- unit.emitln(" final "+DataClassName+" old = "+dataInstanceName+";");
- unit.emitln(" "+dataInstanceName+" = value;");
- }
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" System.err.println(\"ZZZ Map \"+key+\" -> value.nativeParam 0x\"+Long.toHexString(null!=value?value.nativeParam:0));");
- }
- unit.emitln(" if( null != old ) {");
- unit.emitln(" release"+capIfaceName+"Impl(old.nativeParam);");
- unit.emitln(" }");
- unit.emitln(" }");
- if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) {
- emitJavaCallbackDataClass(capIfaceName, DataClassName);
- cfg.emittedJavaCallbackUserParamClasses.add(fqUsrParamClassName);
- }
- if( useDataMap ) {
- unit.emitln(" private final Map<"+KeyClassName+", "+DataClassName+"> "+dataMapInstanceName+" = new HashMap<"+KeyClassName+", "+DataClassName+">();");
- } else {
- unit.emitln(" private "+DataClassName+" "+dataInstanceName+" = null;");
- }
- unit.emitln(" private final Object "+lockInstanceName+" = new Object();");
- unit.emitln();
- }
- }
}
protected void emitPrologueOrEpilogue(final List<String> code) {
@@ -901,15 +597,11 @@ 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 lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
- final String lockInstanceName = lowIfaceName+"Lock";
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final long[] nativeUserParam = { 0 };");
- unit.emitln();
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitJavaSetFuncPreCall(unit);
}
if (!returnType.isVoid()) {
unit.emit(" ");
@@ -941,36 +633,9 @@ 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);
- final String DataClassName = CodeGenUtils.capitalizeString( javaCallback.cbFuncTypeName+"Data" );
- final String KeyClassName;
- final boolean useDataMap;
- if( null != javaCallback.setFuncKeyClassName ) {
- KeyClassName = javaCallback.setFuncKeyClassName;
- useDataMap = true;
- } else {
- KeyClassName = CodeGenUtils.capitalizeString(capIfaceName+"Key");
- useDataMap = javaCallback.setFuncKeyIndices.size() > 0;
- }
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" System.err.println(\"ZZZ returned nativeUserParam 0x\"+Long.toHexString(nativeUserParam[0]));");
- }
+ if( null != javaCallbackEmitter ) {
unit.emitln();
- unit.emitln(" if( 0 != nativeUserParam[0] ) {");
- unit.emitln(" // callback registrated -> add will release a previously mapped instance ");
- unit.emitln(" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, true).toString()+
- "new "+DataClassName+"("+funcArgName+", "+userParamArgName+", nativeUserParam[0]));");
- unit.emitln(" } else {");
- unit.emitln(" // callback released (null func) -> release a previously mapped instance ");
- if( useDataMap ) {
- unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+" ) );");
- } else {
- unit.emitln(" release"+capIfaceName+"();");
- }
- unit.emitln(" }");
- unit.emitln(" } // synchronized ");
+ javaCallbackEmitter.emitJavaSetFuncPostCall(unit);
}
emitPostCallCleanup(binding);
@@ -1094,14 +759,13 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
needComma = true;
++numArgsEmitted;
}
- if( null != javaCallback ) {
- final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
- final String lockInstanceName = lowIfaceName+"Lock";
+ if( null != javaCallbackEmitter ) {
if (needComma) {
unit.emit(", ");
}
- unit.emit("\"" + javaCallback.cbMethodSignature + "\", "+lockInstanceName+", nativeUserParam");
- ++numArgsEmitted;
+ final StringBuilder buf = new StringBuilder();
+ numArgsEmitted += javaCallbackEmitter.appendJavaAdditionalJNIArguments(buf);
+ unit.emit(buf.toString());
}
return numArgsEmitted;
}
@@ -1301,12 +965,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
}
- protected class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter {
-
- @Override
- protected void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer) {
- writer.print("Interface to C language function: <br> ");
- }
+ protected class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter {
+ @Override
+ protected void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer) {
+ writer.print("Interface to C language function: <br> ");
}
+ }
}
diff --git a/src/java/com/jogamp/gluegen/JavaType.java b/src/java/com/jogamp/gluegen/JavaType.java
index 682a95a..3d6d839 100644
--- a/src/java/com/jogamp/gluegen/JavaType.java
+++ b/src/java/com/jogamp/gluegen/JavaType.java
@@ -334,6 +334,84 @@ public class JavaType {
}
/**
+ * Appends the descriptor (internal type signature) corresponding to the given Class<?> c.
+ * @param buf the StringBuilder sink
+ * @param c the Class<?> to append the descriptor for
+ * @param useTrueType if true, use the actual Class<?> name for non primitives, otherwise java.lang.Object will be used (flattened)
+ * @return the given StringBuilder sink for chaining
+ */
+ public static StringBuilder appendDescriptor(final StringBuilder buf, final Class<?> c, final boolean useTrueType) {
+ if (c.isPrimitive()) {
+ if (c == Boolean.TYPE) buf.append("Z");
+ else if (c == Byte.TYPE) buf.append("B");
+ else if (c == Character.TYPE) buf.append("C");
+ else if (c == Short.TYPE) buf.append("S");
+ else if (c == Integer.TYPE) buf.append("I");
+ else if (c == Long.TYPE) buf.append("J");
+ else if (c == Float.TYPE) buf.append("F");
+ else if (c == Double.TYPE) buf.append("D");
+ else throw new RuntimeException("Illegal primitive type \"" + c.getName() + "\"");
+ } else {
+ // Arrays and NIO Buffers are always passed down as java.lang.Object.
+ // The only arrays that show up as true arrays in the signature
+ // are the synthetic byte offset arrays created when passing
+ // down arrays of direct Buffers. Compound type wrappers are
+ // passed down as ByteBuffers (no good reason, just to avoid
+ // accidental conflation) so we mangle them differently.
+ if (useTrueType) {
+ if (c.isArray()) {
+ buf.append("[");
+ final Class<?> componentType = c.getComponentType();
+ // Handle arrays of compound type wrappers differently for
+ // convenience of the Java-level glue code generation
+ appendDescriptor(buf, componentType,
+ (componentType == java.nio.ByteBuffer.class));
+ } else {
+ buf.append("L");
+ buf.append(c.getName().replace('.', '/'));
+ buf.append(";");
+ }
+ } else {
+ if (c.isArray()) {
+ buf.append("[");
+ appendDescriptor(buf, c.getComponentType(), false);
+ } else if (c == java.lang.String.class) {
+ buf.append("L");
+ buf.append(c.getName().replace('.', '/'));
+ buf.append(";");
+ } else {
+ buf.append("L");
+ buf.append("java_lang_Object");
+ buf.append(";");
+ }
+ }
+ }
+ return buf;
+ }
+
+ /**
+ * Appends the native (JNI) method-name descriptor corresponding to the given Class<?> c,
+ * i.e. replacing chars {@link #appendDescriptor(StringBuilder, Class, boolean)} as follows
+ * <ul>
+ * <li>`_` -> `_1`</li>
+ * <li>`/` -> `_`</li>
+ * <li>`;` -> `_2`</li>
+ * <li>`[` -> `_3`</li>
+ * </ul>
+ * Only the newly appended segment to the StringBuilder sink will be converted to (JNI) method-name using {@link #toJNIMethodDescriptor(StringBuilder, int)}.
+ * @param buf the StringBuilder sink
+ * @param c the Class<?> to append the descriptor for
+ * @param useTrueType if true, use the actual Class<?> name for non primitives, otherwise java.lang.Object will be used (flattened)
+ * @return the given StringBuilder sink for chaining
+ * @see JNI Spec 2, Chapter 2, Resolving Native Method Names
+ * @see #toJNIMethodDescriptor(StringBuilder)
+ */
+ public static StringBuilder appendJNIDescriptor(final StringBuilder res, final Class<?> c, final boolean useTrueType) {
+ final int start = res.length();
+ return toJNIMethodDescriptor( appendDescriptor(res, c, useTrueType), start );
+ }
+
+ /**
* Converts the assumed descriptor (internal type signature) to a native (JNI) method-name descriptor,
* i.e. replacing chars {@link #getDescriptor()} as follows
* <ul>
@@ -342,6 +420,7 @@ public class JavaType {
* <li>`;` -> `_2`</li>
* <li>`[` -> `_3`</li>
* </ul>
+ * @param descriptor the char sequence holding the original descriptor
* @see JNI Spec 2, Chapter 2, Resolving Native Method Names
*/
public static String toJNIMethodDescriptor(final String descriptor) {
@@ -351,6 +430,36 @@ public class JavaType {
.replace("[", "_3");
}
+ /**
+ * Converts the assumed descriptor (internal type signature) to a native (JNI) method-name descriptor,
+ * i.e. replacing chars {@link #getDescriptor()} as follows
+ * <ul>
+ * <li>`_` -> `_1`</li>
+ * <li>`/` -> `_`</li>
+ * <li>`;` -> `_2`</li>
+ * <li>`[` -> `_3`</li>
+ * </ul>
+ * @param descriptor the char buffer holding the original descriptor
+ * @param start start position of the segment to convert, use 0 if whole buffr shall be converted
+ * @return returns passed descriptor buffer for chaining
+ * @see JNI Spec 2, Chapter 2, Resolving Native Method Names
+ */
+ public static StringBuilder toJNIMethodDescriptor(final StringBuilder descriptor, final int start) {
+ replace(descriptor, start, "_", "_1");
+ replace(descriptor, start, "/", "_");
+ replace(descriptor, start, ";", "_2");
+ replace(descriptor, start, "[", "_3");
+ return descriptor;
+ }
+ private static StringBuilder replace(final StringBuilder buf, int start, final String target, final String replacement) {
+ start = buf.indexOf(target, start);
+ while( 0 <= start ) {
+ buf.replace(start, start + target.length(), replacement);
+ start = buf.indexOf(target, start + replacement.length());
+ }
+ return buf;
+ }
+
/** Returns the String corresponding to the JNI type for this type,
or NULL if it can't be represented (i.e., it's a boxing class
that we need to call getBuffer() on.) */
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
index a280d6e..c20b07a 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
@@ -102,17 +102,16 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
}
@Override
- protected int emitArguments() {
- int numEmitted = super.emitArguments();
+ protected int appendArguments(final StringBuilder buf) {
+ int numEmitted = super.appendArguments(buf);
if (callThroughProcAddress) {
if (numEmitted > 0) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit(procAddressJavaTypeName);
- unit.emit(" procAddress");
+ buf.append(procAddressJavaTypeName);
+ buf.append(" procAddress");
++numEmitted;
}
-
return numEmitted;
}
@@ -224,7 +223,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
protected String jniMangle(final MethodBinding binding) {
final StringBuilder buf = new StringBuilder(super.jniMangle(binding));
if (callThroughProcAddress && 0 <= buf.indexOf("__") ) {
- getJNIMangledArg(Long.TYPE, buf, false); // to account for the additional _addr_ parameter
+ JavaType.appendJNIDescriptor(buf, Long.TYPE, false); // to account for the additional _addr_ parameter
}
return buf.toString();
}
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
index 0d5de1c..b6ed21b 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
@@ -91,19 +91,18 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
}
@Override
- protected int emitArguments() {
- int numEmitted = super.emitArguments();
+ protected int appendArguments(final StringBuilder buf) {
+ int numEmitted = super.appendArguments(buf);
if (callThroughProcAddress) {
if (changeNameAndArguments) {
if (numEmitted > 0) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit("long procAddress");
+ buf.append("long procAddress");
++numEmitted;
}
}
-
return numEmitted;
}