diff options
author | Sven Gothel <[email protected]> | 2014-06-17 01:35:28 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-06-17 01:35:28 +0200 |
commit | c3054a01990e55ab35756ea23ab7d7c05f24dd37 (patch) | |
tree | 96bd10e51cafe024a56d7b95594c7364d929c768 /src/java/com/jogamp/gluegen/JavaEmitter.java | |
parent | 9d857ea3575ee263801741a95711d9214c156276 (diff) |
GlueGen: Add support for 'compound call-by-value', i.e. passing and returning struct instance
'compound call-by-value' is not efficient.
However, to allow mapping APIs utilizing passing small structs
as arguments and return values - this feature has been added.
+++
To return the struct value, native code needs to
allocate a NIO ByteBuffer and copy the data.
The stack return value can be dismissed afterwards and the
NIO buffer is returned.
We include this functionality for all generated [impl] classes,
native method:
'static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, void * source_address, jlong capacity)'
(See: 'JavaEmitter.initClassAccessCode')
Since this code requires knowledge of java classes and methods,
for which a reference needs to be acquired, a static initialization method
has been introduced for all generated [impl] classes:
'private static native boolean initializeImpl();'
Per default the this method will be called in the new
static initializer block of the class,
which can be supressed via the configuration element:
'ManualStaticInit <class-name>'
'ManualStaticInit' can be used to issue the 'initializeImpl()'
call in a custom static initializer written by the user.
However, at the time 'initializeImpl()' gets called
the JNI native library must have been loaded, of course!
+++
- See tag: // FIXME: Compound call-by-value
for code changes and validation of completeness
Trigger for compond call-by-value in CMethodBindingEmitter is:
!cArgType.isPointer() && javaArgType.isCompoundTypeWrapper()
Trigger for compond call-by-value in JavaEmitter is:
t.isCompound()
+++
Further more we do tolerate 'javaType.isCPrimitivePointerType()',
i.e. adding comments for offset/size and field entries,
which are all NOP.
This allows to utilize the remaining fields of the native structure.
+++
Tests: Added call-by-value to test1.[ch] binding test!
Diffstat (limited to 'src/java/com/jogamp/gluegen/JavaEmitter.java')
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaEmitter.java | 140 |
1 files changed, 122 insertions, 18 deletions
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index f37f5a3..66e9b24 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -54,7 +54,6 @@ import java.nio.Buffer; import java.util.logging.Logger; import jogamp.common.os.MachineDescriptionRuntime; - import static java.util.logging.Level.*; import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*; @@ -349,6 +348,15 @@ public class JavaEmitter implements GlueEmitter { "\" cannot be assigned to a int, long, float, or double"); } + /** Mangle a class, package or function name for JNI usage, i.e. replace all '.' w/ '_' */ + protected static String jniMangle(String name) { + return name.replaceAll("_", "_1").replace('.', '_'); + } + /** Returns the JNI method prefix consisting our of mangled package- and class-name */ + protected static String getJNIMethodNamePrefix(final String javaPackageName, final String javaClassName) { + return "Java_"+jniMangle(javaPackageName)+"_"+jniMangle(javaClassName); + } + @Override public void emitDefine(ConstantDefinition def, String optionalComment) throws Exception { @@ -855,7 +863,7 @@ public class JavaEmitter implements GlueEmitter { } jniWriter = openFile(nRoot + File.separator + containingTypeName + "_JNI.c", containingTypeName); CodeGenUtils.emitAutogeneratedWarning(jniWriter, this); - emitCHeader(jniWriter, containingTypeName); + emitCHeader(jniWriter, structClassPkg, containingTypeName); } else { jniWriter = null; } @@ -903,7 +911,7 @@ public class JavaEmitter implements GlueEmitter { javaWriter.println(" private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal();"); javaWriter.println(); // generate all offset and size arrays - generateOffsetAndSizeArrays(javaWriter, containingTypeName, structType, null); /* w/o offset */ + generateOffsetAndSizeArrays(javaWriter, " ", containingTypeName, structType, null); /* w/o offset */ for (int i = 0; i < structType.getNumFields(); i++) { final Field field = structType.getField(i); final Type fieldType = field.getType(); @@ -922,14 +930,14 @@ public class JavaEmitter implements GlueEmitter { field + "\" in type \"" + name + "\")"); } - generateOffsetAndSizeArrays(javaWriter, fieldName, fieldType, field); + generateOffsetAndSizeArrays(javaWriter, " ", fieldName, fieldType, field); } else if (fieldType.isArray()) { Type baseElementType = field.getType().asArray().getBaseElementType(); if(!baseElementType.isPrimitive()) break; - generateOffsetAndSizeArrays(javaWriter, fieldName, null, field); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, " ", fieldName, null, field); /* w/o size */ } else { JavaType externalJavaType = null; try { @@ -941,10 +949,13 @@ public class JavaEmitter implements GlueEmitter { } if (externalJavaType.isPrimitive()) { // Primitive type - generateOffsetAndSizeArrays(javaWriter, fieldName, null, field); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, " ", fieldName, null, field); /* w/o size */ + } else if (externalJavaType.isCPrimitivePointerType()) { + // FIXME: Primitive Pointer type + generateOffsetAndSizeArrays(javaWriter, "//", fieldName, fieldType, field); } else { // FIXME - LOG.log(WARNING, "Complicated fields (field \"{0}\" of type \"{1}\") not implemented yet", new Object[]{field, name}); + LOG.log(WARNING, "Complicated fields (field \"{0}\" of type \"{1}\") not implemented yet: "+externalJavaType.getDumpString(), new Object[]{field, name}); // throw new RuntimeException("Complicated fields (field \"" + field + "\" of type \"" + t + // "\") not implemented yet"); } @@ -952,7 +963,10 @@ public class JavaEmitter implements GlueEmitter { } } javaWriter.println(); - + if (needsNativeCode) { + emitJavaInitCode(javaWriter, containingTypeName); + javaWriter.println(); + } javaWriter.println(" public static int size() {"); javaWriter.println(" return "+containingTypeName+"_size[mdIdx];"); javaWriter.println(" }"); @@ -1050,8 +1064,7 @@ public class JavaEmitter implements GlueEmitter { } } else if (fieldType.isCompound()) { // FIXME: will need to support this at least in order to - // handle the union in jawt_Win32DrawingSurfaceInfo (fabricate - // a name?) + // handle the union in jawt_Win32DrawingSurfaceInfo (fabricate a name?) if (fieldType.getName() == null) { throw new RuntimeException("Anonymous structs as fields not supported yet (field \"" + field + "\" in type \"" + name + "\")"); @@ -1139,6 +1152,10 @@ public class JavaEmitter implements GlueEmitter { javaWriter.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); } javaWriter.println(" }"); + } else if (javaType.isCPrimitivePointerType()) { + // FIXME: Primitive Pointer type + javaWriter.println(); + javaWriter.println(" /** "+fieldName +": "+javaType.getDumpString()+" */"); } } } @@ -1191,9 +1208,9 @@ public class JavaEmitter implements GlueEmitter { writer.print(" public " + (abstractMethod ? "abstract " : "") + returnTypeName + " set" + capitalizedFieldName + "(" + paramTypeName + " val)"); } - private void generateOffsetAndSizeArrays(PrintWriter writer, String fieldName, Type fieldType, Field field) { + private void generateOffsetAndSizeArrays(PrintWriter writer, String prefix, String fieldName, Type fieldType, Field field) { if(null != field) { - writer.print(" private static final int[] "+fieldName+"_offset = new int[] { "); + writer.print(prefix+"private static final int[] "+fieldName+"_offset = new int[] { "); for( int i=0; i < machDescTargetConfigs.length; i++ ) { if(0<i) { writer.print(", "); @@ -1204,7 +1221,7 @@ public class JavaEmitter implements GlueEmitter { writer.println(" };"); } if(null!=fieldType) { - writer.print(" private static final int[] "+fieldName+"_size = new int[] { "); + writer.print(prefix+"private static final int[] "+fieldName+"_size = new int[] { "); for( int i=0; i < machDescTargetConfigs.length; i++ ) { if(0<i) { writer.print(", "); @@ -1308,7 +1325,7 @@ public class JavaEmitter implements GlueEmitter { } else if (targetType.isDouble()) { return JavaType.createForCDoublePointer(); } else if (targetType.isCompound()) { - if (t.isArray()) { + if (t.isArray()) { // FIXME: Compound and Compound-Arrays throw new RuntimeException("Arrays of compound types not handled yet"); } // Special cases for known JNI types (in particular for converting jawt.h) @@ -1316,7 +1333,6 @@ public class JavaEmitter implements GlueEmitter { t.getName().equals("jobject")) { return javaType(java.lang.Object.class); } - String name = targetType.getName(); if (name == null) { // Try containing pointer type for any typedefs @@ -1393,6 +1409,12 @@ public class JavaEmitter implements GlueEmitter { t.arrayDimension() + " targetType=\"" + targetType + "\"]"); } + } else if(t.isCompound() ) { // FIXME: Compound and Compound-Arrays + final String name = t.getName(); + if (name == null) { + throw new RuntimeException("Couldn't find a proper type name for pointer type " + t); + } + return JavaType.createForCStruct(cfg.renameJavaType(name)); } else { throw new RuntimeException( "Could not convert C type \"" + t + "\" (class " + @@ -1673,7 +1695,8 @@ public class JavaEmitter implements GlueEmitter { } if (cfg.emitImpl()) { - emitCHeader(cWriter(), cfg.implClassName()); + emitJavaInitCode(); + emitCHeader(cWriter(), getImplPackageName(), cfg.implClassName()); } } catch (Exception e) { throw new RuntimeException( @@ -1684,22 +1707,103 @@ public class JavaEmitter implements GlueEmitter { } - protected void emitCHeader(PrintWriter cWriter, String className) { + private static final String initClassAccessCode = "\n"+ + "static const char * clazzNameBuffers = \"com/jogamp/common/nio/Buffers\";\n"+ + "static const char * clazzNameBuffersStaticNewCstrName = \"newDirectByteBuffer\";\n"+ + "static const char * clazzNameBuffersStaticNewCstrSignature = \"(I)Ljava/nio/ByteBuffer;\";\n"+ + "static jclass clazzBuffers = NULL;\n"+ + "static jmethodID cstrBuffersNew = NULL;\n"+ + "\n"+ + "static jboolean _initClazzAccess(JNIEnv *env) {\n"+ + " jclass c;\n"+ + "\n"+ + " if(NULL!=cstrBuffersNew) return JNI_TRUE;\n"+ + "\n"+ + " c = (*env)->FindClass(env, clazzNameBuffers);\n"+ + " if(NULL==c) {\n"+ + " fprintf(stderr, \"FatalError: Can't find %s\\n\", clazzNameBuffers);\n"+ + " (*env)->FatalError(env, clazzNameBuffers);\n"+ + " return JNI_FALSE;\n"+ + " }\n"+ + " clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c);\n"+ + " if(NULL==clazzBuffers) {\n"+ + " fprintf(stderr, \"FatalError: Can't use %s\\n\", clazzNameBuffers);\n"+ + " (*env)->FatalError(env, clazzNameBuffers);\n"+ + " return JNI_FALSE;\n"+ + " }\n"+ + "\n"+ + " cstrBuffersNew = (*env)->GetStaticMethodID(env, clazzBuffers,\n"+ + " clazzNameBuffersStaticNewCstrName, clazzNameBuffersStaticNewCstrSignature);\n"+ + " if(NULL==cstrBuffersNew) {\n"+ + " fprintf(stderr, \"FatalError: Java_jogamp_common_jvm_JVMUtil:: can't create %s.%s %s\\n\",\n"+ + " clazzNameBuffers,\n"+ + " clazzNameBuffersStaticNewCstrName, clazzNameBuffersStaticNewCstrSignature);\n"+ + " (*env)->FatalError(env, clazzNameBuffersStaticNewCstrName);\n"+ + " return JNI_FALSE;\n"+ + " }\n"+ + " return JNI_TRUE;\n"+ + "}\n"+ + "\n"+ + "static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, void * source_address, jlong capacity) {\n"+ + " jobject jbyteBuffer = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffersNew, capacity);\n"+ + " void * byteBufferPtr = (*env)->GetDirectBufferAddress(env, jbyteBuffer);\n"+ + " memcpy(byteBufferPtr, source_address, capacity);\n"+ + " return jbyteBuffer;\n"+ + "}\n"+ + "\n"; + + private static final String staticClassInitCode = "\n"+ + " static {\n"+ + " if( !initializeImpl() ) {\n"+ + " throw new RuntimeException(\"Initialization failure\");\n"+ + " }\n"+ + " }\n"+ + "\n"; + + protected void emitCHeader(PrintWriter cWriter, String packageName, String className) { cWriter.println("#include <jni.h>"); cWriter.println("#include <stdlib.h>"); + cWriter.println("#include <string.h>"); cWriter.println(); if (getConfig().emitImpl()) { cWriter.println("#include <assert.h>"); cWriter.println(); } - + emitCInitCode(cWriter, packageName, className); for (String code : cfg.customCCode()) { cWriter.println(code); } cWriter.println(); } + protected void emitCInitCode(PrintWriter cWriter, String packageName, String className) { + if (getConfig().emitImpl()) { + cWriter.println(initClassAccessCode); + cWriter.println("JNIEXPORT jboolean JNICALL "+JavaEmitter.getJNIMethodNamePrefix(packageName, className)+"_initializeImpl(JNIEnv *env, jclass _unused) {"); + cWriter.println(" return _initClazzAccess(env);"); + cWriter.println("}"); + cWriter.println(); + } + } + protected void emitJavaInitCode() { + if ( cfg.allStatic() ) { + emitJavaInitCode( javaWriter(), cfg.className() ); + } else if( cfg.emitImpl() ) { + emitJavaInitCode( javaImplWriter(), cfg.implClassName() ); + } + } + protected void emitJavaInitCode(PrintWriter jWriter, String className) { + if( null != jWriter ) { + jWriter.println(); + jWriter.println(" private static native boolean initializeImpl();"); + jWriter.println(); + if( !cfg.manualStaticInit(className) ) { + jWriter.println(staticClassInitCode); + } + } + } + /** * Write out any footer information for the output files (closing brace of * class definition, etc). |