diff options
author | Sven Gothel <[email protected]> | 2014-06-25 10:16:01 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-06-25 10:16:01 +0200 |
commit | 9ee44e1a289ecbac024662dd5a2ffc42e8add023 (patch) | |
tree | 2946a8bbf78e2fd26d088c35ee24cde3e51648e0 /src/java/com/jogamp/gluegen | |
parent | 6cb643671578aa912d16dd17e773d92f4667118b (diff) |
Bug 1025 - GlueGen: Add accessor for compound fields of type array, pointer and string (code generation)
Enhance compound access as delivered by Bug 1022,
to also generate accessors (getter and setter) for
array, pointer and string types.
Allow configuration of array length either via
their internal size (c-header) or config 'ReturnedArrayLength'.
'ReturnedArrayLength' allows specifying a java expression.
Canonical field names of compounds are _now_ specified as
follows for configuration entries:
COMPOUND.FIELD
e.g.
StructA.fieldB
Also allow configuration of pointer fields to be treated as
referenced arrays via 'ReturnedArrayLength'.
Further, allow specifying 'pointer fields' as String values
via 'ReturnsString' configuration.
++++
Implementation details:
- handle above described accessor features
- enhance JavaDoc for generated accessors
- generate native JNI compound and string accessor on demand
- encapsule accessor code generation in their own methods
- enhance exception messages
- enhance type verbosity in debug mode
- verbose debug output via GlueGen.debug()
Tests:
- Features covered by test1.[ch]
and Test1p1JavaEmitter and Test1p2ProcAddressEmitter
- Validated compilation and unit tests for modules:
- joal
- jogl (minor config changes req.)
- jocl (minor config changes req.)
Diffstat (limited to 'src/java/com/jogamp/gluegen')
-rw-r--r-- | src/java/com/jogamp/gluegen/CMethodBindingEmitter.java | 37 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaConfiguration.java | 74 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaEmitter.java | 1158 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java | 64 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaType.java | 70 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/MethodBinding.java | 12 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/types/ArrayType.java | 7 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/types/FunctionType.java | 20 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/types/PointerType.java | 12 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/types/StructLayout.java | 12 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/types/Type.java | 97 |
11 files changed, 1149 insertions, 414 deletions
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java index 0e373d0..1c9d043 100644 --- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java @@ -909,7 +909,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { writer.print(CMethodBindingEmitter.cThisArgumentName()); } else { writer.print("("); - Type cArgType = binding.getCArgumentType(i); + final Type cArgType = binding.getCArgumentType(i); boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType); boolean needsArrayOffset = !needsDataCopy && ( javaArgType.isArray() || @@ -921,8 +921,8 @@ public class CMethodBindingEmitter extends FunctionEmitter { // if this is a pointer to an unsigned type, add unsigned to the name to avoid compiler warnings if(cArgType.isPointer()) { - Type typeLast = ((PointerType)cArgType).getLastTargetType(); - if(typeLast.isInt() && (((IntType)typeLast).isPrimitiveUnsigned())) { + final Type baseType = cArgType.getBaseElementType(); + if(baseType.isInt() && (((IntType)baseType).isPrimitiveUnsigned())) { writer.print("unsigned "); } } @@ -955,8 +955,18 @@ public class CMethodBindingEmitter extends FunctionEmitter { return binding.getNumArguments(); } - protected void emitBodyCallCFunction(PrintWriter writer) { + private boolean isCStructFunctionPointer = false; + + /** + * If method originates from a struct, see {@link MethodBinding#hasContainingType()}, + * it can either purposed to call a native static function (default) + * or a struct's function pointer. + */ + protected void setIsCStructFunctionPointer(final boolean v) { + isCStructFunctionPointer = v; + } + protected void emitBodyCallCFunction(PrintWriter writer) { // Make the call to the actual C function writer.print(" "); @@ -967,7 +977,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { if (!cReturnType.isVoid()) { writer.print("_res = "); } - if (binding.hasContainingType()) { + if ( isCStructFunctionPointer && binding.hasContainingType() ) { // Call through function pointer writer.print(CMethodBindingEmitter.cThisArgumentName() + "->"); } @@ -1019,8 +1029,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { // See whether capacity has been specified if (returnValueCapacityExpression != null) { - writer.print( - returnValueCapacityExpression.format(argumentNameArray())); + writer.print( returnValueCapacityExpression.format( argumentNameArray() ) ); } else { if (cReturnType.isPointer() && cReturnType.asPointer().getTargetType().isCompound()) { @@ -1030,7 +1039,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { "for function \"" + binding + "\": " + "Structs to be emitted should have been laid out by this point " + "(type " + cReturnType.asPointer().getTargetType().getName() + " / " + - cReturnType.asPointer().getTargetType() + " was not)" + cReturnType.asPointer().getTargetType() + " was not) for "+binding ); } } @@ -1073,7 +1082,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { throw new RuntimeException( "Could not emit native code for function \"" + binding + - "\": array return values for non-char types not implemented yet"); + "\": array return values for non-char types not implemented yet, for "+binding); // FIXME: This is approximately what will be required here // @@ -1095,8 +1104,8 @@ public class CMethodBindingEmitter extends FunctionEmitter { //writer.print(arrayRes); //writer.println(";"); } else { - System.err.print("Unhandled return type: "+javaReturnType.getDumpString()); - throw new RuntimeException("Unhandled return type"); + System.err.print("Unhandled return type: "+javaReturnType.getDebugString()); + throw new RuntimeException("Unhandled return type: "+javaReturnType.getDebugString()+" for "+binding); } } } @@ -1474,11 +1483,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { } protected String byteOffsetArgName(int i) { - return byteOffsetArgName(binding.getArgumentName(i)); - } - - protected String byteOffsetArgName(String s) { - return s + "_byte_offset"; + return JavaMethodBindingEmitter.byteOffsetArgName(binding.getArgumentName(i)); } protected String isNIOArgName(int i) { diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java index 552b237..771576e 100644 --- a/src/java/com/jogamp/gluegen/JavaConfiguration.java +++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java @@ -492,11 +492,21 @@ public class JavaConfiguration { return returnsString.contains(functionName); } - /** Provides a Java MessageFormat expression indicating the number - of elements in the returned array from the specified function - name. Indicates that the given return value, which must be a - pointer to a CompoundType, is actually an array of the - CompoundType rather than a pointer to a single object. */ + /** + * Returns a MessageFormat string of the Java expression calculating + * the number of elements in the returned array from the specified function + * name. The literal <code>1</code> indicates a single object. + * <p> + * If symbol references a struct fields, see {@link #canonicalStructFieldSymbol(String, String)}, + * it describes field's array-length or element-count referenced by a pointer. + * </p> + * <p> + * In case of struct fields, this array length will also be used + * for the native C function, i.e. multiplied w/ <code>sizeof(C-Type)</code> + * and passed down to native code, <b>if</b> not overriden by + * either {@link #returnValueCapacity(String)} or {@link #returnValueLength(String)}! + * </p> + */ public String returnedArrayLength(String functionName) { return returnedArrayLengths.get(functionName); } @@ -623,18 +633,29 @@ public class JavaConfiguration { return forcedStructs; } - /** Returns a MessageFormat string of the C expression calculating - the capacity of the java.nio.ByteBuffer being returned from a - native method, or null if no expression has been specified. */ + /** + * Returns a MessageFormat string of the C expression calculating + * the capacity of the java.nio.ByteBuffer being returned from a + * native method, or null if no expression has been specified. + * <p> + * If symbol references a struct fields, see {@link #canonicalStructFieldSymbol(String, String)}, + * it describes field's array-length or element-count referenced by a pointer. + * </p> + */ public String returnValueCapacity(String functionName) { return returnValueCapacities.get(functionName); } - /** Returns a MessageFormat string of the C expression calculating - the length of the array being returned from a native method, or - null if no expression has been specified. */ - public String returnValueLength(String functionName) { - return returnValueLengths.get(functionName); + /** + * Returns a MessageFormat string of the C expression calculating + * the length of the array being returned from a native method. + * <p> + * If symbol references a struct fields, see {@link #canonicalStructFieldSymbol(String, String)}, + * it describes field's array-length or element-count referenced by a pointer. + * </p> + */ + public String returnValueLength(String symbol) { + return returnValueLengths.get(symbol); } /** Returns a List of Strings of expressions declaring temporary C @@ -727,8 +748,21 @@ public class JavaConfiguration { } } - /** Returns true if this #define, function, struct, or field within - a struct should be ignored during glue code generation. */ + /** + * Returns the canonical configuration name for a struct field name, + * i.e. 'struct-name'.'field-name' + */ + public static String canonicalStructFieldSymbol(String structName, String fieldName) { + return structName+"."+fieldName; + } + + /** + * Returns true if this #define, function, struct, or field within + * a struct should be ignored during glue code generation of interfaces and implementation. + * <p> + * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}. + * </p> + */ public boolean shouldIgnoreInInterface(String symbol) { if(DEBUG_IGNORES) { dumpIgnoresOnce(); @@ -754,6 +788,13 @@ public class JavaConfiguration { return shouldIgnoreInImpl_Int(symbol); } + /** + * Returns true if this #define, function, struct, or field within + * a struct should be ignored during glue code generation of implementation only. + * <p> + * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}. + * </p> + */ public boolean shouldIgnoreInImpl(String symbol) { return shouldIgnoreInImpl_Int(symbol); } @@ -1195,7 +1236,6 @@ public class JavaConfiguration { } } - @SuppressWarnings("unchecked") protected void readExtendedIntfImplSymbols(StringTokenizer tok, String filename, int lineNo, boolean forInterface, boolean forImplementation, boolean onlyList) { File javaFile; BufferedReader javaReader; @@ -1299,7 +1339,7 @@ public class JavaConfiguration { try { String containingStruct = tok.nextToken(); String name = tok.nextToken(); - ignores.add(Pattern.compile(containingStruct + " " + name)); + ignores.add(Pattern.compile(containingStruct + "\\." + name)); } catch (NoSuchElementException e) { throw new RuntimeException("Error parsing \"IgnoreField\" command at line " + lineNo + " in file \"" + filename + "\"", e); diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index 822c1c9..3125edf 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -659,21 +659,20 @@ public class JavaEmitter implements GlueEmitter { (binding.needsNIOWrappingOrUnwrapping() || hasPrologueOrEpilogue), !cfg.useNIODirectOnly(binding.getName()), machDescJava); - prepCEmitter(binding, cEmitter); + prepCEmitter(binding.getName(), binding.getJavaReturnType(), cEmitter); allEmitters.add(cEmitter); } } } - protected void prepCEmitter(MethodBinding binding, CMethodBindingEmitter cEmitter) + protected void prepCEmitter(String returnSizeLookupName, JavaType javaReturnType, CMethodBindingEmitter cEmitter) { // See whether we need an expression to help calculate the // length of any return type - JavaType javaReturnType = binding.getJavaReturnType(); if (javaReturnType.isNIOBuffer() || javaReturnType.isCompoundTypeWrapper()) { // See whether capacity has been specified - String capacity = cfg.returnValueCapacity(binding.getName()); + final String capacity = cfg.returnValueCapacity(returnSizeLookupName); if (capacity != null) { cEmitter.setReturnValueCapacityExpression( new MessageFormat(capacity) ); } @@ -688,13 +687,13 @@ public class JavaEmitter implements GlueEmitter { } // See whether length has been specified - String len = cfg.returnValueLength(binding.getName()); + final String len = cfg.returnValueLength(returnSizeLookupName); if (len != null) { cEmitter.setReturnValueLengthExpression( new MessageFormat(len) ); } } - cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName())); - cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName())); + cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(returnSizeLookupName)); + cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(returnSizeLookupName)); } /** @@ -827,32 +826,35 @@ public class JavaEmitter implements GlueEmitter { } @Override - public void emitStruct(CompoundType structType, String alternateName) throws Exception { - String name = structType.getName(); - if (name == null && alternateName != null) { - name = alternateName; + public void emitStruct(final CompoundType structCType, final String alternateName) throws Exception { + final String structCTypeName; + { + String _name = structCType.getName(); + if (_name == null && alternateName != null) { + _name = alternateName; + } + structCTypeName = _name; } - if (name == null) { - final String structName = structType.getStructName(); + if (structCTypeName == null) { + final String structName = structCType.getStructName(); if ( null != structName && cfg.shouldIgnoreInInterface(structName) ) { return; } - - LOG.log(WARNING, "skipping emission of unnamed struct \"{0}\"", structType); + LOG.log(WARNING, "skipping emission of unnamed struct \"{0}\"", structCType); return; } - if (cfg.shouldIgnoreInInterface(name)) { + if (cfg.shouldIgnoreInInterface(structCTypeName)) { return; } - Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structType, 0)); - JavaType containingType = typeToJavaType(containingCType, false, null); - if (!containingType.isCompoundTypeWrapper()) { + final Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structCType, 0)); + final JavaType containingJType = typeToJavaType(containingCType, null); + if (!containingJType.isCompoundTypeWrapper()) { return; } - String containingTypeName = containingType.getName(); + final String containingJTypeName = containingJType.getName(); this.requiresStaticInitialization = false; // reset @@ -874,23 +876,36 @@ public class JavaEmitter implements GlueEmitter { // which complies w/ Java types. boolean needsNativeCode = false; + // Native code for calls through function pointers gets emitted // into the abstract base class; Java code which accesses fields // gets emitted into the concrete classes - for (int i = 0; i < structType.getNumFields(); i++) { - if (structType.getField(i).getType().isFunctionPointer()) { - needsNativeCode = true; - break; + for (int i = 0; i < structCType.getNumFields(); i++) { + final Field field = structCType.getField(i); + final Type fieldType = field.getType(); + + final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName()); + + if (!cfg.shouldIgnoreInInterface(cfgFieldName0)) { + + final String renamed = cfg.getJavaSymbolRename(cfgFieldName0); + final String fieldName = renamed==null ? field.getName() : renamed; + final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName); + + if ( fieldType.isFunctionPointer() || fieldType.isPointer() || requiresGetCStringLength(fieldType, cfgFieldName1) ) { + needsNativeCode = true; + break; + } } } - final String structClassPkg = cfg.packageForStruct(name); + final String structClassPkgName = cfg.packageForStruct(structCTypeName); final PrintWriter javaWriter; final PrintWriter jniWriter; try { javaWriter = openFile(cfg.javaOutputDir() + File.separator + - CodeGenUtils.packageAsPath(structClassPkg) + - File.separator + containingTypeName + ".java", containingTypeName); + CodeGenUtils.packageAsPath(structClassPkgName) + + File.separator + containingJTypeName + ".java", containingJTypeName); if( null == javaWriter ) { // suppress output if openFile deliberately returns null. return; @@ -901,9 +916,9 @@ public class JavaEmitter implements GlueEmitter { if (cfg.nativeOutputUsesJavaHierarchy()) { nRoot += File.separator + CodeGenUtils.packageAsPath(cfg.packageName()); } - jniWriter = openFile(nRoot + File.separator + containingTypeName + "_JNI.c", containingTypeName); + jniWriter = openFile(nRoot + File.separator + containingJTypeName + "_JNI.c", containingJTypeName); CodeGenUtils.emitAutogeneratedWarning(jniWriter, this); - emitCHeader(jniWriter, structClassPkg, containingTypeName); + emitCHeader(jniWriter, structClassPkgName, containingJTypeName); } else { jniWriter = null; } @@ -912,7 +927,7 @@ public class JavaEmitter implements GlueEmitter { } javaWriter.println(); - javaWriter.println("package " + structClassPkg + ";"); + javaWriter.println("package " + structClassPkgName + ";"); javaWriter.println(); javaWriter.println("import java.nio.*;"); javaWriter.println(); @@ -929,13 +944,13 @@ public class JavaEmitter implements GlueEmitter { javaWriter.println(";"); } javaWriter.println(); - List<String> javadoc = cfg.javadocForClass(containingTypeName); + List<String> javadoc = cfg.javadocForClass(containingJTypeName); for (String doc : javadoc) { javaWriter.println(doc); } - javaWriter.print("public class " + containingTypeName + " "); + javaWriter.print("public class " + containingJTypeName + " "); boolean firstIteration = true; - List<String> userSpecifiedInterfaces = cfg.implementedInterfaces(containingTypeName); + List<String> userSpecifiedInterfaces = cfg.implementedInterfaces(containingJTypeName); for (String userInterface : userSpecifiedInterfaces) { if (firstIteration) { javaWriter.print("implements "); @@ -951,85 +966,90 @@ 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, null); /* w/o offset */ + generateOffsetAndSizeArrays(javaWriter, " ", containingJTypeName, structCType, null, null); /* w/o offset */ if( GlueGen.debug() ) { - System.err.printf("SE.__: t %s: %s%n", structType, containingTypeName); + System.err.printf("SE.__: structCType %s%n", structCType.getDebugString()); + System.err.printf("SE.__: contCTypeName %s%n", containingCType.getDebugString()); + System.err.printf("SE.__: contJTypeName %s%n", containingJType.getDebugString()); } - for (int i = 0; i < structType.getNumFields(); i++) { - final Field field = structType.getField(i); + for (int i = 0; i < structCType.getNumFields(); i++) { + final Field field = structCType.getField(i); final Type fieldType = field.getType(); - - if (!cfg.shouldIgnoreInInterface(name + " " + field.getName())) { - final String renamed = cfg.getJavaSymbolRename(field.getName()); + final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName()); + if ( !cfg.shouldIgnoreInInterface(cfgFieldName0) ) { + final String renamed = cfg.getJavaSymbolRename(cfgFieldName0); final String fieldName = null==renamed ? field.getName() : renamed; + final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName); if (fieldType.isFunctionPointer()) { // no offset/size for function pointer .. if( GlueGen.debug() ) { - System.err.printf("SE.os.%02d: t %s: %s / %s (%s)%n", (i+1), fieldType, field, fieldName, "SKIP FuncPtr"); + System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "SKIP FuncPtr"); } } else if (fieldType.isCompound()) { // FIXME: will need to support this at least in order to // 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 + "\")"); + throw new RuntimeException("Anonymous structs as fields not supported yet, field \"" + + cfgFieldName1 + "\", "+fieldType.getDebugString()); } if( GlueGen.debug() ) { - System.err.printf("SE.os.%02d: t %s: %s / %s (%s)%n", (i+1), fieldType, field, fieldName, "compound"); + System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "compound"); } generateOffsetAndSizeArrays(javaWriter, " ", fieldName, fieldType, field, null); } else if (fieldType.isArray()) { final Type baseElementType = field.getType().asArray().getBaseElementType(); if( GlueGen.debug() ) { - System.err.printf("SE.os.%02d: t %s: %s / %s - baseType %s (%s)%n", (i+1), fieldType, field, fieldName, baseElementType, "array"); + System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "array"); + System.err.printf("SE.os.%02d: baseType %s%n", (i+1), baseElementType.getDebugString()); } generateOffsetAndSizeArrays(javaWriter, " ", fieldName, fieldType, field, null); } else { final JavaType externalJavaType; try { - externalJavaType = typeToJavaType(fieldType, false, machDescJava); + externalJavaType = typeToJavaType(fieldType, machDescJava); } catch (Exception e) { - System.err.println("Error occurred while creating accessor for field \"" + - field.getName() + "\" in type \"" + name + "\""); - throw(e); + throw new RuntimeException("Error occurred while creating accessor for field \"" + + cfgFieldName1 + "\", "+fieldType.getDebugString(), e); } if( GlueGen.debug() ) { - System.err.printf("SE.os.%02d: t %s: %s / %s - javaType %s (%s)%n", (i+1), fieldType, field, fieldName, externalJavaType.getDumpString(), "MISC"); + System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, fieldName, fieldType.getDebugString(), "MISC"); + System.err.printf("SE.os.%02d: javaType %s%n", (i+1), externalJavaType.getDebugString()); } if (externalJavaType.isPrimitive()) { // Primitive type generateOffsetAndSizeArrays(javaWriter, " ", fieldName, null, field, null); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, "//", fieldName, fieldType, null, null); } else if (externalJavaType.isCPrimitivePointerType()) { - // FIXME: Primitive Pointer type - generateOffsetAndSizeArrays(javaWriter, "// Skipped C-Primitive-Ptr-Type: ", fieldName, fieldType, field, externalJavaType.getDumpString()); + if( requiresGetCStringLength(fieldType, cfgFieldName1) ) { + generateOffsetAndSizeArrays(javaWriter, " ", fieldName, null, field, null); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, "//", fieldName, fieldType, null, "// "+externalJavaType.getDebugString()); + } else { + generateOffsetAndSizeArrays(javaWriter, "//", fieldName, fieldType, field, "// "+externalJavaType.getDebugString()); + } } else { - // FIXME ??? - generateOffsetAndSizeArrays(javaWriter, "// Skipped Complicated Field: ", fieldName, fieldType, field, externalJavaType.getDumpString()); - LOG.log(WARNING, "Complicated fields (field \"{0}\" of type \"{1}\") not implemented yet: {2}", - new Object[]{field, name, externalJavaType.getDumpString()}); - // throw new RuntimeException("Complicated fields (field \"" + field + "\" of type \"" + t + - // "\") not implemented yet"); + generateOffsetAndSizeArrays(javaWriter, " ", fieldName, null, field, null); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, "//", fieldName, fieldType, null, "// "+externalJavaType.getDebugString()); } } } else if( GlueGen.debug() ) { - System.err.printf("SE.os.%02d: t %s: %s (IGNORED)%n", (i+1), fieldType, field); + System.err.printf("SE.os.%02d: %s, %s (IGNORED)%n", (i+1), field, fieldType.getDebugString()); } } javaWriter.println(); javaWriter.println(" public static int size() {"); - javaWriter.println(" return "+containingTypeName+"_size[mdIdx];"); + javaWriter.println(" return "+containingJTypeName+"_size[mdIdx];"); javaWriter.println(" }"); javaWriter.println(); - javaWriter.println(" public static " + containingTypeName + " create() {"); + javaWriter.println(" public static " + containingJTypeName + " create() {"); javaWriter.println(" return create(Buffers.newDirectByteBuffer(size()));"); javaWriter.println(" }"); javaWriter.println(); - javaWriter.println(" public static " + containingTypeName + " create(java.nio.ByteBuffer buf) {"); - javaWriter.println(" return new " + containingTypeName + "(buf);"); + javaWriter.println(" public static " + containingJTypeName + " create(java.nio.ByteBuffer buf) {"); + javaWriter.println(" return new " + containingJTypeName + "(buf);"); javaWriter.println(" }"); javaWriter.println(); - javaWriter.println(" " + containingTypeName + "(java.nio.ByteBuffer buf) {"); + javaWriter.println(" " + containingJTypeName + "(java.nio.ByteBuffer buf) {"); javaWriter.println(" accessor = new StructAccessor(buf);"); javaWriter.println(" }"); javaWriter.println(); @@ -1037,168 +1057,52 @@ public class JavaEmitter implements GlueEmitter { javaWriter.println(" return accessor.getBuffer();"); javaWriter.println(" }"); - for (int i = 0; i < structType.getNumFields(); i++) { - final Field field = structType.getField(i); + Set<MethodBinding> methodBindingSet = new HashSet<MethodBinding>(); + + for (int i = 0; i < structCType.getNumFields(); i++) { + final Field field = structCType.getField(i); final Type fieldType = field.getType(); - if (!cfg.shouldIgnoreInInterface(name + " " + field.getName())) { - final String renamed = cfg.getJavaSymbolRename(field.getName()); + final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName()); + if (!cfg.shouldIgnoreInInterface(cfgFieldName0)) { + final String renamed = cfg.getJavaSymbolRename(cfgFieldName0); final String fieldName = renamed==null ? field.getName() : renamed; + final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName); + if( GlueGen.debug() ) { + System.err.printf("SE.ac.%02d: %s / %s, %s%n", (i+1), field, cfgFieldName1, fieldType.getDebugString()); + } if (fieldType.isFunctionPointer()) { - if( GlueGen.debug() ) { - System.err.printf("SE.ac.%02d: t %s: %s / %s (%s)%n", (i+1), fieldType, field, fieldName, "funcPtr"); - } - try { - // Emit method call and associated native code - final FunctionType funcType = fieldType.asPointer().getTargetType().asFunction(); - final FunctionSymbol funcSym = new FunctionSymbol(fieldName, funcType); - final MethodBinding binding = bindFunction(funcSym, containingType, containingCType, machDescJava); - binding.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis - javaWriter.println(); - - // Emit public Java entry point for calling this function pointer - JavaMethodBindingEmitter emitter = - new JavaMethodBindingEmitter(binding, - javaWriter, - cfg.runtimeExceptionType(), - cfg.unsupportedExceptionType(), - true, - cfg.tagNativeBinding(), - false, // eraseBufferAndArrayTypes - true, // FIXME: should unify this with the general emission code - true, // FIXME: should unify this with the general emission code - false, - false, // FIXME: should unify this with the general emission code - false, // FIXME: should unify this with the general emission code - false, // FIXME: should unify this with the general emission code - false, - cfg); - emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); - emitter.emit(); - - // Emit private native Java entry point for calling this function pointer - emitter = - new JavaMethodBindingEmitter(binding, - javaWriter, - cfg.runtimeExceptionType(), - cfg.unsupportedExceptionType(), - false, - cfg.tagNativeBinding(), - true, - true, // FIXME: should unify this with the general emission code - true, // FIXME: should unify this with the general emission code - true, - true, // FIXME: should unify this with the general emission code - false, // FIXME: should unify this with the general emission code - false, // FIXME: should unify this with the general emission code - false, - cfg); - emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); - emitter.addModifier(JavaMethodBindingEmitter.NATIVE); - emitter.emit(); - - // Emit (private) C entry point for calling this function pointer - CMethodBindingEmitter cEmitter = - new CMethodBindingEmitter(binding, - jniWriter, - structClassPkg, - containingTypeName, - true, // FIXME: this is optional at this point - false, - true, - false, // FIXME: should unify this with the general emission code - machDescJava); - prepCEmitter(binding, cEmitter); - cEmitter.emit(); - } catch (Exception e) { - System.err.println("While processing field " + field + " of type " + name + ":"); - throw(e); - } + generateFunctionPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName, + containingCType, containingJType, i, + new FunctionSymbol(fieldName, fieldType.asPointer().getTargetType().asFunction()), cfgFieldName1); } else if (fieldType.isCompound()) { // FIXME: will need to support this at least in order to // 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 + "\")"); + field + "\" in type \"" + structCTypeName + "\")"); } - if( GlueGen.debug() ) { - System.err.printf("SE.ac.%02d: t %s: %s / %s (%s)%n", (i+1), fieldType, field, fieldName, "compound"); - } - javaWriter.println(); - generateGetterSignature(javaWriter, false, fieldType.getName(), capitalizeString(fieldName)); + generateGetterSignature(javaWriter, fieldType, false, fieldType.getName(), capitalizeString(fieldName), null, null); javaWriter.println(" {"); javaWriter.println(" return " + fieldType.getName() + ".create( accessor.slice( " + fieldName+"_offset[mdIdx], "+fieldName+"_size[mdIdx] ) );"); javaWriter.println(" }"); - } else if (fieldType.isArray()) { - final Type baseElementType = field.getType().asArray().getBaseElementType(); - final JavaType paramType = typeToJavaType(baseElementType, false, machDescJava); - - final String paramTypeName = paramType.getName(); - final String capitalized = capitalizeString(fieldName); - if( GlueGen.debug() ) { - System.err.printf("SE.ac.%02d: t %s: %s / %s - baseType %s, paramType %s (%s)%n", (i+1), fieldType, field, fieldName, baseElementType, paramType.getDumpString(), "array"); - } - - // Setter - javaWriter.println(); - generateSetterSignature(javaWriter, false, containingTypeName, capitalized, paramTypeName+"[]"); - javaWriter.println(" {"); - if(baseElementType.isPrimitive()) { - javaWriter.print (" accessor.set" + capitalizeString(paramTypeName) + "sAt(" + fieldName+"_offset[mdIdx], val);"); - javaWriter.println(" return this;"); - } else { - javaWriter.println(" final int elemSize = "+paramTypeName+".size();"); - javaWriter.println(" final ByteBuffer destB = getBuffer();"); - javaWriter.println(" int offset = "+fieldName+"_offset[mdIdx];"); - javaWriter.println(" final int total = "+fieldType.asArray().getLength()+" * elemSize;"); - javaWriter.println(" if( total > "+fieldName+"_size[mdIdx] ) { throw new IndexOutOfBoundsException(\"total \"+total+\" > size \"+"+fieldName+"_size[mdIdx]+\", elemSize \"+elemSize+\" * "+fieldType.asArray().getLength()+"\"); };"); - javaWriter.println(" final int limes = offset + total;"); - javaWriter.println(" if( limes >= destB.limit() ) { throw new IndexOutOfBoundsException(\"limes \"+limes+\" >= buffer.limit \"+destB.limit()+\", elemOff \"+offset+\", elemSize \"+elemSize+\" * "+fieldType.asArray().getLength()+"\"); };"); - javaWriter.println(" for(int e=0; e<"+fieldType.asArray().getLength()+"; e++) {"); - javaWriter.println(" final "+paramTypeName+" source = val[e];"); - javaWriter.println(" final ByteBuffer sourceB = source.getBuffer();"); - javaWriter.println(" for(int f=0; f<elemSize; f++) {"); - javaWriter.println(" if( offset >= limes ) { throw new IndexOutOfBoundsException(\"elem-byte[\"+e+\"][\"+f+\"]: offset \"+offset+\" >= limes \"+limes+\", elemSize \"+elemSize+\" * "+fieldType.asArray().getLength()+"\"); };"); - javaWriter.println(" destB.put(offset++, sourceB.get(f));"); - javaWriter.println(" }"); - javaWriter.println(" }"); - javaWriter.println(" return this;"); - } - javaWriter.println(" }"); - javaWriter.println(); - // Getter - generateGetterSignature(javaWriter, false, paramTypeName+"[]", capitalized); - javaWriter.println(" {"); - if(baseElementType.isPrimitive()) { - javaWriter.print (" return accessor.get" + capitalizeString(paramTypeName) + "sAt(" + fieldName+"_offset[mdIdx], new " +paramTypeName+"["+fieldType.asArray().getLength()+"]);"); - } else { - javaWriter.println(" final "+paramTypeName+"[] res = new "+paramTypeName+"["+fieldType.asArray().getLength()+"];"); - javaWriter.println(" int offset = "+fieldName+"_offset[mdIdx];"); - javaWriter.println(" final int elemSize = "+paramTypeName+".size();"); - javaWriter.println(" for(int e=0; e<"+fieldType.asArray().getLength()+"; e++) {"); - javaWriter.println(" res[e] = "+paramTypeName+".create(accessor.slice(offset, elemSize));"); - javaWriter.println(" offset += elemSize;"); - javaWriter.println(" }"); - javaWriter.println(" return res;"); - } - javaWriter.println(" }"); + } else if ( fieldType.isArray() || fieldType.isPointer() ) { + generateArrayGetterSetterCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName, + containingCType, containingJType, + i, field, fieldName, cfgFieldName1); } else { final JavaType javaType; - try { - javaType = typeToJavaType(fieldType, false, machDescJava); + javaType = typeToJavaType(fieldType, machDescJava); } catch (Exception e) { System.err.println("Error occurred while creating accessor for field \"" + - field.getName() + "\" in type \"" + name + "\""); + field.getName() + "\", "+fieldType.getDebugString()); throw(e); } - if( GlueGen.debug() ) { - System.err.printf("SE.ac.%02d: t %s: %s / %s - javaType %s (%s)%n", (i+1), fieldType, field, fieldName, javaType.getDumpString(), "MISC"); - } if (javaType.isPrimitive()) { // Primitive type final boolean fieldTypeNativeSizeFixed = fieldType.getSize().hasFixedNativeSize(); @@ -1213,26 +1117,27 @@ public class JavaEmitter implements GlueEmitter { final String sizeDenominator = fieldType.isPointer() ? "pointer" : javaTypeName ; if(GlueGen.debug()) { - System.err.println("Java.StructEmitter.Primitive: "+field.getName()+", "+fieldType.getName(true)+", "+javaTypeName+", "+ - ", fixedSize "+fieldTypeNativeSizeFixed+", opaque "+isOpaque(fieldType)+", isPointer "+fieldType.isPointer()+", isCompound "+fieldType.isCompound()+ - ", sizeDenominator "+sizeDenominator); + System.err.println("Java.StructEmitter.Primitive: "+field.getName()+", "+fieldType.getDebugString()+", "+javaTypeName+", "+ + ", fixedSize "+fieldTypeNativeSizeFixed+", opaque "+isOpaque(fieldType)+", sizeDenominator "+sizeDenominator); } - javaWriter.println(); - // Setter - generateSetterSignature(javaWriter, false, containingTypeName, capFieldName, javaTypeName); - javaWriter.println(" {"); - if( fieldTypeNativeSizeFixed ) { - javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val);"); - } else { - javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); + if( !fieldType.isConst() ) { + // Setter + javaWriter.println(); + generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capFieldName, null, javaTypeName, null, null); + javaWriter.println(" {"); + if( fieldTypeNativeSizeFixed ) { + javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val);"); + } else { + javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); + } + javaWriter.println(" return this;"); + javaWriter.println(" }"); } - javaWriter.println(" return this;"); - javaWriter.println(" }"); - javaWriter.println(); // Getter - generateGetterSignature(javaWriter, false, javaTypeName, capFieldName); + javaWriter.println(); + generateGetterSignature(javaWriter, fieldType, false, javaTypeName, capFieldName, null, null); javaWriter.println(" {"); javaWriter.print (" return "); if( fieldTypeNativeSizeFixed ) { @@ -1241,30 +1146,31 @@ 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 + } else { javaWriter.println(); - javaWriter.println(" /** "+fieldName +": "+javaType.getDumpString()+" */"); + javaWriter.println(" /** UNKNOWN: "+cfgFieldName1 +": "+fieldType.getDebugString()+", "+javaType.getDebugString()+" */"); } } } } - emitCustomJavaCode(javaWriter, containingTypeName); + emitCustomJavaCode(javaWriter, containingJTypeName); if (needsNativeCode) { javaWriter.println(); - emitJavaInitCode(javaWriter, containingTypeName); + emitJavaInitCode(javaWriter, containingJTypeName); javaWriter.println(); } javaWriter.println("}"); javaWriter.flush(); javaWriter.close(); if (needsNativeCode) { - emitCInitCode(jniWriter, structClassPkg, containingTypeName); + emitCInitCode(jniWriter, structClassPkgName, containingJTypeName); jniWriter.flush(); jniWriter.close(); } if( GlueGen.debug() ) { - System.err.printf("SE.XX: t %s: %s%n", structType, containingTypeName); + System.err.printf("SE.XX: structCType %s%n", structCType.getDebugString()); + System.err.printf("SE.XX: contCTypeName %s%n", containingCType.getDebugString()); + System.err.printf("SE.XX: contJTypeName %s%n", containingJType.getDebugString()); } } @Override @@ -1298,12 +1204,39 @@ public class JavaEmitter implements GlueEmitter { // Internals only below this point // - private void generateGetterSignature(PrintWriter writer, boolean abstractMethod, String returnTypeName, String capitalizedFieldName) { - writer.print(" public " + (abstractMethod ? "abstract " : "") + returnTypeName + " get" + capitalizedFieldName + "()"); + private void generateGetterSignature(final PrintWriter writer, final Type origFieldType, final boolean abstractMethod, + final String returnTypeName, final String capitalizedFieldName, + final String customArgs, final String arrayLengthExpr) { + writer.print(" /** Getter for native field: "+origFieldType.getDebugString()); + if( null != arrayLengthExpr ) { + writer.print(", with array length of <code>"+arrayLengthExpr+"</code>"); + } + writer.println(" */"); + writer.print(" public " + (abstractMethod ? "abstract " : "") + returnTypeName + " get" + capitalizedFieldName + "("); + if( null != customArgs ) { + writer.print(customArgs); + } + writer.print(")"); } - private void generateSetterSignature(PrintWriter writer, boolean abstractMethod, String returnTypeName, String capitalizedFieldName, String paramTypeName) { - writer.print(" public " + (abstractMethod ? "abstract " : "") + returnTypeName + " set" + capitalizedFieldName + "(" + paramTypeName + " val)"); + private void generateSetterSignature(final PrintWriter writer, final Type origFieldType, final boolean abstractMethod, + final String returnTypeName, final String capitalizedFieldName, + final String customArgsPre, final String paramTypeName, final String customArgsPost, + final String arrayLengthExpr) { + writer.print(" /** Setter for native field: "+origFieldType.getDebugString()); + if( null != arrayLengthExpr ) { + writer.print(", with array length of <code>"+arrayLengthExpr+"</code>"); + } + writer.println(" */"); + writer.print(" public " + (abstractMethod ? "abstract " : "") + returnTypeName + " set" + capitalizedFieldName + "("); + if( null != customArgsPre ) { + writer.print(customArgsPre+", "); + } + writer.print(paramTypeName + " val"); + if( null != customArgsPost ) { + writer.print(", "+customArgsPost); + } + writer.print(")"); } private void generateOffsetAndSizeArrays(PrintWriter writer, String prefix, String fieldName, Type fieldType, Field field, String postfix) { @@ -1336,31 +1269,682 @@ public class JavaEmitter implements GlueEmitter { } } - private JavaType typeToJavaType(Type cType, boolean outgoingArgument, MachineDescription curMachDesc) { + private void generateFunctionPointerCode(final Set<MethodBinding> methodBindingSet, + final PrintWriter javaWriter, final PrintWriter jniWriter, + final String structCTypeName, final String structClassPkgName, + final Type containingCType, final JavaType containingJType, + final int i, final FunctionSymbol funcSym, final String returnSizeLookupName) { + // Emit method call and associated native code + final MethodBinding mb = bindFunction(funcSym, containingJType, containingCType, machDescJava); + mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis + + // JavaTypes representing C pointers in the initial + // MethodBinding have not been lowered yet to concrete types + final List<MethodBinding> bindings = expandMethodBinding(mb); + + final boolean useNIOOnly = true; + final boolean useNIODirectOnly = true; + + for (final MethodBinding binding : bindings) { + if(!methodBindingSet.add(binding)) { + // skip .. already exisiting binding .. + continue; + } + javaWriter.println(); + // Emit public Java entry point for calling this function pointer + JavaMethodBindingEmitter emitter = + new JavaMethodBindingEmitter(binding, + javaWriter, + cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), + true, + cfg.tagNativeBinding(), + false, // eraseBufferAndArrayTypes + useNIOOnly, + useNIODirectOnly, + false, + false, // FIXME: should unify this with the general emission code + false, // forIndirectBufferAndArrayImplementation + false, // FIXME: should unify this with the general emission code + false, + cfg); + emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); + emitter.emit(); + + // Emit private native Java entry point for calling this function pointer + emitter = + new JavaMethodBindingEmitter(binding, + javaWriter, + cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), + false, + cfg.tagNativeBinding(), + true, // eraseBufferAndArrayTypes + useNIOOnly, + useNIODirectOnly, + true, + true, // FIXME: should unify this with the general emission code + false, // forIndirectBufferAndArrayImplementation + false, // FIXME: should unify this with the general emission code + false, + cfg); + emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); + emitter.addModifier(JavaMethodBindingEmitter.NATIVE); + emitter.emit(); + + // Emit (private) C entry point for calling this function pointer + CMethodBindingEmitter cEmitter = + new CMethodBindingEmitter(binding, + jniWriter, + structClassPkgName, + containingJType.getName(), + true, // FIXME: this is optional at this point + false, + true, + false, // forIndirectBufferAndArrayImplementation + machDescJava); + cEmitter.setIsCStructFunctionPointer(true); + prepCEmitter(returnSizeLookupName, binding.getJavaReturnType(), cEmitter); + cEmitter.emit(); + } + } + + private void generateArrayPointerCode(final Set<MethodBinding> methodBindingSet, + final PrintWriter javaWriter, final PrintWriter jniWriter, + final String structCTypeName, final String structClassPkgName, + final Type containingCType, final JavaType containingJType, + final int i, final FunctionSymbol funcSym, + final String returnSizeLookupName, final String docArrayLenExpr, final String nativeArrayLenExpr) { + // Emit method call and associated native code + final MethodBinding mb = bindFunction(funcSym, containingJType, containingCType, machDescJava); + mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis + + // JavaTypes representing C pointers in the initial + // MethodBinding have not been lowered yet to concrete types + final List<MethodBinding> bindings = expandMethodBinding(mb); + + final boolean useNIOOnly = true; + final boolean useNIODirectOnly = true; + + for (final MethodBinding binding : bindings) { + if(!methodBindingSet.add(binding)) { + // skip .. already exisiting binding .. + continue; + } + JavaMethodBindingEmitter emitter; + + // Emit private native Java entry point for calling this function pointer + emitter = + new JavaMethodBindingEmitter(binding, + javaWriter, + cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), + false, + cfg.tagNativeBinding(), + true, // eraseBufferAndArrayTypes + useNIOOnly, + useNIODirectOnly, + true, + true, // FIXME: should unify this with the general emission code + false, // forIndirectBufferAndArrayImplementation + false, // FIXME: should unify this with the general emission code + false, + cfg); + if( null != docArrayLenExpr ) { + emitter.setReturnedArrayLengthExpression(docArrayLenExpr, true); + } + emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); + emitter.addModifier(JavaMethodBindingEmitter.NATIVE); + emitter.emit(); + + // Emit (private) C entry point for calling this function pointer + CMethodBindingEmitter cEmitter = + new CMethodBindingEmitter(binding, + jniWriter, + structClassPkgName, + containingJType.getName(), + true, // FIXME: this is optional at this point + false, + true, + false, // forIndirectBufferAndArrayImplementation + machDescJava); + cEmitter.setIsCStructFunctionPointer(false); + final String lenExprSet; + if( null != nativeArrayLenExpr ) { + JavaType javaReturnType = binding.getJavaReturnType(); + if (javaReturnType.isNIOBuffer() || + javaReturnType.isCompoundTypeWrapper()) { + final Type retType = funcSym.getReturnType(); + final Type baseType = retType.getBaseElementType(); + lenExprSet = nativeArrayLenExpr+" * sizeof("+baseType.getName()+")"; + cEmitter.setReturnValueCapacityExpression( new MessageFormat(lenExprSet) ); + } else if (javaReturnType.isArray() || + javaReturnType.isArrayOfCompoundTypeWrappers()) { + lenExprSet = nativeArrayLenExpr; + cEmitter.setReturnValueLengthExpression( new MessageFormat(lenExprSet) ); + } else { + lenExprSet = null; + } + } else { + lenExprSet = null; + } + prepCEmitter(returnSizeLookupName, binding.getJavaReturnType(), cEmitter); + cEmitter.emit(); + } + } + + private String getArrayArrayLengthExpr(final ArrayType type, final String returnSizeLookupName, final boolean hasFixedTypeLen[], final int[][] lengthRes) { + final int[] length = new int[type.arrayDimension()]; + lengthRes[0] = length; + final StringBuilder lengthExpr = new StringBuilder(); + hasFixedTypeLen[0] = true; + ArrayType typeIter = type; + for(int i=0; i<length.length; i++) { + if( null!=typeIter && typeIter.hasLength() ) { + length[i] = typeIter.getLength(); + if( 0 < i ) { + lengthExpr.append("*"); + } + lengthExpr.append(length[i]); + } else { + length[i] = -1; + hasFixedTypeLen[0] = false; + } + if( null != typeIter ) { + typeIter = typeIter.getElementType().asArray(); + } + } + final String cfgVal = cfg.returnedArrayLength(returnSizeLookupName); + if( null != cfgVal ) { + if( hasFixedTypeLen[0] ) { + System.err.println("WARNING: struct array field '"+returnSizeLookupName+"' of '"+type+"' length '"+Arrays.toString(length)+"' overwritten by cfg-expression: "+cfgVal); + } + return cfgVal; + } + if( hasFixedTypeLen[0] ) { + return lengthExpr.toString(); + } else { + System.err.println("WARNING: struct array field '"+returnSizeLookupName+"' length '"+Arrays.toString(length)+"' without fixed- nor configured-size: "+type.getDebugString()); + return null; + } + } + private String getPointerArrayLengthExpr(final PointerType type, final String returnSizeLookupName) { + final String cfgVal = cfg.returnedArrayLength(returnSizeLookupName); + if( null != cfgVal ) { + return cfgVal; + } + return null; + } + + private static final String dummyFuncTypeName = "null *"; + private static final Type int32Type = new IntType("int32_t", SizeThunk.INT32, false, CVAttributes.CONST); + // private static final Type int8Type = new IntType("char", SizeThunk.INT8, false, 0); + // private static final Type int8PtrType = new PointerType(SizeThunk.POINTER, int8Type, 0); + private static final String nativeArrayLengthArg = "arrayLength"; + private static final String nativeArrayLengthONE = "1"; + private static final String nativeArrayElemOffsetArg = "elem_offset"; + + private boolean requiresGetCStringLength(final Type fieldType, final String returnSizeLookupName) { + if( !cfg.returnsString(returnSizeLookupName) ) { + return false; + } + final PointerType pointerType = fieldType.asPointer(); + if( null != pointerType ) { + return null == getPointerArrayLengthExpr(pointerType, returnSizeLookupName); + } + return false; + } + + private void generateArrayGetterSetterCode(final Set<MethodBinding> methodBindingSet, + final PrintWriter javaWriter, final PrintWriter jniWriter, + final String structCTypeName, final String structClassPkgName, + final Type containingCType, final JavaType containingJType, + final int i, final Field field, final String fieldName, final String returnSizeLookupName) throws Exception { + final Type fieldType = field.getType(); + final JavaType javaType; + try { + javaType = typeToJavaType(fieldType, machDescJava); + } catch (Exception e) { + throw new RuntimeException("Error occurred while creating array/pointer accessor for field \"" + + returnSizeLookupName + "\", "+fieldType.getDebugString(), e); + } + if( GlueGen.debug() ) { + System.err.printf("SE.ac.%02d: javaType %s%n", (i+1), javaType.getDebugString()); + } + + // + // Collect all required information including considering Opaque types + // + final String containingJTypeName = containingJType.getName(); + final boolean isOpaque = isOpaque(fieldType); + final boolean isString = cfg.returnsString(returnSizeLookupName); // FIXME: Allow custom Charset ? US-ASCII, UTF-8 or UTF-16 ? + final boolean useGetCStringLength; + final String arrayLengthExpr; + final int[] arrayLengths; + final boolean useFixedTypeLen[] = { false }; + final boolean isPointer; + final boolean isPrimitive; + final boolean isConst; + final JavaType baseJElemType; + final String baseJElemTypeName; + final boolean hasSingleElement; + final String capitalFieldName; + final String baseJElemTypeNameC; + final String baseJElemTypeNameU; + final boolean isByteBuffer; + { + final Type baseCElemType; + final ArrayType arrayType = fieldType.asArray(); + String _arrayLengthExpr = null; + if( isOpaque || javaType.isPrimitive() ) { + // Overridden by JavaConfiguration.typeInfo(..), i.e. Opaque! + // Emulating array w/ 1 element + isPrimitive = true; + _arrayLengthExpr = nativeArrayLengthONE; + arrayLengths = new int[] { 1 }; + baseCElemType = null; + isPointer = false; + isConst = fieldType.isConst(); + baseJElemType = null; + baseJElemTypeName = compatiblePrimitiveJavaTypeName(fieldType, javaType, machDescJava); + } else { + if( null != arrayType ) { + final int[][] lengthRes = new int[1][]; + _arrayLengthExpr = getArrayArrayLengthExpr(arrayType, returnSizeLookupName, useFixedTypeLen, lengthRes); + arrayLengths = lengthRes[0]; + baseCElemType = arrayType.getBaseElementType(); + isPointer = false; + } else { + final PointerType pointerType = fieldType.asPointer(); + _arrayLengthExpr = getPointerArrayLengthExpr(pointerType, returnSizeLookupName); + arrayLengths = null; + baseCElemType = pointerType.getBaseElementType(); + isPointer = true; + if( 1 != pointerType.pointerDepth() ) { + javaWriter.println(); + final String msg = "SKIP ptr-ptr (depth "+pointerType.pointerDepth()+"): "+returnSizeLookupName +": "+fieldType; + javaWriter.println(" // "+msg); + System.err.println("WARNING: "+msg); + return; + } + } + if( GlueGen.debug() ) { + System.err.printf("SE.ac.%02d: baseCType %s%n", (i+1), baseCElemType.getDebugString()); + } + isPrimitive = baseCElemType.isPrimitive(); + isConst = baseCElemType.isConst(); + try { + baseJElemType = typeToJavaType(baseCElemType, machDescJava); + } catch (Exception e ) { + throw new RuntimeException("Error occurred while creating array/pointer accessor for field \"" + + returnSizeLookupName + "\", baseType "+baseCElemType.getDebugString()+", topType "+fieldType.getDebugString(), e); + } + baseJElemTypeName = baseJElemType.getName(); + + if( baseCElemType.isPrimitive() && !baseCElemType.getSize().hasFixedNativeSize() ) { + javaWriter.println(); + final String msg = "SKIP primitive w/ platform dependent sized type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString(); + javaWriter.println(" // "+msg); + System.err.println("WARNING: "+msg); + return; + } + } + if( GlueGen.debug() ) { + System.err.printf("SE.ac.%02d: baseJElemType %s%n", (i+1), (null != baseJElemType ? baseJElemType.getDebugString() : null)); + } + capitalFieldName = capitalizeString(fieldName); + baseJElemTypeNameC = capitalizeString(baseJElemTypeName); + baseJElemTypeNameU = baseJElemTypeName.toUpperCase(); + isByteBuffer = "Byte".equals(baseJElemTypeNameC); + if( null == _arrayLengthExpr && isString && isPointer ) { + useGetCStringLength = true; + _arrayLengthExpr = "getCStringLengthImpl(pString)+1"; + this.requiresStaticInitialization = true; + LOG.log(INFO, "StaticInit Trigger.3 \"{0}\"", returnSizeLookupName); + } else { + useGetCStringLength = false; + } + arrayLengthExpr = _arrayLengthExpr; + if( null == arrayLengthExpr ) { + javaWriter.println(); + final String msg = "SKIP unsized array in struct: "+returnSizeLookupName+": "+fieldType.getDebugString(); + javaWriter.println(" // "+msg); + System.err.println("WARNING: "+msg); + return; + } + boolean _hasSingleElement=false; + try { + _hasSingleElement = 1 ==Integer.parseInt(_arrayLengthExpr); + } catch (Exception e ) {} + hasSingleElement = _hasSingleElement; + } + if( GlueGen.debug() ) { + System.err.printf("SE.ac.%02d: baseJElemTypeName %s, array-lengths %s%n", (i+1), baseJElemTypeName, Arrays.toString(arrayLengths)); + System.err.printf("SE.ac.%02d: arrayLengthExpr: %s, hasSingleElement %b, isByteBuffer %b, isString %b, isPointer %b, isPrimitive %b, isOpaque %b, isConst %b, useGetCStringLength %b%n", + (i+1), arrayLengthExpr, hasSingleElement, isByteBuffer, isString, isPointer, isPrimitive, isOpaque, isConst, useGetCStringLength); + } + + // + // Emit .. + // + if( !hasSingleElement && useFixedTypeLen[0] ) { + javaWriter.println(); + generateGetterSignature(javaWriter, fieldType, false, "final int", capitalFieldName+"ArrayLength", null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" return "+arrayLengthExpr+";"); + javaWriter.println(" }"); + } + if( !isConst ) { + // Setter + javaWriter.println(); + if( isPrimitive ) { + // Setter Primitive + if( isPointer ) { + // Setter Primitive Pointer + final String msg = "SKIP setter for primitive-pointer type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString(); + javaWriter.println(" // "+msg); + System.err.println("INFO: "+msg); + } else { + // Setter Primitive Array + if( hasSingleElement ) { + generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" accessor.set" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], val);"); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + } else { + generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + val.length \"+val.length+\" > array-length \"+arrayLength); };"); + javaWriter.println(" final int elemSize = Buffers.SIZEOF_"+baseJElemTypeNameU+";"); + javaWriter.println(" final ByteBuffer destB = getBuffer();"); + javaWriter.println(" final int bTotal = arrayLength * elemSize;"); + javaWriter.println(" if( bTotal > "+fieldName+"_size[mdIdx] ) { throw new IndexOutOfBoundsException(\"bTotal \"+bTotal+\" > size \"+"+fieldName+"_size[mdIdx]+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" int bOffset = "+fieldName+"_offset[mdIdx];"); + javaWriter.println(" final int bLimes = bOffset + bTotal;"); + javaWriter.println(" if( bLimes > destB.limit() ) { throw new IndexOutOfBoundsException(\"bLimes \"+bLimes+\" > buffer.limit \"+destB.limit()+\", elemOff \"+bOffset+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" bOffset += elemSize * offset;"); + javaWriter.println(" accessor.set" + baseJElemTypeNameC + "sAt(bOffset, val);"); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + } + } + } else { + // Setter Struct + if( isPointer ) { + // Setter Struct Pointer + final String msg = "SKIP setter for complex-pointer type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString(); + javaWriter.println(" // "+msg); + System.err.println("INFO: "+msg); + } else { + // Setter Struct Array + if( hasSingleElement ) { + generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int elemSize = "+baseJElemTypeName+".size();"); + javaWriter.println(" final ByteBuffer destB = getBuffer();"); + javaWriter.println(" if( elemSize > "+fieldName+"_size[mdIdx] ) { throw new IndexOutOfBoundsException(\"elemSize \"+elemSize+\" > size \"+"+fieldName+"_size[mdIdx]); };"); + javaWriter.println(" int bOffset = "+fieldName+"_offset[mdIdx];"); + javaWriter.println(" final int bLimes = bOffset + elemSize;"); + javaWriter.println(" if( bLimes > destB.limit() ) { throw new IndexOutOfBoundsException(\"bLimes \"+bLimes+\" > buffer.limit \"+destB.limit()+\", elemOff \"+bOffset+\", elemSize \"+elemSize); };"); + javaWriter.println(" final ByteBuffer sourceB = val.getBuffer();"); + javaWriter.println(" for(int f=0; f<elemSize; f++) {"); + javaWriter.println(" if( bOffset >= bLimes ) { throw new IndexOutOfBoundsException(\"elem-byte[0][\"+f+\"]: bOffset \"+bOffset+\" >= bLimes \"+bLimes+\", elemSize \"+elemSize); };"); + javaWriter.println(" destB.put(bOffset++, sourceB.get(f));"); + javaWriter.println(" }"); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + } else { + generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + val.length \"+val.length+\" > array-length \"+arrayLength); };"); + javaWriter.println(" final int elemSize = "+baseJElemTypeName+".size();"); + javaWriter.println(" final ByteBuffer destB = getBuffer();"); + javaWriter.println(" final int bTotal = arrayLength * elemSize;"); + javaWriter.println(" if( bTotal > "+fieldName+"_size[mdIdx] ) { throw new IndexOutOfBoundsException(\"bTotal \"+bTotal+\" > size \"+"+fieldName+"_size[mdIdx]+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" int bOffset = "+fieldName+"_offset[mdIdx];"); + javaWriter.println(" final int bLimes = bOffset + bTotal;"); + javaWriter.println(" if( bLimes > destB.limit() ) { throw new IndexOutOfBoundsException(\"bLimes \"+bLimes+\" > buffer.limit \"+destB.limit()+\", elemOff \"+bOffset+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" bOffset += elemSize * offset;"); + javaWriter.println(" for(int index=0; index<val.length; index++) {"); + javaWriter.println(" final ByteBuffer sourceB = val[index].getBuffer();"); + javaWriter.println(" for(int f=0; f<elemSize; f++) {"); + javaWriter.println(" if( bOffset >= bLimes ) { throw new IndexOutOfBoundsException(\"elem-byte[\"+(offset+index)+\"][\"+f+\"]: bOffset \"+bOffset+\" >= bLimes \"+bLimes+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" destB.put(bOffset++, sourceB.get(f));"); + javaWriter.println(" }"); + javaWriter.println(" }"); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + javaWriter.println(); + generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int index", baseJElemTypeName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" final int elemSize = "+baseJElemTypeName+".size();"); + javaWriter.println(" final ByteBuffer destB = getBuffer();"); + javaWriter.println(" final int bTotal = arrayLength * elemSize;"); + javaWriter.println(" if( bTotal > "+fieldName+"_size[mdIdx] ) { throw new IndexOutOfBoundsException(\"bTotal \"+bTotal+\" > size \"+"+fieldName+"_size[mdIdx]+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" int bOffset = "+fieldName+"_offset[mdIdx];"); + javaWriter.println(" final int bLimes = bOffset + bTotal;"); + javaWriter.println(" if( bLimes > destB.limit() ) { throw new IndexOutOfBoundsException(\"bLimes \"+bLimes+\" > buffer.limit \"+destB.limit()+\", elemOff \"+bOffset+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" bOffset += elemSize * index;"); + javaWriter.println(" final ByteBuffer sourceB = val.getBuffer();"); + javaWriter.println(" for(int f=0; f<elemSize; f++) {"); + javaWriter.println(" if( bOffset >= bLimes ) { throw new IndexOutOfBoundsException(\"elem-byte[\"+index+\"][\"+f+\"]: bOffset \"+bOffset+\" >= bLimes \"+bLimes+\", elemSize \"+elemSize+\" * \"+arrayLength); };"); + javaWriter.println(" destB.put(bOffset++, sourceB.get(f));"); + javaWriter.println(" }"); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + } + } + } + } + // Getter + javaWriter.println(); + if( isPrimitive ) { + // Getter Primitive + if( isPointer ) { + // Getter Primitive Pointer + final FunctionType ft = new FunctionType(dummyFuncTypeName, SizeThunk.POINTER, fieldType, 0); + ft.addArgument(containingCType.getCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST), + CMethodBindingEmitter.cThisArgumentName()); + ft.addArgument(int32Type, nativeArrayLengthArg); + final FunctionSymbol fs = new FunctionSymbol("get"+capitalFieldName, ft); + jniWriter.println(); + jniWriter.print("static "+fs.toString()); + jniWriter.println("{"); + jniWriter.println(" return "+CMethodBindingEmitter.cThisArgumentName()+"->"+field.getName()+";"); + jniWriter.println("}"); + jniWriter.println(); + generateArrayPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName, + containingCType, containingJType, i, fs, returnSizeLookupName, arrayLengthExpr, nativeArrayLengthArg); + javaWriter.println(); + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeNameC+"Buffer", capitalFieldName, null, arrayLengthExpr); + javaWriter.println(" {"); + if( useGetCStringLength ) { + javaWriter.println(" final int arrayLength = get"+capitalFieldName+"ArrayLength();"); + } else { + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + } + javaWriter.println(" final ByteBuffer _res = get"+capitalFieldName+"0(getBuffer(), arrayLength);"); + javaWriter.println(" if (_res == null) return null;"); + javaWriter.print(" return Buffers.nativeOrder(_res)"); + if( !isByteBuffer ) { + javaWriter.print(".as"+baseJElemTypeNameC+"Buffer()"); + } + javaWriter.println(";"); + javaWriter.println(" }"); + if( isString && isByteBuffer ) { + javaWriter.println(); + generateGetterSignature(javaWriter, fieldType, false, "String", capitalFieldName+"AsString", null, arrayLengthExpr); + javaWriter.println(" {"); + if( useGetCStringLength ) { + javaWriter.println(" final int arrayLength = get"+capitalFieldName+"ArrayLength();"); + } else { + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + } + javaWriter.println(" final ByteBuffer bb = get"+capitalFieldName+"0(getBuffer(), arrayLength);"); + javaWriter.println(" if (bb == null) return null;"); + javaWriter.println(" final byte[] ba = new byte[arrayLength];"); + javaWriter.println(" int i = -1;"); + javaWriter.println(" while( ++i < arrayLength ) {"); + javaWriter.println(" ba[i] = bb.get(i);"); + javaWriter.println(" if( (byte)0 == ba[i] ) break;"); + javaWriter.println(" }"); + javaWriter.println(" return new String(ba, 0, i);"); + javaWriter.println(" }"); + } + if( useGetCStringLength ) { + javaWriter.println(); + generateGetterSignature(javaWriter, fieldType, false, "final int", capitalFieldName+"ArrayLength", null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final long pString = PointerBuffer.wrap( accessor.slice(" + fieldName+"_offset[mdIdx], PointerBuffer.ELEMENT_SIZE) ).get(0);"); + javaWriter.println(" return "+arrayLengthExpr+";"); + javaWriter.println(" }"); + } + } else { + // Getter Primitive Array + if( hasSingleElement ) { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" return accessor.get" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx]);"); + javaWriter.println(" }"); + javaWriter.println(); + } else { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeNameC+"Buffer", capitalFieldName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.print(" return accessor.slice(" + fieldName+"_offset[mdIdx], Buffers.SIZEOF_"+baseJElemTypeNameU+" * "+arrayLengthExpr+")"); + if( !isByteBuffer ) { + javaWriter.print(".as"+baseJElemTypeNameC+"Buffer()"); + } + javaWriter.println(";"); + javaWriter.println(" }"); + javaWriter.println(); + if( isString && isByteBuffer ) { + generateGetterSignature(javaWriter, fieldType, false, "String", capitalFieldName+"AsString", null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int offset = " + fieldName+"_offset[mdIdx];"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" final ByteBuffer bb = getBuffer();"); + javaWriter.println(" final byte[] ba = new byte[arrayLength];"); + javaWriter.println(" int i = -1;"); + javaWriter.println(" while( ++i < arrayLength ) {"); + javaWriter.println(" ba[i] = bb.get(offset+i);"); + javaWriter.println(" if( (byte)0 == ba[i] ) break;"); + javaWriter.println(" }"); + javaWriter.println(" return new String(ba, 0, i);"); + javaWriter.println(" }"); + } else { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };"); + javaWriter.println(" return accessor.get" + baseJElemTypeNameC + "sAt(" + fieldName+"_offset[mdIdx] + (Buffers.SIZEOF_"+baseJElemTypeNameU+" * offset), result);"); + javaWriter.println(" }"); + javaWriter.println(); + } + } + } + } else { + // Getter Struct + if( isPointer ) { + // Getter Struct Pointer + final FunctionType ft = new FunctionType(dummyFuncTypeName, SizeThunk.POINTER, fieldType, 0); + ft.addArgument(containingCType.getCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST), + CMethodBindingEmitter.cThisArgumentName()); + ft.addArgument(int32Type, nativeArrayElemOffsetArg); + final FunctionSymbol fs = new FunctionSymbol("get"+capitalFieldName, ft); + jniWriter.println(); + jniWriter.print("static "+fs.toString()); + jniWriter.println("{"); + jniWriter.println(" return "+CMethodBindingEmitter.cThisArgumentName()+"->"+field.getName()+"+"+nativeArrayElemOffsetArg+";"); + jniWriter.println("}"); + jniWriter.println(); + generateArrayPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName, + containingCType, containingJType, i, fs, returnSizeLookupName, arrayLengthExpr, nativeArrayLengthONE); + javaWriter.println(); + if( hasSingleElement ) { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final ByteBuffer source = getBuffer();"); + javaWriter.println(" final ByteBuffer _res = get"+capitalFieldName+"0(source, 0);"); + javaWriter.println(" if (_res == null) return null;"); + javaWriter.println(" return "+baseJElemTypeName+".create(_res);"); + javaWriter.println(" }"); + } else { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };"); + javaWriter.println(" final ByteBuffer source = getBuffer();"); + javaWriter.println(" for(int index=0; index<result.length; index++) {"); + javaWriter.println(" final ByteBuffer _res = get"+capitalFieldName+"0(source, offset+index);"); + javaWriter.println(" if (_res == null) return null;"); + javaWriter.println(" result[index] = "+baseJElemTypeName+".create(_res);"); + javaWriter.println(" }"); + javaWriter.println(" return result;"); + javaWriter.println(" }"); + } + } else { + // Getter Struct Array + if( hasSingleElement ) { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" return "+baseJElemTypeName+".create(accessor.slice("+fieldName+"_offset[mdIdx], "+baseJElemTypeName+".size()));"); + javaWriter.println(" }"); + } else { + generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr); + javaWriter.println(" {"); + javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";"); + javaWriter.println(" if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };"); + javaWriter.println(" final int elemSize = "+baseJElemTypeName+".size();"); + javaWriter.println(" int bOffset = "+fieldName+"_offset[mdIdx] + ( elemSize * offset );"); + javaWriter.println(" for(int index=0; index<result.length; index++) {"); + javaWriter.println(" result[index] = "+baseJElemTypeName+".create(accessor.slice(bOffset, elemSize));"); + javaWriter.println(" bOffset += elemSize;"); + javaWriter.println(" }"); + javaWriter.println(" return result;"); + javaWriter.println(" }"); + } + } + } + } + + private static final boolean DEBUG_TYPEC2JAVA = false; + private JavaType typeToJavaType(final Type cType, final MachineDescription curMachDesc) { + final JavaType jt = typeToJavaTypeImpl(cType, curMachDesc); + if( DEBUG_TYPEC2JAVA ) { + System.err.println("typeToJavaType: "+cType.getDebugString()+" -> "+jt.getDebugString()); + } + return jt; + } + private boolean isJNIEnvPointer(final Type cType) { + final PointerType opt = cType.asPointer(); + return (opt != null) && + (opt.getTargetType().getName() != null) && + (opt.getTargetType().getName().equals("JNIEnv")); + } + private JavaType typeToJavaTypeImpl(final Type cType, final MachineDescription curMachDesc) { // Recognize JNIEnv* case up front - PointerType opt = cType.asPointer(); - if ((opt != null) && - (opt.getTargetType().getName() != null) && - (opt.getTargetType().getName().equals("JNIEnv"))) { - return JavaType.createForJNIEnv(); + if( isJNIEnvPointer(cType) ) { + return JavaType.createForJNIEnv(); } - Type t = cType; - // Opaque specifications override automatic conversions // in case the identity is being used .. not if ptr-ptr - TypeInfo info = cfg.typeInfo(t, typedefDictionary); + final TypeInfo info = cfg.typeInfo(cType, typedefDictionary); if (info != null) { boolean isPointerPointer = false; - if (t.pointerDepth() > 0 || t.arrayDimension() > 0) { + if (cType.pointerDepth() > 0 || cType.arrayDimension() > 0) { Type targetType; // target type - if (t.isPointer()) { + if (cType.isPointer()) { // t is <type>*, we need to get <type> - targetType = t.asPointer().getTargetType(); + targetType = cType.asPointer().getTargetType(); } else { // t is <type>[], we need to get <type> - targetType = t.asArray().getBaseElementType(); + targetType = cType.asArray().getBaseElementType(); } - if (t.pointerDepth() == 2 || t.arrayDimension() == 2) { + if (cType.pointerDepth() == 2 || cType.arrayDimension() == 2) { // Get the target type of the target type (targetType was computer earlier // as to be a pointer to the target type, so now we need to get its // target type) @@ -1369,7 +1953,9 @@ public class JavaEmitter implements GlueEmitter { // t is<type>**, targetType is <type>*, we need to get <type> Type bottomType = targetType.asPointer().getTargetType(); - LOG.log(INFO, "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr", new Object[]{t, targetType, bottomType}); + if( GlueGen.debug() ) { + LOG.log(INFO, "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr", new Object[]{cType.getDebugString(), targetType, bottomType}); + } } } } @@ -1378,35 +1964,35 @@ public class JavaEmitter implements GlueEmitter { } } - if (t.isInt() || t.isEnum()) { - switch ((int) t.getSize(curMachDesc)) { + if (cType.isInt() || cType.isEnum()) { + switch ((int) cType.getSize(curMachDesc)) { case 1: return javaType(Byte.TYPE); case 2: return javaType(Short.TYPE); case 4: return javaType(Integer.TYPE); case 8: return javaType(Long.TYPE); default: throw new RuntimeException("Unknown integer type of size " + - t.getSize(curMachDesc) + " and name " + t.getName()); + cType.getSize(curMachDesc) + " and name " + cType.getName()); } - } else if (t.isFloat()) { + } else if (cType.isFloat()) { return javaType(Float.TYPE); - } else if (t.isDouble()) { + } else if (cType.isDouble()) { return javaType(Double.TYPE); - } else if (t.isVoid()) { + } else if (cType.isVoid()) { return javaType(Void.TYPE); - } else if (t.pointerDepth() > 0 || t.arrayDimension() > 0) { + } else if (cType.pointerDepth() > 0 || cType.arrayDimension() > 0) { Type targetType; // target type - if (t.isPointer()) { + if (cType.isPointer()) { // t is <type>*, we need to get <type> - targetType = t.asPointer().getTargetType(); + targetType = cType.asPointer().getTargetType(); } else { // t is <type>[], we need to get <type> - targetType = t.asArray().getBaseElementType(); + targetType = cType.asArray().getBaseElementType(); } // Handle Types of form pointer-to-type or array-of-type, like // char* or int[]; these are expanded out into Java primitive // arrays, NIO buffers, or both in expandMethodBinding - if (t.pointerDepth() == 1 || t.arrayDimension() == 1) { + if (cType.pointerDepth() == 1 || cType.arrayDimension() == 1) { if (targetType.isVoid()) { return JavaType.createForCVoidPointer(); } else if (targetType.isInt()) { @@ -1421,39 +2007,39 @@ public class JavaEmitter implements GlueEmitter { case 4: return JavaType.createForCInt32Pointer(); case 8: return JavaType.createForCInt64Pointer(); default: throw new RuntimeException("Unknown integer array type of size " + - t.getSize(curMachDesc) + " and name " + t.getName()); + cType.getSize(curMachDesc) + " and name " + cType.getName()+", "+cType.getDebugString()); } } else if (targetType.isFloat()) { return JavaType.createForCFloatPointer(); } else if (targetType.isDouble()) { return JavaType.createForCDoublePointer(); } else if (targetType.isCompound()) { - if (t.isArray()) { // FIXME: Compound and Compound-Arrays + if (cType.isArray()) { // FIXME: Compound and Compound-Arrays return JavaType.createForCArray(targetType); } // Special cases for known JNI types (in particular for converting jawt.h) - if (t.getName() != null && - t.getName().equals("jobject")) { + if (cType.getName() != null && + cType.getName().equals("jobject")) { return javaType(java.lang.Object.class); } String name = targetType.getName(); if (name == null) { // Try containing pointer type for any typedefs - name = t.getName(); + name = cType.getName(); if (name == null) { - throw new RuntimeException("Couldn't find a proper type name for pointer type " + t); + throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString()); } } return JavaType.createForCStruct(cfg.renameJavaType(name)); } else { throw new RuntimeException("Don't know how to convert pointer/array type \"" + - t + "\""); + cType.getDebugString() + "\""); } } // Handle Types of form pointer-to-pointer-to-type or // array-of-arrays-of-type, like char** or int[][] - else if (t.pointerDepth() == 2 || t.arrayDimension() == 2) { + else if (cType.pointerDepth() == 2 || cType.arrayDimension() == 2) { // Get the target type of the target type (targetType was computer earlier // as to be a pointer to the target type, so now we need to get its // target type) @@ -1461,11 +2047,21 @@ public class JavaEmitter implements GlueEmitter { if (targetType.isPointer()) { // t is<type>**, targetType is <type>*, we need to get <type> bottomType = targetType.asPointer().getTargetType(); + if( GlueGen.debug() ) { + LOG.log(INFO, "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType}); + } return JavaType.forNIOPointerBufferClass(); - } else { + } else if(targetType.isArray()) { // t is<type>[][], targetType is <type>[], we need to get <type> bottomType = targetType.asArray().getBaseElementType(); - LOG.log(WARNING, "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2} -> Unhandled!", new Object[]{t, targetType, bottomType}); + if( GlueGen.debug() ) { + LOG.log(INFO, "typeToJavaType(ptr-ptr.array): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType}); + } + } else { + bottomType = targetType; + if( GlueGen.debug() ) { + LOG.log(INFO, "typeToJavaType(ptr-ptr.primitive): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType}); + } } // Warning: The below code is not backed up by an implementation, @@ -1479,14 +2075,14 @@ public class JavaEmitter implements GlueEmitter { case 4: return javaType(ArrayTypes.intBufferArrayClass); case 8: return javaType(ArrayTypes.longBufferArrayClass); default: throw new RuntimeException("Unknown two-dimensional integer array type of element size " + - bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()); + bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()+", "+bottomType.getDebugString()); } } else if (bottomType.isFloat()) { return javaType(ArrayTypes.floatBufferArrayClass); } else if (bottomType.isDouble()) { return javaType(ArrayTypes.doubleBufferArrayClass); } else { - throw new RuntimeException("Unexpected primitive type " + bottomType.getName() + + throw new RuntimeException("Unexpected primitive type " + bottomType.getDebugString() + " in two-dimensional array"); } } else if (bottomType.isVoid()) { @@ -1497,7 +2093,7 @@ public class JavaEmitter implements GlueEmitter { return JavaType.createForCArray(bottomType); } else { throw new RuntimeException( - "Could not convert C type \"" + t + "\" " + + "Could not convert C type \"" + cType.getDebugString() + "\" " + "to appropriate Java type; need to add more support for " + "depth=2 pointer/array types [debug info: targetType=\"" + targetType + "\"]"); @@ -1505,23 +2101,23 @@ public class JavaEmitter implements GlueEmitter { } else { // can't handle this type of pointer/array argument throw new RuntimeException( - "Could not convert C pointer/array \"" + t + "\" to " + + "Could not convert C pointer/array \"" + cType.getDebugString() + "\" to " + "appropriate Java type; types with pointer/array depth " + "greater than 2 are not yet supported [debug info: " + - "pointerDepth=" + t.pointerDepth() + " arrayDimension=" + - t.arrayDimension() + " targetType=\"" + targetType + "\"]"); + "pointerDepth=" + cType.pointerDepth() + " arrayDimension=" + + cType.arrayDimension() + " targetType=\"" + targetType + "\"]"); } - } else if(t.isCompound() ) { // FIXME: Compound and Compound-Arrays - final String name = t.getName(); + } else if(cType.isCompound() ) { // FIXME: Compound and Compound-Arrays + final String name = cType.getName(); if (name == null) { - throw new RuntimeException("Couldn't find a proper type name for pointer type " + t); + throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString()); } return JavaType.createForCStruct(cfg.renameJavaType(name)); } else { throw new RuntimeException( - "Could not convert C type \"" + t + "\" (class " + - t.getClass().getName() + ") to appropriate Java type"); + "Could not convert C type \"" + cType.getDebugString() + "\" (class " + + cType.getClass().getName() + ") to appropriate Java type"); } } @@ -1897,6 +2493,10 @@ public class JavaEmitter implements GlueEmitter { cWriter.println(" return _initClazzAccess(env);"); cWriter.println("}"); cWriter.println(); + cWriter.println("JNIEXPORT jint JNICALL "+JavaEmitter.getJNIMethodNamePrefix(packageName, className)+"_getCStringLengthImpl(JNIEnv *env, jclass _unused, jlong pString) {"); + cWriter.println(" return 0 != pString ? strlen((const char*)(intptr_t)pString) : 0;"); + cWriter.println("}"); + cWriter.println(); } } @@ -1905,6 +2505,9 @@ public class JavaEmitter implements GlueEmitter { jWriter.println(); jWriter.println(" private static native boolean initializeImpl();"); jWriter.println(); + jWriter.println(); + jWriter.println(" private static native int getCStringLengthImpl(final long pString);"); + jWriter.println(); if( !cfg.manualStaticInitCall(className) ) { jWriter.println(staticClassInitCallJavaCode); } @@ -1958,7 +2561,7 @@ public class JavaEmitter implements GlueEmitter { } binding.setJavaReturnType(javaType(java.lang.String.class)); } else { - binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), false, curMachDesc)); + binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), curMachDesc)); } // System.out.println("bindFunction(1) "+binding.getJavaReturnType()); @@ -1969,7 +2572,7 @@ public class JavaEmitter implements GlueEmitter { for (int i = 0; i < sym.getNumArguments(); i++) { Type cArgType = sym.getArgumentType(i); - JavaType mappedType = typeToJavaType(cArgType, true, curMachDesc); + JavaType mappedType = typeToJavaType(cArgType, curMachDesc); // System.out.println("C arg type -> \"" + cArgType + "\"" ); // System.out.println(" Java -> \"" + mappedType + "\"" ); @@ -2147,5 +2750,4 @@ public class JavaEmitter implements GlueEmitter { private final String capitalizeString(String string) { return Character.toUpperCase(string.charAt(0)) + string.substring(1); } - } diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java index c651114..ea7910a 100644 --- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java @@ -41,9 +41,7 @@ package com.jogamp.gluegen; import com.jogamp.gluegen.cgram.HeaderParser; import com.jogamp.gluegen.cgram.types.ArrayType; -import com.jogamp.gluegen.cgram.types.CompoundType; import com.jogamp.gluegen.cgram.types.EnumType; -import com.jogamp.gluegen.cgram.types.PointerType; import com.jogamp.gluegen.cgram.types.Type; import java.io.PrintWriter; @@ -93,6 +91,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { // incoming Java arguments as parameters and computing as an int the // number of elements of the returned array. private String returnedArrayLengthExpression; + private boolean returnedArrayLengthExpressionOnlyForComments = false; // A suffix used to create a temporary outgoing array of Buffers to // represent an array of compound type wrappers @@ -154,6 +153,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { prologue = arg.prologue; epilogue = arg.epilogue; returnedArrayLengthExpression = arg.returnedArrayLengthExpression; + returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments; cfg = arg.cfg; } @@ -192,6 +192,17 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { arguments. */ public void setReturnedArrayLengthExpression(String expr) { returnedArrayLengthExpression = expr; + returnedArrayLengthExpressionOnlyForComments = false; + } + protected void setReturnedArrayLengthExpression(String expr, boolean onlyForComments) { + returnedArrayLengthExpression = expr; + returnedArrayLengthExpressionOnlyForComments = onlyForComments; + } + protected String getReturnedArrayLengthExpression() { + return returnedArrayLengthExpressionOnlyForComments ? null : returnedArrayLengthExpression; + } + protected String getReturnedArrayLengthComment() { + return returnedArrayLengthExpression; } /** Sets the manually-generated prologue code for this emitter. */ @@ -278,6 +289,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { } } String name = type.getName(); + if( null == name ) { + throw new IllegalArgumentException("null type name: "+type.getDebugString()); + } int index = name.lastIndexOf('.')+1; // always >= 0 name = name.substring(index); @@ -389,7 +403,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { return byteOffsetArgName(getArgumentName(i)); } - protected String byteOffsetArgName(String s) { + protected static String byteOffsetArgName(String s) { return s + "_byte_offset"; } @@ -715,38 +729,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { JavaType returnType = binding.getJavaReturnType(); if (returnType.isCompoundTypeWrapper()) { - String fmt = getReturnedArrayLengthExpression(); + // Details are handled in JavaEmitter's struct handling! writer.println(" if (_res == null) return null;"); - if (fmt == null) { - writer.print(" return " + returnType.getName() + ".create(Buffers.nativeOrder(_res))"); - } else { - writer.println(" Buffers.nativeOrder(_res);"); - String expr = new MessageFormat(fmt).format(argumentNameArray()); - PointerType cReturnTypePointer = binding.getCReturnType().asPointer(); - CompoundType cReturnType = null; - if (cReturnTypePointer != null) { - cReturnType = cReturnTypePointer.getTargetType().asCompound(); - } - if (cReturnType == null) { - throw new RuntimeException("ReturnedArrayLength directive currently only supported for pointers to compound types " + - "(error occurred while generating Java glue code for " + getName() + ")"); - } - writer.println(" final " + getReturnTypeString(false) + " _retarray = new " + getReturnTypeString(true) + "[" + expr + "];"); - writer.println(" for (int _count = 0; _count < " + expr + "; _count++) {"); - // Create temporary ByteBuffer slice - // FIXME: probably need Type.getAlignedSize() for arrays of - // compound types (rounding up to machine-dependent alignment) - writer.println(" _res.position(_count * " + getReturnTypeString(true) + ".size());"); - writer.println(" _res.limit ((1 + _count) * " + getReturnTypeString(true) + ".size());"); - writer.println(" final ByteBuffer _tmp = _res.slice();"); - writer.println(" Buffers.nativeOrder(_tmp);"); - writer.println(" _res.position(0);"); - writer.println(" _res.limit(_res.capacity());"); - writer.println(" _retarray[_count] = " + getReturnTypeString(true) + ".create(_tmp);"); - writer.println(" }"); - writer.print (" return _retarray"); - } - writer.println(";"); + writer.println(" return " + returnType.getName() + ".create(Buffers.nativeOrder(_res));"); } else if (returnType.isNIOBuffer()) { writer.println(" if (_res == null) return null;"); writer.println(" Buffers.nativeOrder(_res);"); @@ -821,10 +806,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { @Override protected String getBaseIndentString() { return " "; } - protected String getReturnedArrayLengthExpression() { - return returnedArrayLengthExpression; - } - /** * Class that emits a generic comment for JavaMethodBindingEmitters; the comment * includes the C signature of the native method that is being bound by the @@ -835,6 +816,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { public void emit(FunctionEmitter emitter, PrintWriter writer) { emitBeginning(emitter, writer); emitBindingCSignature(((JavaMethodBindingEmitter)emitter).getBinding(), writer); + final String arrayLengthExpr = getReturnedArrayLengthComment(); + if( null != arrayLengthExpr ) { + writer.print(", covering an array of length <code>"+arrayLengthExpr+"</code>"); + } emitEnding(emitter, writer); } protected void emitBeginning(FunctionEmitter emitter, PrintWriter writer) { @@ -889,8 +874,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { protected class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { @Override - protected void emitBeginning(FunctionEmitter emitter, - PrintWriter writer) { + protected void emitBeginning(FunctionEmitter emitter, 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 a1cbb01..9091588 100644 --- a/src/java/com/jogamp/gluegen/JavaType.java +++ b/src/java/com/jogamp/gluegen/JavaType.java @@ -60,7 +60,7 @@ public class JavaType { } private final Class<?> clazz; // Primitive types and other types representable as Class objects - private final String name; // Types we're generating glue code for (i.e., C structs) + private final String structName; // Types we're generating glue code for (i.e., C structs) private final Type elementType; // Element type if this JavaType represents a C array private final C_PTR primitivePointerType; @@ -82,8 +82,8 @@ public class JavaType { JavaType t = (JavaType) arg; return (this == t || (t.clazz == clazz && - ((name == null ? t.name == null : name.equals(t.name)) || - ((name != null) && (t.name != null) && (name.equals(t.name)))) && + ((structName == null ? t.structName == null : structName.equals(t.structName)) || + ((structName != null) && (t.structName != null) && (structName.equals(t.structName)))) && ((elementType == t.elementType) || (elementType != null) && (t.elementType != null) && (elementType.equals(t.elementType))) && (primitivePointerType == t.primitivePointerType))); @@ -92,10 +92,10 @@ public class JavaType { @Override public int hashCode() { if (clazz == null) { - if (name == null) { + if (structName == null) { return 0; } - return name.hashCode(); + return structName.hashCode(); } return clazz.hashCode(); } @@ -245,7 +245,7 @@ public class JavaType { if (elementType != null) { return elementType.getName(); } - return name; + return structName; } /** @@ -261,11 +261,14 @@ public class JavaType { } if (elementType != null) { if(elementType.getName()==null) { - throw new RuntimeException("elementType.name is null: "+getDumpString()); + throw new RuntimeException("elementType.name is null: "+getDebugString()); } return "[" + descriptor(elementType.getName()); } - return descriptor(name); + if( null != structName ) { + return descriptor(structName); + } + return "ANON_NIO"; } /** Returns the String corresponding to the JNI type for this type, @@ -432,7 +435,7 @@ public class JavaType { } public boolean isCompoundTypeWrapper() { - return (clazz == null && name != null && !isJNIEnv()); + return (clazz == null && structName != null && !isJNIEnv()); } public boolean isArrayOfCompoundTypeWrappers() { @@ -473,12 +476,12 @@ public class JavaType { } public boolean isJNIEnv() { - return clazz == null && "JNIEnv".equals(name); + return clazz == null && "JNIEnv".equals(structName); } @Override public Object clone() { - return new JavaType(primitivePointerType, clazz, name, elementType); + return new JavaType(primitivePointerType, clazz, structName, elementType); } @Override @@ -497,16 +500,27 @@ public class JavaType { sb.append(val); } // For debugging - public String getDumpString() { + public String getDebugString() { final StringBuilder sb = new StringBuilder(); - sb.append("JavaType["); + sb.append("JType["); boolean prepComma = false; + { + final String javaTypeName = getName(); + if( null != javaTypeName ) { + append(sb, javaTypeName, false); + } else { + append(sb, "ANON", false); + } + sb.append(" / "); + if( null != structName ) { + append(sb, "'"+structName+"'", prepComma); prepComma=true; + } else { + append(sb, "NIL", prepComma); prepComma=true; + } + } if( null != clazz ) { append(sb, "clazz = "+clazz.getName(), prepComma); prepComma=true; } - if( null != name ) { - append(sb, "name = "+name, prepComma); prepComma=true; - } if( null != elementType ) { append(sb, "elementType = "+elementType, prepComma); prepComma=true; } @@ -523,6 +537,15 @@ public class JavaType { if( isCompoundTypeWrapper() ) { append(sb, "compound", prepComma); prepComma=true; } + if( isArray() ) { + append(sb, "array", prepComma); prepComma=true; + } + if( isPrimitive() ) { + append(sb, "primitive", prepComma); prepComma=true; + } + if( isPrimitiveArray() ) { + append(sb, "primitiveArray", prepComma); prepComma=true; + } if( isNIOBuffer() ) { append(sb, "nioBuffer", prepComma); prepComma=true; } @@ -532,7 +555,7 @@ public class JavaType { if( isCPrimitivePointerType() ) { append(sb, "C-Primitive-Pointer", prepComma); prepComma=true; } - sb.append("]]"); + append(sb, "descriptor '"+getDescriptor()+"'", prepComma); prepComma=true; return sb.toString(); } @@ -543,15 +566,15 @@ public class JavaType { private JavaType(Class<?> clazz) { this.primitivePointerType = null; this.clazz = clazz; - this.name = null; + this.structName = null; this.elementType = null; } /** Constructs a type representing a named C struct. */ - private JavaType(String name) { + private JavaType(String structName) { this.primitivePointerType = null; this.clazz = null; - this.name = name; + this.structName = structName; this.elementType = null; } @@ -560,7 +583,7 @@ public class JavaType { private JavaType(C_PTR primitivePointerType) { this.primitivePointerType = primitivePointerType; this.clazz = null; - this.name = null; + this.structName = null; this.elementType = null; } @@ -568,14 +591,15 @@ public class JavaType { private JavaType(Type elementType) { this.primitivePointerType = null; this.clazz = null; - this.name = null; + this.structName = null; this.elementType = elementType; } + /** clone only */ private JavaType(C_PTR primitivePointerType, Class<?> clazz, String name, Type elementType) { this.primitivePointerType = primitivePointerType; this.clazz = clazz; - this.name = name; + this.structName = name; this.elementType = elementType; } diff --git a/src/java/com/jogamp/gluegen/MethodBinding.java b/src/java/com/jogamp/gluegen/MethodBinding.java index 61732fb..53f6c7d 100644 --- a/src/java/com/jogamp/gluegen/MethodBinding.java +++ b/src/java/com/jogamp/gluegen/MethodBinding.java @@ -436,8 +436,16 @@ public class MethodBinding { computedSignatureProperties = true; } - /** Indicates whether this MethodBinding is for a function pointer - contained in a struct. */ + /** + * Indicates whether this MethodBinding is for a function pointer + * contained in a struct, or to access array- or pointer-data from a struct. + * <p> + * The native calling convention, i.e. via a 'this' function pointer + * or by a static native function must be decided in the + * {@link JavaEmitter} handling structs and + * passed to the {@link CMethodBindingEmitter#setIsCStructFunctionPointer(boolean)}. + * </p> + */ public boolean hasContainingType() { return (getContainingType() != null); } diff --git a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java index 678fa10..401944b 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java @@ -72,8 +72,7 @@ public class ArrayType extends MemoryLayoutType implements Cloneable { // names during parsing // Note: don't think cvAttributes can be set for array types (unlike pointer types) if (computedName == null) { - computedName = elementType.getName() + " *"; - computedName = computedName.intern(); + computedName = (elementType.getName() + " *").intern(); } return computedName; } @@ -85,14 +84,14 @@ public class ArrayType extends MemoryLayoutType implements Cloneable { public int getLength() { return length; } public boolean hasLength() { return length >= 0; } - /** Return the bottommost element type if this is a multidimensional - array. */ + @Override public Type getBaseElementType() { ArrayType t = this; while (t.getElementType().isArray()) { t = t.getElementType().asArray(); } return t.getElementType(); + // return elementType.getBaseElementType(); } /** Recompute the size of this array if necessary. This needs to be diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java index 70fbc64..7672744 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java @@ -126,19 +126,16 @@ public class FunctionType extends Type implements Cloneable { return toString(null); } - public String toString(String functionName) { + public String toString(final String functionName) { return toString(functionName, false); } - public String toString(String functionName, boolean emitNativeTag) { + public String toString(final String functionName, final boolean emitNativeTag) { return toString(functionName, null, emitNativeTag, false); } - String toString(String functionName, String callingConvention, boolean emitNativeTag, boolean isPointer) { - StringBuilder res = new StringBuilder(); - if(isConst()) { - res.append("const "); - } + String toString(final String functionName, final String callingConvention, final boolean emitNativeTag, final boolean isPointer) { + final StringBuilder res = new StringBuilder(); res.append(getReturnType()); res.append(" "); if (isPointer) { @@ -167,17 +164,11 @@ public class FunctionType extends Type implements Cloneable { Type t = getArgumentType(i); if (t.isFunctionPointer()) { Type targetType = t.asPointer().getTargetType(); - if(targetType.isConst()) { - res.append("const "); - } FunctionType ft = targetType.asFunction(); res.append(ft.toString(getArgumentName(i), callingConvention, false, true)); } else if (t.isArray()) { res.append(t.asArray().toString(getArgumentName(i))); } else { - if(t.isConst()) { - res.append("const "); - } res.append(t); String argumentName = getArgumentName(i); if (argumentName != null) { @@ -190,9 +181,6 @@ public class FunctionType extends Type implements Cloneable { } } res.append(")"); - if (!isPointer) { - res.append(";"); - } return res.toString(); } diff --git a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java index 330d791..5f19202 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java @@ -97,8 +97,7 @@ public class PointerType extends Type implements Cloneable { // Lazy computation of name due to lazy setting of compound type // names during parsing if (computedName == null) { - computedName = targetType.getName(includeCVAttrs) + " *"; - computedName = computedName.intern(); + computedName = (targetType.getName(includeCVAttrs) + " *").intern(); } if (!includeCVAttrs) { return computedName; @@ -120,12 +119,15 @@ public class PointerType extends Type implements Cloneable { return targetType; } - public Type getLastTargetType() { + @Override + public Type getBaseElementType() { + /** if(targetType.isPointer()) { - return ((PointerType)targetType).getLastTargetType(); + return ((PointerType)targetType).getBaseElementType(); } else { return targetType; - } + } */ + return targetType.getBaseElementType(); } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java b/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java index f105f1f..dfcb722 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java +++ b/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java @@ -87,9 +87,6 @@ public class StructLayout { } else { curOffset = SizeThunk.add(curOffset, sz); } - if( GlueGen.debug() ) { - System.err.printf("SL.%02d: o %03d, s %03d, t %s: %s%n", (i+1), f.getOffset(dbgMD), ft.getSize(dbgMD), ft, f); - } } else if (ft.isCompound()) { final CompoundType ct = ft.asCompound(); if(!ct.isLayouted()) { @@ -103,9 +100,6 @@ public class StructLayout { } else { curOffset = SizeThunk.add(curOffset, sz); } - if( GlueGen.debug() ) { - System.err.printf("SL.%02d: o %03d, s %03d, t %s{%d}: %s%n", (i+1), f.getOffset(dbgMD), ft.getSize(dbgMD), ft, ct.getNumFields(), f); - } } else if (ft.isArray()) { final ArrayType arrayType = ft.asArray(); if(!arrayType.isLayouted()) { @@ -122,9 +116,6 @@ public class StructLayout { curOffset = SizeThunk.align(curOffset, sz); f.setOffset(curOffset); curOffset = SizeThunk.add(curOffset, sz); - if( GlueGen.debug() ) { - System.err.printf("SL.%02d: o %03d, s %03d, t %s: %s%n", (i+1), f.getOffset(dbgMD), ft.getSize(dbgMD), ft, f); - } } else { // FIXME String name = t.getName(); @@ -136,6 +127,9 @@ public class StructLayout { " in type " + name + ") not implemented yet"); } + if( GlueGen.debug() ) { + System.err.printf("SL.%02d: o %03d, s %03d: %s, %s%n", (i+1), f.getOffset(dbgMD), ft.getSize(dbgMD), f, ft.getDebugString()); + } } if (t.isUnion()) { t.setSize(maxSize); diff --git a/src/java/com/jogamp/gluegen/cgram/types/Type.java b/src/java/com/jogamp/gluegen/cgram/types/Type.java index a403de6..45d610d 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/Type.java +++ b/src/java/com/jogamp/gluegen/cgram/types/Type.java @@ -52,8 +52,8 @@ public abstract class Type implements Cloneable { private String name; private SizeThunk size; - private int cvAttributes; - private int typedefedCVAttributes; + private final int cvAttributes; + private int typedefedCVAttributes; private boolean hasTypedefName; protected Type(String name, SizeThunk size, int cvAttributes) { @@ -75,18 +75,96 @@ public abstract class Type implements Cloneable { /** Returns the name of this type. The returned string is suitable for use as a type specifier. Does not include any const/volatile attributes. */ - public String getName() { return getName(false); } + public final String getName() { return getName(false); } /** Returns the name of this type, optionally including const/volatile attributes. The returned string is suitable for use as a type specifier. */ - public String getName(boolean includeCVAttrs) { + public String getName(boolean includeCVAttrs) { if (!includeCVAttrs) { return name; } return getCVAttributesString() + name; } + private void append(final StringBuilder sb, final String val, final boolean prepComma) { + if( prepComma ) { + sb.append(", "); + } + sb.append(val); + } + // For debugging + public String getDebugString() { + final StringBuilder sb = new StringBuilder(); + boolean prepComma = false; + sb.append("CType["); + if( null != name ) { + append(sb, "'"+name+"'", prepComma); prepComma=true; + } else { + append(sb, "ANON", prepComma); prepComma=true; + } + if( hasTypedefName() ) { + sb.append(" (typedef)"); + } + append(sb, "size ", prepComma); prepComma=true; + if( null != size ) { + final long mdSize; + { + long _mdSize = -1; + try { + _mdSize = size.computeSize(MachineDescription.StaticConfig.X86_64_UNIX.md); + } catch (Exception e) {} + mdSize = _mdSize; + } + sb.append("[fixed ").append(size.hasFixedNativeSize()).append(", lnx64 ").append(mdSize).append("]"); + } else { + sb.append(" ZERO"); + } + append(sb, "[", prepComma); prepComma=false; + if( isConst() ) { + append(sb, "const ", false); + } + if( isVolatile() ) { + append(sb, "volatile ", false); + } + if( isPointer() ) { + append(sb, "pointer*"+pointerDepth(), prepComma); prepComma=true; + } + if( isArray() ) { + append(sb, "array*"+arrayDimension(), prepComma); prepComma=true; + } + if( isBit() ) { + append(sb, "bit", prepComma); prepComma=true; + } + if( isCompound() ) { + sb.append("struct{").append(asCompound().getNumFields()); + append(sb, "}", prepComma); prepComma=true; + } + if( isDouble() ) { + append(sb, "double", prepComma); prepComma=true; + } + if( isEnum() ) { + append(sb, "enum", prepComma); prepComma=true; + } + if( isFloat() ) { + append(sb, "float", prepComma); prepComma=true; + } + if( isFunction() ) { + append(sb, "function", prepComma); prepComma=true; + } + if( isFunctionPointer() ) { + append(sb, "funcPointer", prepComma); prepComma=true; + } + if( isInt() ) { + append(sb, "int", prepComma); prepComma=true; + } + if( isVoid() ) { + append(sb, "void", prepComma); prepComma=true; + } + sb.append("]]"); + return sb.toString(); + } + /** Set the name of this type; used for handling typedefs. */ public void setName(String name) { if (name == null) { @@ -269,6 +347,17 @@ public abstract class Type implements Cloneable { return 1 + arrayType.getElementType().arrayDimension(); } + /** + * Helper method to returns the bottom-most element type of this type. + * <p> + * If this is a multidimensional array or pointer method returns the bottom-most element type, + * otherwise this. + * </p> + */ + public Type getBaseElementType() { + return this; + } + /** Helper routine for list equality comparison */ static <C> boolean listsEqual(List<C> a, List<C> b) { return ((a == null && b == null) || (a != null && b != null && a.equals(b))); |