aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com/jogamp/gluegen/JavaCallbackEmitter.java')
-rw-r--r--src/java/com/jogamp/gluegen/JavaCallbackEmitter.java666
1 files changed, 666 insertions, 0 deletions
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;
+ }
+
+
+}