diff options
Diffstat (limited to 'src/java')
-rw-r--r-- | src/java/com/jogamp/common/nio/StructAccessor.java | 6 | ||||
-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 |
12 files changed, 1152 insertions, 417 deletions
diff --git a/src/java/com/jogamp/common/nio/StructAccessor.java b/src/java/com/jogamp/common/nio/StructAccessor.java index d6df083..b1593fe 100644 --- a/src/java/com/jogamp/common/nio/StructAccessor.java +++ b/src/java/com/jogamp/common/nio/StructAccessor.java @@ -117,7 +117,7 @@ public class StructAccessor { public final int getIntAt(int byteOffset, int nativeSizeInBytes) { switch(nativeSizeInBytes) { case 2: - return (int) bb.getShort(byteOffset) & 0x0000FFFF ; + return bb.getShort(byteOffset) & 0x0000FFFF ; case 4: return bb.getInt(byteOffset); case 8: @@ -137,7 +137,7 @@ public class StructAccessor { bb.putInt(byteOffset, v); break; case 8: - bb.putLong(byteOffset, (long)v & 0x00000000FFFFFFFFL ); + bb.putLong(byteOffset, v & 0x00000000FFFFFFFFL ); break; default: throw new InternalError("invalid nativeSizeInBytes "+nativeSizeInBytes); @@ -178,7 +178,7 @@ public class StructAccessor { public final long getLongAt(int byteOffset, int nativeSizeInBytes) { switch(nativeSizeInBytes) { case 4: - return (long) bb.getInt(byteOffset) & 0x00000000FFFFFFFFL; + return bb.getInt(byteOffset) & 0x00000000FFFFFFFFL; case 8: return bb.getLong(byteOffset); default: 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))); |