diff options
author | Kenneth Russel <[email protected]> | 2005-08-29 07:03:51 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2005-08-29 07:03:51 +0000 |
commit | 6737d87b266ba10a56e8975fed42805608bd37d4 (patch) | |
tree | 50b2433f44fe7b413cc58cceac9ec49f089dbd75 /src/net/java/games | |
parent | 6b9841f75655fabd491f7410643272d36eddc77e (diff) |
Restructured generation of MethodBindings and emitters to more closely
match desired new code generation style of mapping void* to Buffer and
to support non-direct Buffers. Removed expansion of void* to multiple
primitive array types. Primitive-type C pointers (such as int*) are
now exposed as IntBuffer and (optionally) int[], if NioDirectOnly has
not been specified. The int[] variant is a simple wrapper around the
indirect buffer implementation. If desired, expansion of void* to
other array types could be layered on this new support.
Rewrote and simplified expandMethodBinding and split up creation of
emitters into generatePublicEmitters and generatePrivateEmitters.
Deleted JavaMethodBindingImplEmitter and CMethodBindingImplEmitter and
folded their functionality into their superclasses, controlled under
flags, which makes it more straightforward to tweak a given emitter to
produce correct glue code. Restructured OpenGL-specific
JavaGLPAWrapperEmitter and CGLPAWrapperEmitter and how they are
created by the GLEmitter; these classes are now much simpler than
before.
Changed how data types are passed from MethodBindings to Emitters.
Generally only two MethodBindings will be created, one which maps
types like int* to IntBuffer and one which maps it to int[]. The
version taking Buffers will be the only one for which glue code will
be generated; the one taking int[] will call the native code for the
indirect buffer case for the one taking Buffers. Compound types
(representing C structs) and compound type arrays (represending arrays
of C structs) are no longer mapped to NIO ByteBuffers and arrays of
NIO ByteBuffers by the MethodBinding; erasure and lowering of types is
now handled by the Emitters, to preserve more type information during
the code generation process. It is unclear whether this is in the end
a simplification or just pushing code around, but it does help reduce
confusion over the number of MethodBindings floating around in the
system and what purpose they served.
Restructured cure JOGL code and demos to work with new APIs, in
particular new glTexImage*D, glDrawElements, and glReadPixels Buffer
arguments. Fixed performance problem in new Animator which occurred
with VertexArrayRange demo. Added new gluPickMatrix entry point to be
able to implement NIO variant in generated signatures.
Some further simplifications of the new code may be possible (i.e.,
some new flags in JavaMethodBindingEmitter and MethodBinding removed)
and it is possible more unused code remains to be deleted. As it
stands the new GL.java is significantly smaller than before, as all of
the expansions of void* to primitive arrays are gone, several areas of
GlueGen are easier to understand, and while some functionality has
been lost, the autogenerated APIs are basically in the final form
specified by JSR-231.
Tested with the JOGL demos on Windows and Linux.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JSR-231@353 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/net/java/games')
16 files changed, 1584 insertions, 2265 deletions
diff --git a/src/net/java/games/gluegen/CMethodBindingEmitter.java b/src/net/java/games/gluegen/CMethodBindingEmitter.java index 2616f151b..4a7ad1c98 100644 --- a/src/net/java/games/gluegen/CMethodBindingEmitter.java +++ b/src/net/java/games/gluegen/CMethodBindingEmitter.java @@ -57,8 +57,6 @@ public class CMethodBindingEmitter extends FunctionEmitter protected MethodBinding binding; - protected boolean indirectBufferInterface = false; - /** Name of the package in which the corresponding Java method resides.*/ private String packageName; @@ -77,6 +75,10 @@ public class CMethodBindingEmitter extends FunctionEmitter */ private boolean isJavaMethodStatic; + // Flags which change various aspects of glue code generation + protected boolean forImplementingMethodCall; + protected boolean forIndirectBufferAndArrayImplementation; + /** * Optional List of Strings containing temporary C variables to declare. */ @@ -117,11 +119,13 @@ public class CMethodBindingEmitter extends FunctionEmitter * being bound. */ public CMethodBindingEmitter(MethodBinding binding, - boolean isOverloadedBinding, + PrintWriter output, String javaPackageName, String javaClassName, + boolean isOverloadedBinding, boolean isJavaMethodStatic, - PrintWriter output) + boolean forImplementingMethodCall, + boolean forIndirectBufferAndArrayImplementation) { super(output); @@ -134,21 +138,14 @@ public class CMethodBindingEmitter extends FunctionEmitter this.className = javaClassName; this.isOverloadedBinding = isOverloadedBinding; this.isJavaMethodStatic = isJavaMethodStatic; - setCommentEmitter(defaultCommentEmitter); - } - - public final MethodBinding getBinding() { return binding; } + this.forImplementingMethodCall = forImplementingMethodCall; + this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation; - public boolean isIndirectBufferInterface() { - return indirectBufferInterface; - } - - - public void setIndirectBufferInterface(boolean indirect) { - indirectBufferInterface = indirect; + setCommentEmitter(defaultCommentEmitter); } + public final MethodBinding getBinding() { return binding; } public String getName() { return binding.getName(); @@ -164,8 +161,8 @@ public class CMethodBindingEmitter extends FunctionEmitter /** * If this function returns a void* encapsulated in a - * java.nio.Buffer, sets the expression for the capacity of the - * returned Buffer. + * java.nio.Buffer (or compound type wrapper), sets the expression + * for the capacity of the returned Buffer. * * @param expression a MessageFormat which, when applied to an array * of type String[] that contains each of the arguments names of the @@ -175,18 +172,20 @@ public class CMethodBindingEmitter extends FunctionEmitter * returned from this method. * * @throws IllegalArgumentException if the <code> - * binding.getJavaReturnType().isNIOBuffer() == false + * binding.getJavaReturnType().isNIOBuffer() == false and + * binding.getJavaReturnType().isCompoundTypeWrapper() == false * </code> */ public final void setReturnValueCapacityExpression(MessageFormat expression) { returnValueCapacityExpression = expression; - if (!binding.getJavaReturnType().isNIOBuffer()) + if (!binding.getJavaReturnType().isNIOBuffer() && + !binding.getJavaReturnType().isCompoundTypeWrapper()) { throw new IllegalArgumentException( "Cannot specify return value capacity for a method that does not " + - "return java.nio.Buffer: \"" + binding + "\""); + "return java.nio.Buffer or a compound type wrapper: \"" + binding + "\""); } } @@ -217,7 +216,8 @@ public class CMethodBindingEmitter extends FunctionEmitter { returnValueLengthExpression = expression; - if (!binding.getJavaReturnType().isArray()) + if (!binding.getJavaReturnType().isArray() && + !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers()) { throw new IllegalArgumentException( "Cannot specify return value length for a method that does not " + @@ -285,6 +285,12 @@ public class CMethodBindingEmitter extends FunctionEmitter */ public final boolean getIsJavaMethodStatic() { return isJavaMethodStatic; } + /** + * Is this CMethodBindingEmitter implementing the case of an + * indirect buffer or array being passed down to C code? + */ + public final boolean forIndirectBufferAndArrayImplementation() { return forIndirectBufferAndArrayImplementation; } + protected void emitReturnType(PrintWriter writer) { writer.print("JNIEXPORT "); @@ -314,10 +320,19 @@ public class CMethodBindingEmitter extends FunctionEmitter } } + protected String getImplSuffix() { + if (forImplementingMethodCall) { + if (forIndirectBufferAndArrayImplementation) { + return "1"; + } else { + return "0"; + } + } + return ""; + } + protected int emitArguments(PrintWriter writer) { - int numBufferOffsetArgs = 0, numBufferOffsetArrayArgs = 0; - writer.print("JNIEnv *env, "); int numEmitted = 1; // initially just the JNIEnv if (isJavaMethodStatic && !binding.hasContainingType()) @@ -335,9 +350,6 @@ public class CMethodBindingEmitter extends FunctionEmitter { // "this" argument always comes down in argument 0 as direct buffer writer.print(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName()); - numBufferOffsetArgs++; - // add Buffer offset argument for Buffer types - writer.print(", jint " + byteOffsetConversionArgName(numBufferOffsetArgs)); } for (int i = 0; i < binding.getNumArguments(); i++) { JavaType javaArgType = binding.getJavaArgumentType(i); @@ -357,28 +369,13 @@ public class CMethodBindingEmitter extends FunctionEmitter writer.print(binding.getArgumentName(i)); ++numEmitted; - // Replace following for indirect buffer case - // if(javaArgType.isNIOBuffer() || javaArgType.isNIOBufferArray()) { - if((javaArgType.isNIOBuffer() && !isIndirectBufferInterface()) || javaArgType.isNIOBufferArray()) { - if(!javaArgType.isArray()) { - numBufferOffsetArgs++; - writer.print(", jint " + byteOffsetConversionArgName(numBufferOffsetArgs)); - } else { - numBufferOffsetArrayArgs++; - writer.print(", jintArray " + - byteOffsetArrayConversionArgName(numBufferOffsetArrayArgs)); - } - } - - // indirect buffer case needs same offset syntax as arrays - if(javaArgType.isNIOBuffer() && isIndirectBufferInterface()) - writer.print(", jint " + binding.getArgumentName(i) + "_offset"); - - // Add array primitive index/offset parameter - if(javaArgType.isArray() && !javaArgType.isNIOBufferArray() && !javaArgType.isStringArray()) { - writer.print(", jint " + binding.getArgumentName(i) + "_offset"); - } - + if (javaArgType.isPrimitiveArray() || + javaArgType.isNIOBuffer()) { + writer.print(", jint " + byteOffsetArgName(i)); + } else if (javaArgType.isNIOBufferArray()) { + writer.print(", jintArray " + + byteOffsetArrayArgName(i)); + } } return numEmitted; } @@ -418,7 +415,7 @@ public class CMethodBindingEmitter extends FunctionEmitter continue; } - if (type.isArray() || type.isNIOBuffer()) { + if (type.isArray() || type.isNIOBuffer() || type.isCompoundTypeWrapper()) { String convName = pointerConversionArgumentName(i); // handle array/buffer argument types boolean needsDataCopy = @@ -435,7 +432,7 @@ public class CMethodBindingEmitter extends FunctionEmitter writer.println(" jsize _tmpArrayLen;"); // Pointer to the data in the Buffer, taking the offset into account - writer.println(" GLint * _offsetHandle = NULL;"); + writer.println(" int * _offsetHandle = NULL;"); emittedDataCopyTemps = true; } @@ -457,37 +454,36 @@ public class CMethodBindingEmitter extends FunctionEmitter // Note we must respect const/volatile for return argument writer.print(binding.getCSymbol().getReturnType().getName(true)); writer.println(" _res;"); - if (javaReturnType.isArray()) { - if (javaReturnType.isNIOByteBufferArray()) { - writer.print(" int "); - writer.print(arrayResLength); - writer.println(";"); - writer.print(" int "); - writer.print(arrayIdx); - writer.println(";"); - writer.print(" jobjectArray "); - writer.print(arrayRes); - writer.println(";"); - } else { - writer.print(" int "); - writer.print(arrayResLength); - writer.println(";"); - - Class componentType = javaReturnType.getJavaClass().getComponentType(); - if (componentType.isArray()) { - throw new RuntimeException("Multi-dimensional arrays not supported yet"); - } + if (javaReturnType.isNIOByteBufferArray() || + javaReturnType.isArrayOfCompoundTypeWrappers()) { + writer.print(" int "); + writer.print(arrayResLength); + writer.println(";"); + writer.print(" int "); + writer.print(arrayIdx); + writer.println(";"); + writer.print(" jobjectArray "); + writer.print(arrayRes); + writer.println(";"); + } else if (javaReturnType.isArray()) { + writer.print(" int "); + writer.print(arrayResLength); + writer.println(";"); - String javaTypeName = componentType.getName(); - capitalizedComponentType = - "" + Character.toUpperCase(javaTypeName.charAt(0)) + javaTypeName.substring(1); - String javaArrayTypeName = "j" + javaTypeName + "Array"; - writer.print(" "); - writer.print(javaArrayTypeName); - writer.print(" "); - writer.print(arrayRes); - writer.println(";"); + Class componentType = javaReturnType.getJavaClass().getComponentType(); + if (componentType.isArray()) { + throw new RuntimeException("Multi-dimensional arrays not supported yet"); } + + String javaTypeName = componentType.getName(); + capitalizedComponentType = + "" + Character.toUpperCase(javaTypeName.charAt(0)) + javaTypeName.substring(1); + String javaArrayTypeName = "j" + javaTypeName + "Array"; + writer.print(" "); + writer.print(javaArrayTypeName); + writer.print(" "); + writer.print(arrayRes); + writer.println(";"); } } } @@ -504,6 +500,17 @@ public class CMethodBindingEmitter extends FunctionEmitter } } + /** Checks a type (expected to be pointer-to-pointer) for const-ness */ + protected boolean isConstPtrPtr(Type type) { + if (type.pointerDepth() != 2) { + return false; + } + if (type.asPointer().getTargetType().asPointer().getTargetType().isConst()) { + return true; + } + return false; + } + /** * Code to init the variables that were declared in * emitBodyVariableDeclarations(), PRIOR TO calling the actual C @@ -512,21 +519,17 @@ public class CMethodBindingEmitter extends FunctionEmitter protected void emitBodyVariablePreCallSetup(PrintWriter writer, boolean emittingPrimitiveArrayCritical) { - int byteOffsetCounter=0, byteOffsetArrayCounter=0; - if (!emittingPrimitiveArrayCritical) { // Convert all Buffers to pointers first so we don't have to // call ReleasePrimitiveArrayCritical for any arrays if any // incoming buffers aren't direct - // we don't want to fall in here for indirectBuffer case, since its an array - if (binding.hasContainingType() && !isIndirectBufferInterface()) { - byteOffsetCounter++; + if (binding.hasContainingType()) { emitPointerConversion(writer, binding, binding.getContainingType(), binding.getContainingCType(), JavaMethodBindingEmitter.javaThisArgumentName(), CMethodBindingEmitter.cThisArgumentName(), - byteOffsetConversionArgName(byteOffsetCounter)); + null); } for (int i = 0; i < binding.getNumArguments(); i++) { @@ -535,13 +538,13 @@ public class CMethodBindingEmitter extends FunctionEmitter continue; } - if (type.isNIOBuffer() && !isIndirectBufferInterface()) { - byteOffsetCounter++; + if (type.isCompoundTypeWrapper() || + (type.isNIOBuffer() && !forIndirectBufferAndArrayImplementation)) { emitPointerConversion(writer, binding, type, binding.getCArgumentType(i), binding.getArgumentName(i), pointerConversionArgumentName(i), - byteOffsetConversionArgName(byteOffsetCounter)); + byteOffsetArgName(i)); } } } @@ -554,16 +557,9 @@ public class CMethodBindingEmitter extends FunctionEmitter continue; } - // create array replacement type for Buffer for indirect Buffer case - if(isIndirectBufferInterface() && javaArgType.isNIOBuffer()) { - float[] c = new float[1]; - javaArgType = JavaType.createForClass(c.getClass()); - } - - if (javaArgType.isArray()) { + if (javaArgType.isArray() || + (javaArgType.isNIOBuffer() && forIndirectBufferAndArrayImplementation)) { boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType); - Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType(); - // We only defer the emission of GetPrimitiveArrayCritical // calls that won't be matched up until after the function @@ -588,15 +584,14 @@ public class CMethodBindingEmitter extends FunctionEmitter writer.print(" "); writer.print(convName); writer.print(" = ("); - if (javaArgType.isArray() && - javaArgType.getJavaClass().getComponentType() == java.lang.String.class) { + if (javaArgType.isStringArray()) { // java-side type is String[] cArgTypeName = "jstring *"; } writer.print(cArgTypeName); - writer.print(") (*env)->GetPrimitiveArrayCritical(env, "); + writer.print(") (((char*) (*env)->GetPrimitiveArrayCritical(env, "); writer.print(binding.getArgumentName(i)); - writer.println(", NULL);"); + writer.println(", NULL)) + " + byteOffsetArgName(i) + ");"); //if(cargtypename is void*) // _ptrX = ((char*)convName + index1*sizeof(thisArgsJavaType)); @@ -607,7 +602,7 @@ public class CMethodBindingEmitter extends FunctionEmitter // // FIXME: should factor out this whole block of code into a separate // method for clarity and maintenance purposes - if (cArgType.toString().indexOf("const") == -1) { + if (!isConstPtrPtr(cArgType)) { // FIXME: if the arg type is non-const, the sematics might be that // the function modifies the argument -- we don't yet support // this. @@ -654,49 +649,43 @@ public class CMethodBindingEmitter extends FunctionEmitter arrayLenName, "Could not allocate buffer for copying data in argument \\\""+binding.getArgumentName(i)+"\\\""); - // Get the handle for the byte offset array sent down for Buffers - // But avoid doing this if the Array is a string array, the one exception since - // that type is never converted to a Buffer according to JOGL semantics (for instance, - // glShaderSourceARB Java signature is String[], not Buffer) - byteOffsetArrayCounter++; - if(subArrayElementJavaType != java.lang.String.class) + // Get the handle for the byte offset array sent down for Buffers + // FIXME: not 100% sure this is correct with respect to the + // JNI spec because it may be illegal to call + // GetObjectArrayElement while in a critical section. May + // need to do another loop and add in the offsets. + if (javaArgType.isNIOBufferArray()) { writer.println - (" _offsetHandle = (GLint *) (*env)->GetPrimitiveArrayCritical(env, " + - byteOffsetArrayConversionArgName(byteOffsetArrayCounter) + - ", NULL);"); - + (" _offsetHandle = (int *) (*env)->GetPrimitiveArrayCritical(env, " + + byteOffsetArrayArgName(i) + + ", NULL);"); + } // process each element in the array writer.println(" for (_copyIndex = 0; _copyIndex < "+arrayLenName+"; ++_copyIndex) {"); // get each array element writer.println(" /* get each element of the array argument \"" + binding.getArgumentName(i) + "\" */"); - String subArrayElementJNITypeString = jniType(subArrayElementJavaType); - writer.print(" _tmpObj = ("); - writer.print(subArrayElementJNITypeString); - writer.print(") (*env)->GetObjectArrayElement(env, "); + writer.print(" _tmpObj = (*env)->GetObjectArrayElement(env, "); writer.print(binding.getArgumentName(i)); writer.println(", _copyIndex);"); - if (subArrayElementJNITypeString == "jstring") - { + if (javaArgType.isStringArray()) { writer.print(" "); emitGetStringUTFChars(writer, "(jstring) _tmpObj", - convName+"_copy[_copyIndex]"); - } - else if (isNIOBufferClass(subArrayElementJavaType)) - { + convName+"_copy[_copyIndex]", + true); + } else if (javaArgType.isNIOBufferArray()) { /* We always assume an integer "byte offset" argument follows any Buffer in the method binding. */ emitGetDirectBufferAddress(writer, "_tmpObj", cArgElementType.getName(), convName + "_copy[_copyIndex]", - "_offsetHandle[_copyIndex]"); - } - else - { + "_offsetHandle[_copyIndex]", + true); + } else { // Question: do we always need to copy the sub-arrays, or just // GetPrimitiveArrayCritical on each jobjectarray element and // assign it to the appropriate elements at pointer depth 1? @@ -704,46 +693,35 @@ public class CMethodBindingEmitter extends FunctionEmitter // Malloc enough space to hold a copy of each sub-array writer.print(" "); emitMalloc( - writer, - convName+"_copy[_copyIndex]", - cArgElementType.getTargetType().getName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !! - "(*env)->GetArrayLength(env, _tmpObj)", - "Could not allocate buffer during copying of data in argument \\\""+binding.getArgumentName(i)+"\\\""); + writer, + convName+"_copy[_copyIndex]", + cArgElementType.getTargetType().getName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !! + "(*env)->GetArrayLength(env, _tmpObj)", + "Could not allocate buffer during copying of data in argument \\\""+binding.getArgumentName(i)+"\\\""); // FIXME: copy the data (use matched Get/ReleasePrimitiveArrayCritical() calls) if (true) throw new RuntimeException( - "Cannot yet handle type \"" + cArgType.getName() + - "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays"); + "Cannot yet handle type \"" + cArgType.getName() + + "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays"); } writer.println(" }"); - if(subArrayElementJavaType != java.lang.String.class) { - writer.println - (" (*env)->ReleasePrimitiveArrayCritical(env, " + - byteOffsetArrayConversionArgName(byteOffsetArrayCounter) + - ", _offsetHandle, JNI_ABORT);"); + if (javaArgType.isNIOBufferArray()) { + writer.println + (" (*env)->ReleasePrimitiveArrayCritical(env, " + + byteOffsetArrayArgName(i) + + ", _offsetHandle, JNI_ABORT);"); } writer.println(); } // end of data copy if (EMIT_NULL_CHECKS) { - writer.print(" }"); - - if (needsDataCopy) { - writer.println(); - } else { - // Zero out array offset in the case of a null pointer - // being passed down to prevent construction of arbitrary - // pointers - writer.println(" else {"); - writer.println(" " + binding.getArgumentName(i) + "_offset = 0;"); - writer.println(" }"); - } + writer.println(" }"); } } else if (javaArgType.isString()) { - if (emittingPrimitiveArrayCritical) { + if (!emittingPrimitiveArrayCritical) { continue; } @@ -755,7 +733,8 @@ public class CMethodBindingEmitter extends FunctionEmitter emitGetStringUTFChars(writer, binding.getArgumentName(i), - "_UTF8" + binding.getArgumentName(i)); + "_UTF8" + binding.getArgumentName(i), + false); if (EMIT_NULL_CHECKS) { writer.println(" }"); @@ -783,16 +762,9 @@ public class CMethodBindingEmitter extends FunctionEmitter continue; } - - // create array type for Indirect Buffer case - if(isIndirectBufferInterface() && javaArgType.isNIOBuffer()) { - float[] c = new float[1]; - javaArgType = JavaType.createForClass(c.getClass()); - } - - if (javaArgType.isArray()) { + if (javaArgType.isArray() || + (javaArgType.isNIOBuffer() && forIndirectBufferAndArrayImplementation)) { boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType); - Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType(); if ((!needsDataCopy && !emittingPrimitiveArrayCritical) || (needsDataCopy && emittingPrimitiveArrayCritical)) { @@ -838,7 +810,7 @@ public class CMethodBindingEmitter extends FunctionEmitter // Only need to perform cleanup for individual array // elements if they are not direct buffers - if (!isNIOBufferClass(subArrayElementJavaType)) { + if (!javaArgType.isNIOBufferArray()) { // Re-fetch length of array that was copied String arrayLenName = "_tmpArrayLen"; writer.print(" "); @@ -861,14 +833,11 @@ public class CMethodBindingEmitter extends FunctionEmitter // get each array element writer.println(" /* free each element of " +convName +"_copy */"); - String subArrayElementJNITypeString = jniType(subArrayElementJavaType); - writer.print(" _tmpObj = ("); - writer.print(subArrayElementJNITypeString); - writer.print(") (*env)->GetObjectArrayElement(env, "); + writer.print(" _tmpObj = (*env)->GetObjectArrayElement(env, "); writer.print(binding.getArgumentName(i)); writer.println(", _copyIndex);"); - if (subArrayElementJNITypeString == "jstring") { + if (javaArgType.isStringArray()) { writer.print(" (*env)->ReleaseStringUTFChars(env, "); writer.print("(jstring) _tmpObj"); writer.print(", "); @@ -920,25 +889,9 @@ public class CMethodBindingEmitter extends FunctionEmitter } } - protected void emitBodyCallCFunction(PrintWriter writer) - { - - // Make the call to the actual C function - writer.print(" "); - - // WARNING: this code assumes that the return type has already been - // typedef-resolved. - Type cReturnType = binding.getCReturnType(); - - if (!cReturnType.isVoid()) { - writer.print("_res = "); - } - if (binding.hasContainingType()) { - // Call through function pointer - writer.print(CMethodBindingEmitter.cThisArgumentName() + "->"); - } - writer.print(binding.getCSymbol().getName()); - writer.print("("); + /** Returns the number of arguments passed so calling code knows + whether to print a comma */ + protected int emitBodyPassCArguments(PrintWriter writer) { for (int i = 0; i < binding.getNumArguments(); i++) { if (i != 0) { writer.print(", "); @@ -964,40 +917,39 @@ public class CMethodBindingEmitter extends FunctionEmitter if (binding.getCArgumentType(i).isPointer() && binding.getJavaArgumentType(i).isPrimitive()) { writer.print("(intptr_t) "); } - if (javaArgType.isArray() || javaArgType.isNIOBuffer()) { - - // Add special code for accounting for array offsets - // - // For mapping from byte primitive array type to type* case produces code: - // (GLtype*)((char*)_ptr0 + varName_offset) - // where varName_offset is the number of bytes offset as calculated in Java code - // also, output same for indirect buffer as for array - if(javaArgType.isNIOBuffer() && isIndirectBufferInterface()) - writer.print("( (char*)"); - else if(javaArgType.isArray() && !javaArgType.isNIOBufferArray() && !javaArgType.isStringArray()) { - writer.print("( (char*)"); - } - /* End of this section of new code for array offsets */ - - writer.print(pointerConversionArgumentName(i)); - if (javaArgTypeNeedsDataCopy(javaArgType)) { - writer.print("_copy"); - } - - /* Continuation of special code for accounting for array offsets */ - if(javaArgType.isNIOBuffer() && isIndirectBufferInterface()) - writer.print(" + " + binding.getArgumentName(i) + "_offset)"); - else if(javaArgType.isArray() && !javaArgType.isNIOBufferArray() && !javaArgType.isStringArray()) { - writer.print(" + " + binding.getArgumentName(i) + "_offset)"); - } - /* End of this section of new code for array offsets */ - + if (javaArgType.isArray() || javaArgType.isNIOBuffer() || javaArgType.isCompoundTypeWrapper()) { + writer.print(pointerConversionArgumentName(i)); + if (javaArgTypeNeedsDataCopy(javaArgType)) { + writer.print("_copy"); + } } else { if (javaArgType.isString()) { writer.print("_UTF8"); } writer.print(binding.getArgumentName(i)); } } } + return binding.getNumArguments(); + } + + protected void emitBodyCallCFunction(PrintWriter writer) { + + // Make the call to the actual C function + writer.print(" "); + + // WARNING: this code assumes that the return type has already been + // typedef-resolved. + Type cReturnType = binding.getCReturnType(); + + if (!cReturnType.isVoid()) { + writer.print("_res = "); + } + if (binding.hasContainingType()) { + // Call through function pointer + writer.print(CMethodBindingEmitter.cThisArgumentName() + "->"); + } + writer.print(binding.getCSymbol().getName()); + writer.print("("); + emitBodyPassCArguments(writer); writer.println(");"); } @@ -1013,9 +965,6 @@ public class CMethodBindingEmitter extends FunctionEmitter } } - // FIXME: refactor this so that subclasses (in particular, - // net.java.games.gluegen.opengl.CGLPAWrapperEmitter) don't have to copy the whole - // method protected void emitBodyReturnResult(PrintWriter writer) { // WARNING: this code assumes that the return type has already been @@ -1033,7 +982,8 @@ public class CMethodBindingEmitter extends FunctionEmitter writer.print("(" + javaReturnType.jniTypeName() + ") (intptr_t) "); } writer.println("_res;"); - } else if (javaReturnType.isNIOBuffer()) { + } else if (javaReturnType.isNIOBuffer() || + javaReturnType.isCompoundTypeWrapper()) { writer.println(" if (_res == NULL) return NULL;"); writer.print(" return (*env)->NewDirectByteBuffer(env, _res, "); // See whether capacity has been specified @@ -1051,7 +1001,7 @@ public class CMethodBindingEmitter extends FunctionEmitter cReturnType.asPointer().getTargetType().isCompound()) { sz = cReturnType.asPointer().getTargetType().getSize(); if (sz == -1) { - throw new InternalError( + throw new RuntimeException( "Error emitting code for compound return type "+ "for function \"" + binding + "\": " + "Structs to be emitted should have been laid out by this point " + @@ -1072,64 +1022,67 @@ public class CMethodBindingEmitter extends FunctionEmitter } else if (javaReturnType.isString()) { writer.print(" if (_res == NULL) return NULL;"); writer.println(" return (*env)->NewStringUTF(env, _res);"); - } else if (javaReturnType.isArray()) { - if (javaReturnType.isNIOByteBufferArray()) { - writer.println(" if (_res == NULL) return NULL;"); - if (returnValueLengthExpression == null) { - throw new RuntimeException("Error while generating C code: no length specified for array returned from function " + - binding); - } - String[] argumentNames = new String[binding.getNumArguments()]; - for (int i = 0; i < binding.getNumArguments(); i++) { - argumentNames[i] = binding.getArgumentName(i); - } - writer.println(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNames) + ";"); - writer.println(" " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);"); - writer.println(" for (" + arrayIdx + " = 0; " + arrayIdx + " < " + arrayResLength + "; " + arrayIdx + "++) {"); - Type retType = binding.getCSymbol().getReturnType(); - Type baseType; - if (retType.isPointer()) { - baseType = retType.asPointer().getTargetType().asPointer().getTargetType(); - } else { - baseType = retType.asArray().getElementType().asPointer().getTargetType(); - } - int sz = baseType.getSize(); - if (sz < 0) - sz = 0; - writer.println(" (*env)->SetObjectArrayElement(env, " + arrayRes + ", " + arrayIdx + - ", (*env)->NewDirectByteBuffer(env, _res[" + arrayIdx + "], " + sz + "));"); - writer.println(" }"); - writer.println(" return " + arrayRes + ";"); + } else if (javaReturnType.isArrayOfCompoundTypeWrappers() || + (javaReturnType.isArray() && javaReturnType.isNIOByteBufferArray())) { + writer.println(" if (_res == NULL) return NULL;"); + if (returnValueLengthExpression == null) { + throw new RuntimeException("Error while generating C code: no length specified for array returned from function " + + binding); + } + String[] argumentNames = new String[binding.getNumArguments()]; + for (int i = 0; i < binding.getNumArguments(); i++) { + argumentNames[i] = binding.getArgumentName(i); + } + writer.println(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNames) + ";"); + writer.println(" " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);"); + writer.println(" for (" + arrayIdx + " = 0; " + arrayIdx + " < " + arrayResLength + "; " + arrayIdx + "++) {"); + Type retType = binding.getCSymbol().getReturnType(); + Type baseType; + if (retType.isPointer()) { + baseType = retType.asPointer().getTargetType().asPointer().getTargetType(); } else { - // FIXME: must have user provide length of array in .cfg file - // by providing a constant value, input parameter, or - // expression which computes the array size (already present - // as ReturnValueCapacity, not yet implemented / tested here) - - throw new RuntimeException( - "Could not emit native code for function \"" + binding + - "\": array return values for non-char types not implemented yet"); - - // FIXME: This is approximately what will be required here - // - //writer.print(" "); - //writer.print(arrayRes); - //writer.print(" = (*env)->New"); - //writer.print(capitalizedComponentType); - //writer.print("Array(env, "); - //writer.print(arrayResLength); - //writer.println(");"); - //writer.print(" (*env)->Set"); - //writer.print(capitalizedComponentType); - //writer.print("ArrayRegion(env, "); - //writer.print(arrayRes); - //writer.print(", 0, "); - //writer.print(arrayResLength); - //writer.println(", _res);"); - //writer.print(" return "); - //writer.print(arrayRes); - //writer.println(";"); + baseType = retType.asArray().getElementType().asPointer().getTargetType(); } + int sz = baseType.getSize(); + if (sz < 0) + sz = 0; + writer.println(" (*env)->SetObjectArrayElement(env, " + arrayRes + ", " + arrayIdx + + ", (*env)->NewDirectByteBuffer(env, _res[" + arrayIdx + "], " + sz + "));"); + writer.println(" }"); + writer.println(" return " + arrayRes + ";"); + } else if (javaReturnType.isArray()) { + // FIXME: must have user provide length of array in .cfg file + // by providing a constant value, input parameter, or + // expression which computes the array size (already present + // as ReturnValueCapacity, not yet implemented / tested here) + + throw new RuntimeException( + "Could not emit native code for function \"" + binding + + "\": array return values for non-char types not implemented yet"); + + // FIXME: This is approximately what will be required here + // + //writer.print(" "); + //writer.print(arrayRes); + //writer.print(" = (*env)->New"); + //writer.print(capitalizedComponentType); + //writer.print("Array(env, "); + //writer.print(arrayResLength); + //writer.println(");"); + //writer.print(" (*env)->Set"); + //writer.print(capitalizedComponentType); + //writer.print("ArrayRegion(env, "); + //writer.print(arrayRes); + //writer.print(", 0, "); + //writer.print(arrayResLength); + //writer.println(", _res);"); + //writer.print(" return "); + //writer.print(arrayRes); + //writer.println(";"); + } else { + System.err.print("Unhandled return type: "); + javaReturnType.dump(); + throw new RuntimeException("Unhandled return type"); } } } @@ -1146,38 +1099,56 @@ public class CMethodBindingEmitter extends FunctionEmitter protected String jniMangle(MethodBinding binding) { StringBuffer buf = new StringBuffer(); buf.append(jniMangle(binding.getName())); + buf.append(getImplSuffix()); buf.append("__"); + if (binding.hasContainingType()) { + // "this" argument always comes down in argument 0 as direct buffer + jniMangle(java.nio.ByteBuffer.class, buf, true); + } for (int i = 0; i < binding.getNumArguments(); i++) { + if (binding.isArgumentThisPointer(i)) { + continue; + } JavaType type = binding.getJavaArgumentType(i); - Class c = type.getJavaClass(); - if (c != null) { - jniMangle(c, buf); - // If Buffer offset arguments were added, we need to mangle the JNI for the - // extra arguments - if(type.isNIOBuffer()) { - jniMangle(Integer.TYPE, buf); - } else if (type.isNIOBufferArray()) { - int[] intArrayType = new int[0]; - c = intArrayType.getClass(); - jniMangle(c , buf); - } - if(type.isArray() && !type.isNIOBufferArray()) { - jniMangle(Integer.TYPE, buf); - } + if (type.isVoid()) { + // We should only see "void" as the first argument of a 1-argument function + // FIXME: should normalize this in the parser + if ((i != 0) || (binding.getNumArguments() > 1)) { + throw new RuntimeException("Saw illegal \"void\" argument while emitting \"" + binding.getName() + "\""); + } } else { - // FIXME: add support for char* -> String conversion - throw new RuntimeException("Unknown kind of JavaType: name="+type.getName()); + Class c = type.getJavaClass(); + if (c != null) { + jniMangle(c, buf, false); + // If Buffer offset arguments were added, we need to mangle the JNI for the + // extra arguments + if (type.isNIOBuffer()) { + jniMangle(Integer.TYPE, buf, false); + } else if (type.isNIOBufferArray()) { + int[] intArrayType = new int[0]; + c = intArrayType.getClass(); + jniMangle(c , buf, true); + } + if (type.isPrimitiveArray()) { + jniMangle(Integer.TYPE, buf, false); + } + } else if (type.isCompoundTypeWrapper()) { + // Mangle wrappers for C structs as ByteBuffer + jniMangle(java.nio.ByteBuffer.class, buf, true); + } else if (type.isJNIEnv()) { + // These are not exposed at the Java level + } else { + // FIXME: add support for char* -> String conversion + throw new RuntimeException("Unknown kind of JavaType: name="+type.getName()); + } } } return buf.toString(); } - protected void jniMangle(Class c, StringBuffer res) { - if (c.isArray()) { - res.append("_3"); - jniMangle(c.getComponentType(), res); - } else if (c.isPrimitive()) { + protected void jniMangle(Class c, StringBuffer res, boolean syntheticArgument) { + if (c.isPrimitive()) { if (c == Boolean.TYPE) res.append("Z"); else if (c == Byte.TYPE) res.append("B"); else if (c == Character.TYPE) res.append("C"); @@ -1186,35 +1157,37 @@ public class CMethodBindingEmitter extends FunctionEmitter else if (c == Long.TYPE) res.append("J"); else if (c == Float.TYPE) res.append("F"); else if (c == Double.TYPE) res.append("D"); - else throw new InternalError("Illegal primitive type"); + else throw new RuntimeException("Illegal primitive type \"" + c.getName() + "\""); } else { - if(!isIndirectBufferInterface()) { - res.append("L"); - res.append(c.getName().replace('.', '_')); - res.append("_2"); - } else { // indirect buffer sends array as object - res.append("L"); - res.append("java_lang_Object"); - res.append("_2"); - } + // Arrays and NIO Buffers are always passed down as java.lang.Object. + // The only arrays that show up as true arrays in the signature + // are the synthetic byte offset arrays created when passing + // down arrays of direct Buffers. Compound type wrappers are + // passed down as ByteBuffers (no good reason, just to avoid + // accidental conflation) so we mangle them differently. + if (syntheticArgument) { + if (c.isArray()) { + res.append("_3"); + jniMangle(c.getComponentType(), res, false); + } else { + res.append("L"); + res.append(c.getName().replace('.', '_')); + res.append("_2"); + } + } else { + if (c == java.lang.String.class) { + res.append("L"); + res.append(c.getName().replace('.', '_')); + res.append("_2"); + } else { + res.append("L"); + res.append("java_lang_Object"); + res.append("_2"); + } + } } } - private String jniType(Class javaType) - { - if (javaType.isPrimitive()) { - return "j" + javaType.getName(); - } else if (javaType == java.lang.String.class) { - return "jstring"; - } else if (isNIOBufferClass(javaType)) { - return "jobject"; - } else { - throw new RuntimeException( - "Could not determine JNI type for Java class \"" + - javaType.getName() + "\"; was not String, primitive or direct buffer"); - } - } - private void emitOutOfMemoryCheck(PrintWriter writer, String varName, String errorMessage) { @@ -1259,11 +1232,14 @@ public class CMethodBindingEmitter extends FunctionEmitter private void emitGetStringUTFChars(PrintWriter writer, String sourceVarName, - String receivingVarName) + String receivingVarName, + boolean emitElseClause) { - writer.print(" if ("); - writer.print(sourceVarName); - writer.println(" != NULL) {"); + if (EMIT_NULL_CHECKS) { + writer.print(" if ("); + writer.print(sourceVarName); + writer.println(" != NULL) {"); + } writer.print(" "); writer.print(receivingVarName); writer.print(" = (*env)->GetStringUTFChars(env, "); @@ -1276,11 +1252,18 @@ public class CMethodBindingEmitter extends FunctionEmitter writer, receivingVarName, "Failed to get UTF-8 chars for argument \\\""+sourceVarName+"\\\""); } - writer.println(" } else {"); - writer.print(" "); - writer.print(receivingVarName); - writer.println(" = NULL;"); - writer.println(" }"); + if (EMIT_NULL_CHECKS) { + writer.print(" }"); + if (emitElseClause) { + writer.print(" else {"); + writer.print(" "); + writer.print(receivingVarName); + writer.println(" = NULL;"); + writer.println(" }"); + } else { + writer.println(); + } + } } @@ -1289,56 +1272,37 @@ public class CMethodBindingEmitter extends FunctionEmitter String sourceVarName, String receivingVarTypeString, String receivingVarName, - String byteOffsetVarName) { + String byteOffsetVarName, + boolean emitElseClause) { if (EMIT_NULL_CHECKS) { - writer.print(" if ("); + writer.print(" if ("); writer.print(sourceVarName); writer.println(" != NULL) {"); + writer.print(" "); } - /* Pre Buffer Offset code: In the case where there is NOT an integer offset - in bytes for the direct buffer, we used to use: - (type*) (*env)->GetDirectBufferAddress(env, buf); - generated as follows: - if(byteOffsetVarName == null) { - writer.print(" "); - writer.print(receivingVarName); - writer.print(" = ("); - writer.print(receivingVarTypeString); - writer.print(") (*env)->GetDirectBufferAddress(env, "); - writer.print(sourceVarName); - writer.println(");"); - */ - - /* In the case (now always the case) where there is an integer offset in bytes for - the direct buffer, we want to use: - _ptrX = (type*) (*env)->GetDirectBufferAddress(env, buf); - _ptrX = (type*) ((char*)buf + __byteOffset); - Note that __byteOffset is an int */ - writer.print(" "); - writer.print(receivingVarName); - writer.print(" = ("); - writer.print(receivingVarTypeString); - - writer.print(") (*env)->GetDirectBufferAddress(env, "); - writer.print(sourceVarName); - writer.println(");"); - - writer.print(" "); - writer.print(receivingVarName); - writer.print(" = ("); - writer.print(receivingVarTypeString); - writer.print(") ((char*)" + receivingVarName + " + "); - writer.println(byteOffsetVarName + ");"); + + writer.print(" "); + writer.print(receivingVarName); + writer.print(" = ("); + writer.print(receivingVarTypeString); + + writer.print(") (((char*) (*env)->GetDirectBufferAddress(env, "); + writer.print(sourceVarName); + writer.println(")) + " + ((byteOffsetVarName != null) ? byteOffsetVarName : "0") + ");"); if (EMIT_NULL_CHECKS) { - writer.println(" } else {"); - writer.print(" "); - writer.print(receivingVarName); - writer.println(" = NULL;"); - writer.println(" }"); + writer.print(" }"); + if (emitElseClause) { + writer.println(" else {"); + writer.print(" "); + writer.print(receivingVarName); + writer.println(" = NULL;"); + writer.println(" }"); + } else { + writer.println(); + } } } - // Note: if the data in the Type needs to be converted from the Java memory // model to the C memory model prior to calling any C-side functions, then @@ -1356,80 +1320,54 @@ public class CMethodBindingEmitter extends FunctionEmitter // // Note that we don't need to obey const/volatile for outgoing arguments // - if (javaType.isNIOBuffer()) - { + if (javaType.isNIOBuffer()) { ptrTypeString = cType.getName(); - } - else if (javaType.isArray()) { + } else if (javaType.isArray()) { needsDataCopy = javaArgTypeNeedsDataCopy(javaType); - // It's an array; get the type of the elements in the array - Class elementType = javaType.getJavaClass().getComponentType(); - if (elementType.isPrimitive()) - { + if (javaType.isPrimitiveArray() || + javaType.isNIOBufferArray()) { ptrTypeString = cType.getName(); - } - else if (elementType == java.lang.String.class) - { - ptrTypeString = "jstring"; - } - else if (elementType.isArray()) - { - Class subElementType = elementType.getComponentType(); - if (subElementType.isPrimitive()) - { - // type is pointer to pointer to primitive - ptrTypeString = cType.getName(); - } - else - { + } else if (!javaType.isStringArray()) { + Class elementType = javaType.getJavaClass().getComponentType(); + if (elementType.isArray()) { + Class subElementType = elementType.getComponentType(); + if (subElementType.isPrimitive()) { + // type is pointer to pointer to primitive + ptrTypeString = cType.getName(); + } else { + // type is pointer to pointer of some type we don't support (maybe + // it's an array of pointers to structs?) + throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\""); + } + } else { // type is pointer to pointer of some type we don't support (maybe // it's an array of pointers to structs?) throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\""); } - - } - else if (isNIOBufferClass(elementType)) - { - // type is an array of direct buffers of some sort - ptrTypeString = cType.getName(); } - else - { - // Type is pointer to something we can't/don't handle - throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\""); - } - } - else if (javaType.isArrayOfCompoundTypeWrappers()) - { + } else if (javaType.isArrayOfCompoundTypeWrappers()) { // FIXME throw new RuntimeException("Outgoing arrays of StructAccessors not yet implemented"); - } - else - { + } else { ptrTypeString = cType.getName(); } - if (!needsDataCopy) - { + if (!needsDataCopy) { // declare the pointer variable writer.print(" "); writer.print(ptrTypeString); writer.print(" "); writer.print(cVariableName); writer.println(" = NULL;"); - } - else - { + } else { // Declare a variable to hold a copy of the argument data in which the // incoming data has been properly laid out in memory to match the C // memory model - //writer.print(" const "); Class elementType = javaType.getJavaClass().getComponentType(); - if (javaType.isArray() && - javaType.getJavaClass().getComponentType() == java.lang.String.class) { + if (javaType.isStringArray()) { writer.print(" const char **"); } else { - writer.print(ptrTypeString); + writer.print(" " + ptrTypeString); } writer.print(" "); writer.print(cVariableName); @@ -1448,45 +1386,34 @@ public class CMethodBindingEmitter extends FunctionEmitter String incomingArgumentName, String cVariableName, String byteOffsetVarName) { + // Compound type wrappers do not get byte offsets added on + if (type.isCompoundTypeWrapper()) { + byteOffsetVarName = null; + } + emitGetDirectBufferAddress(writer, incomingArgumentName, cType.getName(), cVariableName, - byteOffsetVarName); - - /* - if (EMIT_NULL_CHECKS) { - writer.print(" if ("); - writer.print(incomingArgumentName); - writer.println(" != NULL) {"); - } - - writer.print(" "); - writer.print(cVariableName); - writer.print(" = ("); - writer.print(cType.getName()); - writer.print(") (*env)->GetDirectBufferAddress(env, "); - writer.print(incomingArgumentName); - writer.println(");"); - - if (EMIT_NULL_CHECKS) { - writer.println(" }"); - } - */ + byteOffsetVarName, + false); } - protected String pointerConversionArgumentName(int i) { - return "_ptr" + i; + protected String byteOffsetArgName(int i) { + return byteOffsetArgName(binding.getArgumentName(i)); } - protected String byteOffsetConversionArgName(int i) { - return "__byteOffset" + i; + protected String byteOffsetArgName(String s) { + return s + "_byte_offset"; } - - protected String byteOffsetArrayConversionArgName(int i) { - return "__byteOffsetArray" + i; + + protected String byteOffsetArrayArgName(int i) { + return binding.getArgumentName(i) + "_byte_offset_array"; + } + + protected String pointerConversionArgumentName(int i) { + return "_ptr" + i; } - /** * Class that emits a generic comment for CMethodBindingEmitters; the comment @@ -1515,16 +1442,10 @@ public class CMethodBindingEmitter extends FunctionEmitter protected boolean javaArgTypeNeedsDataCopy(JavaType javaArgType) { if (javaArgType.isArray()) { - Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType(); - return (subArrayElementJavaType.isArray() || - subArrayElementJavaType == java.lang.String.class || - isNIOBufferClass(subArrayElementJavaType)); + return (javaArgType.isNIOBufferArray() || + javaArgType.isStringArray() || + javaArgType.getJavaClass().getComponentType().isArray()); } return false; } - - protected static boolean isNIOBufferClass(Class c) { - return java.nio.Buffer.class.isAssignableFrom(c); - } } - diff --git a/src/net/java/games/gluegen/CMethodBindingImplEmitter.java b/src/net/java/games/gluegen/CMethodBindingImplEmitter.java deleted file mode 100644 index 3f3505896..000000000 --- a/src/net/java/games/gluegen/CMethodBindingImplEmitter.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package net.java.games.gluegen; - -import java.util.*; -import java.io.*; -import java.text.MessageFormat; - -public class CMethodBindingImplEmitter extends CMethodBindingEmitter -{ - protected static final CommentEmitter defaultCImplCommentEmitter = - new CImplCommentEmitter(); - - protected boolean arrayImplRoutine = false; - - public CMethodBindingImplEmitter(MethodBinding binding, - boolean isOverloadedBinding, - boolean arrayImpl, - String javaPackageName, - String javaClassName, - boolean isJavaMethodStatic, - PrintWriter output) - { - super(binding, isOverloadedBinding, - javaPackageName, javaClassName, - isJavaMethodStatic, output); - setCommentEmitter(defaultCImplCommentEmitter); - arrayImplRoutine = arrayImpl; - } - - protected void emitName(PrintWriter writer) - { - super.emitName(writer); - if (!getIsOverloadedBinding()) { - if( isIndirectBufferInterface() ) - writer.print("2"); - else if(!arrayImplRoutine) - writer.print("0"); - else - writer.print("1"); - } - } - - /** - * Gets the mangled name for the binding, but assumes that this is an Impl - * routine - */ - protected String jniMangle(MethodBinding binding) { - StringBuffer buf = new StringBuffer(); - buf.append(jniMangle(binding.getName())); - - if( isIndirectBufferInterface() ) - buf.append("2"); - else if(!arrayImplRoutine) - buf.append("0"); - else - buf.append("1"); - - buf.append("__"); - for (int i = 0; i < binding.getNumArguments(); i++) { - JavaType type = binding.getJavaArgumentType(i); - - Class c = type.getJavaClass(); - if (c != null) { - jniMangle(c, buf); - // Add mangling for buffer offset arguments - if(type.isNIOBuffer()) { - jniMangle(Integer.TYPE, buf); - } else if (type.isNIOBufferArray()) { - int[] intArrayType = new int[0]; - c = intArrayType.getClass(); - jniMangle(c , buf); - } - if(type.isArray() && !type.isNIOBufferArray() && !type.isStringArray()) { - jniMangle(Integer.TYPE, buf); - } - } else { - // FIXME: add support for char* -> String conversion - throw new RuntimeException("Unknown kind of JavaType: name="+type.getName()); - } - } - return buf.toString(); - } - - protected static class CImplCommentEmitter extends CMethodBindingEmitter.DefaultCommentEmitter { - protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) { - writer.print(" -- FIXME: PUT A COMMENT HERE -- "); - } - } -} diff --git a/src/net/java/games/gluegen/JavaConfiguration.java b/src/net/java/games/gluegen/JavaConfiguration.java index e39a147f8..51e22f7d6 100644 --- a/src/net/java/games/gluegen/JavaConfiguration.java +++ b/src/net/java/games/gluegen/JavaConfiguration.java @@ -50,28 +50,6 @@ import net.java.games.gluegen.cgram.types.*; public class JavaConfiguration { - /* possible PrimitiveArrayExpansionMode states */ - private int ALL_POINTERS = 1; - private int NON_VOID_ONLY = 2; - private int NO_POINTERS = 3; - - /* Default primitive array expansion mode is ALL_POINTERS, meaning all C - pointers, including void pointers, will have Java primitive array - expansions */ - private int primitiveArrayExpansionMode = ALL_POINTERS; - - /* Determines which primitive array types void * C signatures are - expanded into (assuming PrimitiveArrayExpansionMode = ALL_POINTERS). */ - private boolean voidPointerExpansionToBoolean = true; - private boolean voidPointerExpansionToChar = true; - private boolean voidPointerExpansionToByte = true; - private boolean voidPointerExpansionToShort = true; - private boolean voidPointerExpansionToInt = true; - private boolean voidPointerExpansionToLong = true; - private boolean voidPointerExpansionToFloat = true; - private boolean voidPointerExpansionToDouble = true; - - private int nestedReads; private String packageName; private String implPackageName; @@ -120,21 +98,12 @@ public class JavaConfiguration { private Set/*<Pattern>*/ ignoreNots = new HashSet(); private Set/*<Pattern>*/ unimplemented = new HashSet(); private Set/*<String>*/ nioDirectOnly = new HashSet(); - /** See {@link #nioMode} */ - public static final int NIO_MODE_VOID_ONLY = 1; - /** See {@link #nioMode} */ - public static final int NIO_MODE_ALL_POINTERS = 2; - private int nioMode = NIO_MODE_VOID_ONLY; - private Set/*<String>*/ noNio = new HashSet(); - private Set/*<String>*/ forcedNio = new HashSet(); - private boolean flattenNIOVariants = true; private Set/*<String>*/ manuallyImplement = new HashSet(); private Map/*<String,List<String>>*/ customJavaCode = new HashMap(); private Map/*<String,List<String>>*/ classJavadoc = new HashMap(); private Map/*<String,String>*/ structPackages = new HashMap(); private List/*<String>*/ customCCode = new ArrayList(); private List/*<String>*/ forcedStructs = new ArrayList(); - private Map/*<String,List<Integer>>*/ mirroredArgs = new HashMap(); private Map/*<String, String>*/ returnValueCapacities = new HashMap(); private Map/*<String, String>*/ returnValueLengths = new HashMap(); private Map/*<String, List<String>>*/ temporaryCVariableDeclarations = new HashMap(); @@ -253,30 +222,6 @@ public class JavaConfiguration { /** Returns the list of imports that should be emitted at the top of each .java file. */ public List/*<String>*/ imports() { return imports; } - - /* Return Primitive Array Expansion Mode state */ - public boolean isPrimArrayExpModeAllPtrs() { - return (primitiveArrayExpansionMode == ALL_POINTERS); - } - public boolean isPrimArrayExpModeNonVoidPtrs() { - return (primitiveArrayExpansionMode == NON_VOID_ONLY); - } - public boolean isPrimArrayExpModeNoPtrs() { - return (primitiveArrayExpansionMode == NO_POINTERS); - } - - - /** Returns VoidPointerExpansion values */ - public boolean voidPointerExpansionToBoolean() { return voidPointerExpansionToBoolean; } - public boolean voidPointerExpansionToChar() { return voidPointerExpansionToChar; } - public boolean voidPointerExpansionToByte() { return voidPointerExpansionToByte; } - public boolean voidPointerExpansionToShort() { return voidPointerExpansionToShort; } - public boolean voidPointerExpansionToInt() { return voidPointerExpansionToInt; } - public boolean voidPointerExpansionToLong() { return voidPointerExpansionToLong; } - public boolean voidPointerExpansionToFloat() { return voidPointerExpansionToFloat; } - public boolean voidPointerExpansionToDouble() { return voidPointerExpansionToDouble; } - - /** If this type should be considered opaque, returns the TypeInfo describing the replacement type. Returns null if this type should not be considered opaque. */ @@ -367,40 +312,6 @@ public class JavaConfiguration { return nioDirectOnly.contains(functionName); } - /** Returns true if the user requested that the given function - should only create array variants, and no java.nio variant, for - <code>void*</code> and other C primitive pointers, overriding - the NIO mode default. */ - public boolean noNio(String functionName) { - return noNio.contains(functionName); - } - - /** Returns true if the user requested that the given function - should create a java.nio variant for the given function's - <code>void*</code> and other C primitive pointers, overriding - the NIO mode default. */ - public boolean forcedNio(String functionName) { - return forcedNio.contains(functionName); - } - - /** Returns the default NIO generation mode for C primitive pointer - arguments. NIO_MODE_VOID_ONLY is the default and specifies - that only void* arguments will have java.nio variants generated - for them. NIO_MODE_ALL_POINTERS specifies that all C - primitive arguments will have java.nio variants generated. */ - public int nioMode() { - return nioMode; - } - - /** Returns true if, for the plethora of java.nio variants generated - for primitive C pointer types, the emitter should flatten the - output down to two variants: one taking only Java primitive - arrays as arguments, and one taking only java.nio.Buffers as - arguments. */ - public boolean flattenNIOVariants() { - return flattenNIOVariants; - } - /** Returns true if the glue code for the given function will be manually implemented by the end user. */ public boolean manuallyImplement(String functionName) { @@ -456,14 +367,6 @@ public class JavaConfiguration { return forcedStructs; } - /** Returns a List of Integers indicating the indices of arguments - in this function that should be expanded to the same type when - binding functions with multiple void* arguments. Returns null if - no such indices were specified. */ - public List/*<Integer>*/ mirroredArgs(String functionName) { - return (List) mirroredArgs.get(functionName); - } - /** 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. */ @@ -676,22 +579,8 @@ public class JavaConfiguration { // because readClassJavadoc changes them. } else if (cmd.equalsIgnoreCase("NioDirectOnly")) { nioDirectOnly.add(readString("NioDirectOnly", tok, filename, lineNo)); - } else if (cmd.equalsIgnoreCase("NoNio")) { - noNio.add(readString("NoNio", tok, filename, lineNo)); - } else if (cmd.equalsIgnoreCase("ForcedNio")) { - forcedNio.add(readString("ForcedNio", tok, filename, lineNo)); - } else if (cmd.equalsIgnoreCase("NioMode")) { - readNioMode(tok, filename, lineNo); - } else if (cmd.equalsIgnoreCase("FlattenNIOVariants")) { - flattenNIOVariants = readBoolean("FlattenNIOVariants", tok, filename, lineNo).booleanValue(); - } else if (cmd.equalsIgnoreCase("PrimitiveArrayExpansionMode")) { - readPrimitiveExpMode(tok, filename, lineNo); - } else if (cmd.equalsIgnoreCase("VoidPointerExpansion")) { - readVoidPointerExpansionSet(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("EmitStruct")) { forcedStructs.add(readString("EmitStruct", tok, filename, lineNo)); - } else if (cmd.equalsIgnoreCase("MirrorExpandedBindingArgs")) { - readMirrorExpandedBindingArgs(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("StructPackage")) { readStructPackage(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("TemporaryCVariableDeclaration")) { @@ -899,226 +788,6 @@ public class JavaConfiguration { codeList.add(code); } - /** - * Sets the default NIO generation mode for C primitive - * pointers. Options are VOID_ONLY or ALL_POINTERS. When the mode is - * set to VOID_ONLY, java.nio variants of methods are only generated - * for C primitive pointers of type <code>void*</code>. All other - * pointers are translated by default into Java primitive arrays. - * When the mode is set to ALL_POINTERS, C primitive pointers of - * other types (i.e., <code>int*</code>) will have java.nio variants - * generated for them (i.e., <code>IntBuffer</code> as opposed to - * merely <code>int[]</code>). This default mode can be overridden - * with the NioDirectOnly and NoNio directives. The default for this mode - * is currently VOID_ONLY. - */ - protected void readNioMode(StringTokenizer tok, String filename, int lineNo) { - try { - String mode = tok.nextToken(); - if (mode.equalsIgnoreCase("VOID_ONLY")) { - nioMode = NIO_MODE_VOID_ONLY; - } else if (mode.equalsIgnoreCase("ALL_POINTERS")) { - nioMode = NIO_MODE_ALL_POINTERS; - } else { - throw new RuntimeException("Error parsing \"NioMode\" command at line " + lineNo + - " in file \"" + filename + "\"; expected VOID_ONLY or ALL_POINTERS"); - } - } catch (NoSuchElementException e) { - throw new RuntimeException( - "Error parsing \"NioMode\" command at line " + lineNo + - " in file \"" + filename + "\"", e); - } - } - - - /** - * Sets the Primitive Array Expansion Mode. Options are ALL_POINTERS (default), - * NON_VOID_ONLY, and NO_POINTERS. ALL_POINTERS means that all Primitive array - * C pointers (float*, int*, void*, etc.) get expanded into non-NIO buffer - * targets. The setting has no bearing on whether NIO buffer targets happen. - * So float * goes to float[], int* goes to int[], and void* gets expanded to - * (by default) double[], float[], long[], int[], short[], byte[], char[], and - * boolean[]. NON_VOID_ONLY means that all Primitive array pointers except - * for void * get expanded, and NO_POINTERS means that no C Primitive array - * pointers get expanded. - * For void * expansion the default is all 8 primitive types as listed above. - * However, the types can be restricted by use of the VoidPointerExpansion - * attribute defined elsewhere in this file. - */ - - protected void readPrimitiveExpMode(StringTokenizer tok, String filename, int lineNo) { - try { - String mode = tok.nextToken(); - if (mode.equalsIgnoreCase("ALL_POINTERS")) { - primitiveArrayExpansionMode = ALL_POINTERS; - } else if (mode.equalsIgnoreCase("NON_VOID_ONLY")) { - primitiveArrayExpansionMode = NON_VOID_ONLY; - } else if (mode.equalsIgnoreCase("NO_POINTERS")) { - primitiveArrayExpansionMode = NO_POINTERS; - } else { - throw new RuntimeException("Error parsing \"PrimitiveArrayExpansionMode\" command at line " + lineNo + - " in file \"" + filename - + "\"; expected NO_POINTERS, NON_VOID_ONLY or ALL_POINTERS"); - } - } catch (NoSuchElementException e) { - throw new RuntimeException( - "Error parsing \"PrimitiveArrayExpansionMode\" command at line " + lineNo + - " in file \"" + filename + "\"", e); - } - } - - - - /** - * readVoidPointerExpansionSet: - * Parses VoidPointerExpansion arguments. Expecting subset of boolean, char, byte, - * short, int, long,float, double. Example grammar file syntax: - * VoidPointerExpansion short int float byte double - * If PrimitiveArrayExpansionMode is set to NON_VOID_ONLY or NO_POINTERS, then - * the VoidPointerExpansion attribute has no effect, since in that case void - * pointers are not expanded. - */ - - protected void readVoidPointerExpansionSet(StringTokenizer tok, String filename, int lineNo) { - int number_passes=0; - boolean finished = false; - - voidPointerExpansionToBoolean = false; - voidPointerExpansionToChar = false; - voidPointerExpansionToByte = false; - voidPointerExpansionToShort = false; - voidPointerExpansionToInt = false; - voidPointerExpansionToLong = false; - voidPointerExpansionToFloat = false; - voidPointerExpansionToDouble = false; - - while(!finished) { - try { - String mode = tok.nextToken(); - if (mode.equalsIgnoreCase("float")) { - voidPointerExpansionToFloat = true; - number_passes++; - } else if (mode.equalsIgnoreCase("int")) { - voidPointerExpansionToInt = true; - number_passes++; - } else if (mode.equalsIgnoreCase("byte")) { - voidPointerExpansionToByte = true; - number_passes++; - } else if (mode.equalsIgnoreCase("short")) { - voidPointerExpansionToShort = true; - number_passes++; - } else if (mode.equalsIgnoreCase("boolean")) { - voidPointerExpansionToBoolean = true; - number_passes++; - } else if (mode.equalsIgnoreCase("char")) { - voidPointerExpansionToChar = true; - number_passes++; - } else if (mode.equalsIgnoreCase("long")) { - voidPointerExpansionToLong = true; - number_passes++; - } else if (mode.equalsIgnoreCase("double")) { - voidPointerExpansionToDouble = true; - number_passes++; - } else { - throw new RuntimeException("Error parsing \"VoidPointerExpansion\" command at line " + lineNo + - " in file \"" + filename + - "\"; expected some combination of boolean, char, byte, short, int, long, float, double"); - } - } catch (NoSuchElementException e) { - if(number_passes == 0) { - throw new RuntimeException( - "Error parsing \"VoidPointerExpansion\" command at line " + lineNo + - " in file \"" + filename + "\"", e); - } - finished = true; - } - } - } - - - - /** - * When void* arguments in the C function prototypes are encountered, the - * emitter will try to expand the binding and create Java entry points for - * all possible array types. If there are 2 or more void* arguments in the C - * prototype, this directive lets you specify which of those arguments - * should always be expanded to the same type. <p> - * - * For example, given the C prototype: - * <pre> - * void FuncName(void *foo, void *bar); - * </pre> - * - * The emitter will normally emit multiple Java entry points: - * <pre> - * public abstract void FuncName(boolean[] foo, java.nio.Buffer bar); - * public abstract void FuncName(boolean[] foo, boolean[] bar); - * public abstract void FuncName(boolean[] foo, byte[] bar); - * public abstract void FuncName(boolean[] foo, char[] bar); - * public abstract void FuncName(boolean[] foo, short[] bar); - * public abstract void FuncName(boolean[] foo, int[] bar); - * public abstract void FuncName(boolean[] foo, long[] bar); - * public abstract void FuncName(boolean[] foo, float[] bar); - * public abstract void FuncName(boolean[] foo, double[] bar); - * - * public abstract void FuncName(byte[] foo, java.nio.Buffer bar); - * public abstract void FuncName(byte[] foo, boolean[] bar); - * public abstract void FuncName(byte[] foo, byte[] bar); - * <...etc for all variants on the second parameter...> - * - * public abstract void FuncName(char[] foo, java.nio.Buffer bar); - * public abstract void FuncName(char[] foo, boolean[] bar); - * public abstract void FuncName(char[] foo, byte[] bar); - * <...etc for all variants on the second parameter...> - * <...and so on for all remaining variants on the first parameter...> - * </pre> - * - * This directive lets you specify that arguments at a particular index - * should always be expanded to the same type. For example, the directive: - * <pre> - * MirrorExpandedBindingArgs FuncName 0 1 - * </pre> - * will force the first and second arguments in function FuncName to be - * expanded identically. This would result in the emission of the following - * entry points only: - * <pre> - * public abstract void FuncName(java.nio.Buffer[] foo, java.nio.Buffer bar); - * public abstract void FuncName(boolean[] foo, boolean[] bar); - * public abstract void FuncName(byte[] foo, byte[] bar); - * public abstract void FuncName(char[] foo, char[] bar); - * public abstract void FuncName(short[] foo, short[] bar); - * public abstract void FuncName(int[] foo, int[] bar); - * public abstract void FuncName(long[] foo, long[] bar); - * public abstract void FuncName(float[] foo, float[] bar); - * public abstract void FuncName(double[] foo, double[] bar); - * </pre> - */ - protected void readMirrorExpandedBindingArgs(StringTokenizer tok, String filename, int lineNo) { - try { - String methodName = tok.nextToken(); - ArrayList argIndices = new ArrayList(2); - while (tok.hasMoreTokens()) - { - Integer idx = Integer.valueOf(tok.nextToken()); - argIndices.add(idx); - } - - if(argIndices.size() > 1) - { - mirroredArgs.put(methodName, argIndices); - } - else - { - throw new RuntimeException("ERROR: Error parsing \"MirrorExpandedBindingArgs\" command at line " + lineNo + - " in file \"" + filename + "\": directive requires at least 2 argument indices"); - } - } catch (NoSuchElementException e) { - throw new RuntimeException( - "Error parsing \"MirrorExpandedBindingArgs\" command at line " + lineNo + - " in file \"" + filename + "\"", e); - } - } - /** * When const char* arguments in the C function prototypes are encountered, * the emitter will normally convert them to <code>byte[]</code> diff --git a/src/net/java/games/gluegen/JavaEmitter.java b/src/net/java/games/gluegen/JavaEmitter.java index dad954db2..e260da992 100644 --- a/src/net/java/games/gluegen/JavaEmitter.java +++ b/src/net/java/games/gluegen/JavaEmitter.java @@ -300,170 +300,288 @@ public class JavaEmitter implements GlueEmitter { } /** + * Generates the public emitters for this MethodBinding which will + * produce either simply signatures (for the interface class, if + * any) or function definitions with or without a body (depending on + * whether or not the implementing function can go directly to + * native code because it doesn't need any processing of the + * outgoing arguments). + */ + protected void generatePublicEmitters(MethodBinding binding, + List allEmitters, + boolean signatureOnly) { + PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter()); + + if (cfg.manuallyImplement(binding.getName()) && !signatureOnly) { + // We only generate signatures for manually-implemented methods; + // user provides the implementation + return; + } + + // It's possible we may not need a body even if signatureOnly is + // set to false; for example, if the routine doesn't take any + // arrays or buffers as arguments + boolean isUnimplemented = cfg.isUnimplemented(binding.getName()); + boolean needsBody = (isUnimplemented || + (binding.needsNIOWrappingOrUnwrapping() || + binding.signatureUsesJavaPrimitiveArrays())); + + JavaMethodBindingEmitter emitter = + new JavaMethodBindingEmitter(binding, + writer, + cfg.runtimeExceptionType(), + !signatureOnly && needsBody, + false, + cfg.nioDirectOnly(binding.getName()), + false, + false, + false, + isUnimplemented); + emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); + if (cfg.allStatic()) { + emitter.addModifier(JavaMethodBindingEmitter.STATIC); + } + if (!isUnimplemented && !needsBody && !signatureOnly) { + emitter.addModifier(JavaMethodBindingEmitter.NATIVE); + } + emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); + allEmitters.add(emitter); + } + + /** + * Generates the private emitters for this MethodBinding. On the + * Java side these will simply produce signatures for native + * methods. On the C side these will create the emitters which will + * write the JNI code to interface to the functions. We need to be + * careful to make the signatures all match up and not produce too + * many emitters which would lead to compilation errors from + * creating duplicated methods / functions. + */ + protected void generatePrivateEmitters(MethodBinding binding, + List allEmitters) { + if (cfg.manuallyImplement(binding.getName())) { + // Don't produce emitters for the implementation class + return; + } + + // If we already generated a public native entry point for this + // method, don't emit another one + if (!cfg.isUnimplemented(binding.getName()) && + (binding.needsNIOWrappingOrUnwrapping() || + binding.signatureUsesJavaPrimitiveArrays())) { + PrintWriter writer = (cfg.allStatic() ? javaWriter() : javaImplWriter()); + + // If the binding uses primitive arrays, we are going to emit + // the private native entry point for it along with the version + // taking only NIO buffers + if (!binding.signatureUsesJavaPrimitiveArrays()) { + // (Always) emit the entry point taking only direct buffers + JavaMethodBindingEmitter emitter = + new JavaMethodBindingEmitter(binding, + writer, + cfg.runtimeExceptionType(), + false, + true, + cfg.nioDirectOnly(binding.getName()), + true, + true, + false, + false); + emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); + if (cfg.allStatic()) { + emitter.addModifier(JavaMethodBindingEmitter.STATIC); + } + emitter.addModifier(JavaMethodBindingEmitter.NATIVE); + emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); + allEmitters.add(emitter); + + // Optionally emit the entry point taking arrays which handles + // both the public entry point taking arrays as well as the + // indirect buffer case + if (!cfg.nioDirectOnly(binding.getName()) && + binding.signatureCanUseIndirectNIO()) { + emitter = + new JavaMethodBindingEmitter(binding, + writer, + cfg.runtimeExceptionType(), + false, + true, + false, + true, + false, + true, + false); + + emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); + if (cfg.allStatic()) { + emitter.addModifier(JavaMethodBindingEmitter.STATIC); + } + emitter.addModifier(JavaMethodBindingEmitter.NATIVE); + emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); + allEmitters.add(emitter); + } + } + } + + // Now generate the C emitter(s). We need to produce one for every + // Java native entry point (public or private). The only + // situations where we don't produce one are (a) when the method + // is unimplemented, and (b) when the signature contains primitive + // arrays, since the latter is handled by the method binding + // variant taking only NIO Buffers. + if (!cfg.isUnimplemented(binding.getName()) && + !binding.signatureUsesJavaPrimitiveArrays()) { + // See whether we need an expression to help calculate the + // length of any return type + MessageFormat returnValueCapacityFormat = null; + MessageFormat returnValueLengthFormat = null; + JavaType javaReturnType = binding.getJavaReturnType(); + if (javaReturnType.isNIOBuffer() || + javaReturnType.isCompoundTypeWrapper()) { + // See whether capacity has been specified + String capacity = cfg.returnValueCapacity(binding.getName()); + if (capacity != null) { + returnValueCapacityFormat = new MessageFormat(capacity); + } + } else if (javaReturnType.isArray() || + javaReturnType.isArrayOfCompoundTypeWrappers()) { + // NOTE: adding a check here because the CMethodBindingEmitter + // also doesn't yet handle returning scalar arrays. In order + // to implement this, return the type as a Buffer instead + // (i.e., IntBuffer, FloatBuffer) and add code as necessary. + if (javaReturnType.isPrimitiveArray()) { + throw new RuntimeException("Primitive array return types not yet supported"); + } + + // See whether length has been specified + String len = cfg.returnValueLength(binding.getName()); + if (len != null) { + returnValueLengthFormat = new MessageFormat(len); + } + } + + CMethodBindingEmitter cEmitter = + new CMethodBindingEmitter(binding, + cWriter(), + cfg.implPackageName(), + cfg.implClassName(), + true, /* NOTE: we always disambiguate with a suffix now, so this is optional */ + cfg.allStatic(), + binding.needsNIOWrappingOrUnwrapping(), + false); + if (returnValueCapacityFormat != null) { + cEmitter.setReturnValueCapacityExpression(returnValueCapacityFormat); + } + if (returnValueLengthFormat != null) { + cEmitter.setReturnValueLengthExpression(returnValueLengthFormat); + } + cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName())); + cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName())); + allEmitters.add(cEmitter); + + // Now see if we have to emit another entry point to handle the + // indirect buffer and array case + if (binding.argumentsUseNIO() && + binding.signatureCanUseIndirectNIO() && + !cfg.nioDirectOnly(binding.getName())) { + cEmitter = + new CMethodBindingEmitter(binding, + cWriter(), + cfg.implPackageName(), + cfg.implClassName(), + true, /* NOTE: we always disambiguate with a suffix now, so this is optional */ + cfg.allStatic(), + binding.needsNIOWrappingOrUnwrapping(), + true); + if (returnValueCapacityFormat != null) { + cEmitter.setReturnValueCapacityExpression(returnValueCapacityFormat); + } + if (returnValueLengthFormat != null) { + cEmitter.setReturnValueLengthExpression(returnValueLengthFormat); + } + cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName())); + cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName())); + allEmitters.add(cEmitter); + } + } + } + + /** * Generate all appropriate Java bindings for the specified C function * symbols. */ protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception { - ArrayList/*<FunctionEmitter>*/ allEmitters = new ArrayList(1); + ArrayList/*<FunctionEmitter>*/ allEmitters = new ArrayList(); try { // Get Java binding for the function MethodBinding mb = bindFunction(sym, null, null); - // Expand all void* arguments + // JavaTypes representing C pointers in the initial + // MethodBinding have not been lowered yet to concrete types List bindings = expandMethodBinding(mb); - boolean overloaded = (bindings.size() > 1); - if (overloaded) { - // resize ahead of time for speed - allEmitters.ensureCapacity(bindings.size()); - } - - // List of the indices of the arguments in this function that should be - // expanded to the same type when binding functions with multiple void* - // arguments - List mirrorIdxs = cfg.mirroredArgs(sym.getName()); for (Iterator iter = bindings.iterator(); iter.hasNext(); ) { MethodBinding binding = (MethodBinding) iter.next(); - // Honor the MirrorExpandedBindingArgs directive in .cfg files - if (mirrorIdxs != null) { - assert(mirrorIdxs.size() >= 2); // sanity check. - boolean typesMatch = true; - int argIndex = ((Integer)mirrorIdxs.get(0)).intValue(); - JavaType leftArgType = binding.getJavaArgumentType(argIndex); - for (int i = 1; i < mirrorIdxs.size(); ++i) { - argIndex = ((Integer)mirrorIdxs.get(i)).intValue(); - JavaType rightArgType = binding.getJavaArgumentType(argIndex); - if (!(leftArgType.equals(rightArgType))) { - typesMatch = false; - break; - } - leftArgType = rightArgType; - } - // Don't emit the binding if the specified args aren't the same type - if (!typesMatch) { continue; } // skip this binding - } - - // Try to create an NIOBuffer variant for this expanded binding. If - // it's the same as the original binding, then we'll be able to emit - // the binding like any normal binding because no special binding - // generation (wrapper methods, etc) will be necessary. - MethodBinding specialBinding = binding.createNIOBufferVariant(); - - if (cfg.allStatic() && binding.hasContainingType()) { // This should not currently happen since structs are emitted using a different mechanism throw new IllegalArgumentException("Cannot create binding in AllStatic mode because method has containing type: \"" + binding + "\""); } - boolean isUnimplemented = cfg.isUnimplemented(binding.getName()); - JavaMethodBindingImplEmitter entryPoint=null; - - if (cfg.emitImpl()) { - // Generate the emitter for the method which may do conversion - // from type wrappers to NIO Buffers or which may call the - // underlying function directly - - boolean arrayImplMethod = false; - if(binding.signatureUsesPrimitiveArrays()) { - //overloaded = true; - arrayImplMethod = true; - } - - entryPoint = new JavaMethodBindingImplEmitter(binding, - (cfg.allStatic() ? javaWriter() : javaImplWriter()), - cfg.runtimeExceptionType(), - isUnimplemented, - arrayImplMethod); - entryPoint.addModifier(JavaMethodBindingEmitter.PUBLIC); - if (cfg.allStatic()) { - entryPoint.addModifier(JavaMethodBindingEmitter.STATIC); - } - if (!isUnimplemented && !bindingNeedsBody(binding)) { - entryPoint.addModifier(JavaMethodBindingEmitter.NATIVE); - } - entryPoint.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); - allEmitters.add(entryPoint); - } + // The structure of the generated glue code looks something like this: + // Simple method (no arrays, void pointers, etc.): + // Interface class: + // public void fooMethod(); + // Implementation class: + // public native void fooMethod(); + // + // Method taking void* argument: + // Interface class: + // public void fooMethod(Buffer arg); + // Implementation class: + // public void fooMethod(Buffer arg) { + // ... bounds checks, etc. ... + // if (arg.isDirect()) { + // fooMethod0(arg, computeDirectBufferByteOffset(arg)); + // } else { + // fooMethod1(getIndirectBufferArray(arg), computeIndirectBufferByteOffset(arg)); + // } + // } + // private native void fooMethod0(Object arg, int arg_byte_offset); + // private native void fooMethod1(Object arg, int arg_byte_offset); + // + // Method taking primitive array argument: + // Interface class: + // public void fooMethod(int[] arg, int arg_offset); + // public void fooMethod(IntBuffer arg); + // Implementing class: + // public void fooMethod(int[] arg, int arg_offset) { + // ... range checks, etc. ... + // fooMethod1(arg, SIZEOF_INT * arg_offset); + // } + // public void fooMethod(IntBuffer arg) { + // ... bounds checks, etc. ... + // if (arg.isDirect()) { + // fooMethod0(arg, computeDirectBufferByteOffset(arg)); + // } else { + // fooMethod1(getIndirectBufferArray(arg), computeIndirectBufferByteOffset(arg)); + // } + // } + // private native void fooMethod0(Object arg, int arg_byte_offset); + // private native void fooMethod1(Object arg, int arg_byte_offset); + // + // Note in particular that the public entry point taking an + // array is merely a special case of the indirect buffer case. if (cfg.emitInterface()) { - // Generate an emitter that will emit just the interface to the function - JavaMethodBindingEmitter entryPointInterface = - new JavaMethodBindingEmitter(binding, javaWriter(), cfg.runtimeExceptionType()); - entryPointInterface.addModifier(JavaMethodBindingEmitter.PUBLIC); - entryPointInterface.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); - allEmitters.add(entryPointInterface); + generatePublicEmitters(binding, allEmitters, true); } - if (cfg.emitImpl()) { - // If the user has stated that the function will be - // manually implemented, then don't auto-generate a function body. - if (!cfg.manuallyImplement(sym.getName()) && !isUnimplemented) { - // need to check if should create CMethodBindingImplEmitter instead of just - // CMethodBindingEmitter. Basically adds a "0" to JNI method name - boolean arrayImplMethod = false; - - if (bindingNeedsBody(binding)) { - // Generate the method which calls the underlying C function - // after unboxing has occurred - PrintWriter output = cfg.allStatic() ? javaWriter() : javaImplWriter(); - if(binding.signatureUsesPrimitiveArrays()) { - arrayImplMethod = true; - } - JavaMethodBindingEmitter wrappedEntryPoint = - new JavaMethodBindingEmitter(specialBinding, output, cfg.runtimeExceptionType(), true, - arrayImplMethod); - wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.PRIVATE); - wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.STATIC); // Doesn't really matter - wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.NATIVE); - allEmitters.add(wrappedEntryPoint); - - String bindingName = specialBinding.getName(); - if(binding != specialBinding && bindingName.contains("gl") && !bindingName.contains("glX") - && !bindingName.contains("wgl") && !bindingName.contains("CGL")) { - JavaMethodBindingEmitter wrappedEntryPoint2 = - new JavaMethodBindingEmitter(specialBinding, output, cfg.runtimeExceptionType(), - true, arrayImplMethod); - wrappedEntryPoint2.addModifier(JavaMethodBindingEmitter.PRIVATE); - wrappedEntryPoint2.addModifier(JavaMethodBindingEmitter.STATIC); // Doesn't really matter - wrappedEntryPoint2.addModifier(JavaMethodBindingEmitter.NATIVE); - - entryPoint.setGenerateIndirectBufferInterface(true); - wrappedEntryPoint2.setIndirectBufferInterface(true); - allEmitters.add(wrappedEntryPoint2); - } - - } - - CMethodBindingEmitter cEmitter = - makeCEmitter(specialBinding, - overloaded, - (binding != specialBinding), - arrayImplMethod, - cfg.implPackageName(), cfg.implClassName(), - cWriter()); - allEmitters.add(cEmitter); - - String bindingName = specialBinding.getName(); - if(binding != specialBinding && bindingName.contains("gl") && !bindingName.contains("glX") - && !bindingName.contains("wgl") && !bindingName.contains("CGL") ) { - - CMethodBindingEmitter cEmitter2 = - makeCEmitter(specialBinding, - //overloaded, - true, - true, - arrayImplMethod, - cfg.implPackageName(), cfg.implClassName(), - cWriter()); - cEmitter2.setIndirectBufferInterface(true); - allEmitters.add(cEmitter2); - } - - } + generatePublicEmitters(binding, allEmitters, false); + generatePrivateEmitters(binding, allEmitters); } } // end iteration over expanded bindings } catch (Exception e) { @@ -615,29 +733,49 @@ public class JavaEmitter implements GlueEmitter { FunctionSymbol funcSym = new FunctionSymbol(field.getName(), funcType); MethodBinding binding = bindFunction(funcSym, containingType, containingCType); binding.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis - MethodBinding specialBinding = binding.createNIOBufferVariant(); writer.println(); - JavaMethodBindingEmitter entryPoint = new JavaMethodBindingImplEmitter(binding, writer, cfg.runtimeExceptionType()); - entryPoint.addModifier(JavaMethodBindingEmitter.PUBLIC); - if (!bindingNeedsBody(binding) && !binding.hasContainingType()) { - entryPoint.addModifier(JavaMethodBindingEmitter.NATIVE); - } - entryPoint.emit(); - - JavaMethodBindingEmitter wrappedEntryPoint = new JavaMethodBindingEmitter(specialBinding, writer, cfg.runtimeExceptionType(), true, false); - wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.PRIVATE); - wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.NATIVE); - wrappedEntryPoint.emit(); - + // Emit public Java entry point for calling this function pointer + JavaMethodBindingEmitter emitter = + new JavaMethodBindingEmitter(binding, + writer, + cfg.runtimeExceptionType(), + true, + false, + 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); + emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); + emitter.emit(); + + // Emit private native Java entry point for calling this function pointer + emitter = + new JavaMethodBindingEmitter(binding, + writer, + cfg.runtimeExceptionType(), + false, + true, + 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); + emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); + emitter.addModifier(JavaMethodBindingEmitter.NATIVE); + emitter.emit(); + + // Emit (private) C entry point for calling this function pointer CMethodBindingEmitter cEmitter = - makeCEmitter(specialBinding, - false, // overloaded - true, // doing NIO impl routine? - false, // array impl method ? - structClassPkg, - containingTypeName, - cWriter); + new CMethodBindingEmitter(binding, + cWriter, + structClassPkg, + containingTypeName, + true, // FIXME: this is optional at this point + false, + true, + false); // FIXME: should unify this with the general emission code cEmitter.emit(); } catch (Exception e) { System.err.println("While processing field " + field + " of type " + name + ":"); @@ -726,59 +864,6 @@ public class JavaEmitter implements GlueEmitter { // Internals only below this point // - protected boolean bindingNeedsBody(MethodBinding binding) { - // We need to perform NIO checks and conversions and array length - // checks - return binding.signatureUsesNIO() || binding.signatureUsesCArrays() || binding.signatureUsesPrimitiveArrays(); - } - - private CMethodBindingEmitter makeCEmitter(MethodBinding binding, - boolean overloaded, - boolean doingNIOImplRoutine, - boolean doingArrayImplRoutine, - String bindingJavaPackageName, - String bindingJavaClassName, - PrintWriter output) { - MessageFormat returnValueCapacityFormat = null; - MessageFormat returnValueLengthFormat = null; - JavaType javaReturnType = binding.getJavaReturnType(); - if (javaReturnType.isNIOBuffer()) { - // See whether capacity has been specified - String capacity = cfg.returnValueCapacity(binding.getName()); - if (capacity != null) { - returnValueCapacityFormat = new MessageFormat(capacity); - } - } else if (javaReturnType.isArray()) { - // See whether length has been specified - String len = cfg.returnValueLength(binding.getName()); - if (len != null) { - returnValueLengthFormat = new MessageFormat(len); - } - } - CMethodBindingEmitter cEmitter; - if (doingNIOImplRoutine || doingArrayImplRoutine) { - cEmitter = new CMethodBindingImplEmitter(binding, overloaded, - doingArrayImplRoutine, - bindingJavaPackageName, - bindingJavaClassName, - cfg.allStatic(), output); - } else { - cEmitter = new CMethodBindingEmitter(binding, overloaded, - bindingJavaPackageName, - bindingJavaClassName, - cfg.allStatic(), output); - } - if (returnValueCapacityFormat != null) { - cEmitter.setReturnValueCapacityExpression(returnValueCapacityFormat); - } - if (returnValueLengthFormat != null) { - cEmitter.setReturnValueLengthExpression(returnValueLengthFormat); - } - cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName())); - cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName())); - return cEmitter; - } - private JavaType typeToJavaType(Type cType, boolean outgoingArgument) { // Recognize JNIEnv* case up front PointerType opt = cType.asPointer(); @@ -1233,6 +1318,12 @@ public class JavaEmitter implements GlueEmitter { return JavaType.createForClass(c); } + /** Maps the C types in the specified function to Java types through + the MethodBinding interface. Note that the JavaTypes in the + returned MethodBinding are "intermediate" JavaTypes (some + potentially representing C pointers rather than true Java types) + and must be lowered to concrete Java types before creating + emitters for them. */ private MethodBinding bindFunction(FunctionSymbol sym, JavaType containingType, Type containingCType) { @@ -1292,207 +1383,119 @@ public class JavaEmitter implements GlueEmitter { return binding; } - // Expands a MethodBinding containing C primitive pointer types into - // multiple variants taking Java primitive arrays and NIO buffers, subject - // to the per-function "NIO only" rule in the configuration file - private List/*<MethodBinding>*/ expandMethodBinding(MethodBinding binding) { - List result = new ArrayList(); - result.add(binding); - int i = 0; - while (i < result.size()) { - MethodBinding mb = (MethodBinding) result.get(i); - boolean shouldRemoveCurrent = false; - for (int j = 0; j < mb.getNumArguments(); j++) { - JavaType t = mb.getJavaArgumentType(j); - if (t.isCPrimitivePointerType()) { - // Remove original from list - shouldRemoveCurrent = true; - MethodBinding variant = null; - - // Non-NIO variants for non-void C primitive pointer types - if (!cfg.nioDirectOnly(mb.getCSymbol().getName()) && !t.isCVoidPointerType() - && !cfg.isPrimArrayExpModeNoPtrs()) { - if (t.isCCharPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.byteArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (t.isCShortPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.shortArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (t.isCInt32PointerType()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.intArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (t.isCInt64PointerType()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.longArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (t.isCFloatPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.floatArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (t.isCDoublePointerType()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.doubleArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - } - - // Non-NIO variants for void* C primitive pointer type - if (!cfg.nioDirectOnly(mb.getCSymbol().getName()) && t.isCVoidPointerType() - && cfg.isPrimArrayExpModeAllPtrs()) { - if (cfg.voidPointerExpansionToBoolean()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.booleanArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToChar()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.charArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToByte()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.byteArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToShort()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.shortArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToInt()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.intArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToLong()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.longArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToFloat()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.floatArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - if (cfg.voidPointerExpansionToDouble()) { - variant = mb.createCPrimitivePointerVariant(j, javaType(ArrayTypes.doubleArrayClass)); - if (! result.contains(variant)) result.add(variant); - } + private MethodBinding lowerMethodBindingPointerTypes(MethodBinding inputBinding, + boolean convertToArrays, + boolean[] canProduceArrayVariant) { + MethodBinding result = inputBinding; + boolean arrayPossible = false; + + for (int i = 0; i < inputBinding.getNumArguments(); i++) { + JavaType t = inputBinding.getJavaArgumentType(i); + if (t.isCPrimitivePointerType()) { + if (t.isCVoidPointerType()) { + // These are always bound to java.nio.Buffer + result = result.replaceJavaArgumentType(i, JavaType.forNIOBufferClass()); + } else if (t.isCCharPointerType()) { + arrayPossible = true; + if (convertToArrays) { + result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.byteArrayClass)); + } else { + result = result.replaceJavaArgumentType(i, JavaType.forNIOByteBufferClass()); } - - - // NIO variant for void* C primitive pointer type - if (!cfg.noNio(mb.getCSymbol().getName())) { - if (t.isCVoidPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIOBufferClass()); - if (! result.contains(variant)) result.add(variant); - } + } else if (t.isCShortPointerType()) { + arrayPossible = true; + if (convertToArrays) { + result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.shortArrayClass)); + } else { + result = result.replaceJavaArgumentType(i, JavaType.forNIOShortBufferClass()); } - - - // NIO variants for non-void* C primitive pointer types - if ((cfg.nioMode() == JavaConfiguration.NIO_MODE_ALL_POINTERS && - !cfg.noNio(mb.getCSymbol().getName())) || - (cfg.nioMode() == JavaConfiguration.NIO_MODE_VOID_ONLY && - cfg.forcedNio(mb.getCSymbol().getName()))) { - if (t.isCCharPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIOByteBufferClass()); - if (! result.contains(variant)) result.add(variant); - } - - if (t.isCShortPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIOShortBufferClass()); - if (! result.contains(variant)) result.add(variant); - } - - if (t.isCInt32PointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIOIntBufferClass()); - if (! result.contains(variant)) result.add(variant); - } - - if (t.isCInt64PointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIOLongBufferClass()); - if (! result.contains(variant)) result.add(variant); - } - - if (t.isCFloatPointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIOFloatBufferClass()); - if (! result.contains(variant)) result.add(variant); - } - - if (t.isCDoublePointerType()) { - variant = mb.createCPrimitivePointerVariant(j, JavaType.forNIODoubleBufferClass()); - if (! result.contains(variant)) result.add(variant); - } + } else if (t.isCInt32PointerType()) { + arrayPossible = true; + if (convertToArrays) { + result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.intArrayClass)); + } else { + result = result.replaceJavaArgumentType(i, JavaType.forNIOIntBufferClass()); + } + } else if (t.isCInt64PointerType()) { + arrayPossible = true; + if (convertToArrays) { + result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.longArrayClass)); + } else { + result = result.replaceJavaArgumentType(i, JavaType.forNIOLongBufferClass()); + } + } else if (t.isCFloatPointerType()) { + arrayPossible = true; + if (convertToArrays) { + result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.floatArrayClass)); + } else { + result = result.replaceJavaArgumentType(i, JavaType.forNIOFloatBufferClass()); + } + } else if (t.isCDoublePointerType()) { + arrayPossible = true; + if (convertToArrays) { + result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.doubleArrayClass)); + } else { + result = result.replaceJavaArgumentType(i, JavaType.forNIODoubleBufferClass()); } + } else { + throw new RuntimeException("Unknown C pointer type " + t); } } + } - if (mb.getJavaReturnType().isCPrimitivePointerType()) { - MethodBinding variant = null; - if (mb.getJavaReturnType().isCVoidPointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, JavaType.forNIOByteBufferClass()); - if (! result.contains(variant)) result.add(variant); - } else if (mb.getJavaReturnType().isCCharPointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, javaType(ArrayTypes.byteArrayClass)); - if (! result.contains(variant)) result.add(variant); - } else if (mb.getJavaReturnType().isCShortPointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, javaType(ArrayTypes.shortArrayClass)); - if (! result.contains(variant)) result.add(variant); - } else if (mb.getJavaReturnType().isCInt32PointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, javaType(ArrayTypes.intArrayClass)); - if (! result.contains(variant)) result.add(variant); - } else if (mb.getJavaReturnType().isCInt64PointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, javaType(ArrayTypes.longArrayClass)); - if (! result.contains(variant)) result.add(variant); - } else if (mb.getJavaReturnType().isCFloatPointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, javaType(ArrayTypes.floatArrayClass)); - if (! result.contains(variant)) result.add(variant); - } else if (mb.getJavaReturnType().isCDoublePointerType()) { - variant = mb.createCPrimitivePointerVariant(-1, javaType(ArrayTypes.doubleArrayClass)); - if (! result.contains(variant)) result.add(variant); - } - shouldRemoveCurrent = true; - } - if (shouldRemoveCurrent) { - result.remove(i); - --i; + // Always return primitive pointer types as NIO buffers + JavaType t = result.getJavaReturnType(); + if (t.isCPrimitivePointerType()) { + if (t.isCVoidPointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIOByteBufferClass()); + } else if (t.isCCharPointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIOByteBufferClass()); + } else if (t.isCShortPointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIOShortBufferClass()); + } else if (t.isCInt32PointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIOIntBufferClass()); + } else if (t.isCInt64PointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIOLongBufferClass()); + } else if (t.isCFloatPointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIOFloatBufferClass()); + } else if (t.isCDoublePointerType()) { + result = result.replaceJavaArgumentType(-1, JavaType.forNIODoubleBufferClass()); + } else { + throw new RuntimeException("Unknown C pointer type " + t); } - ++i; - } - - // Honor the flattenNIOVariants directive in the configuration file - // FlattenNIOVariants <boolean> - // true: If there are multiple arguments in a method signature that map - // to NIO buffer, do not pair an NIO buffer argument with a primitive - // array argument - // false: Allow cross-pairing of nio and primitive array arguments in a - // single method signature. - if (cfg.flattenNIOVariants()) { - i = 0; - while (i < result.size()) { - boolean shouldRemoveCurrent = false; - MethodBinding mb = (MethodBinding) result.get(i); - for (int j = 0; j < binding.getNumArguments() && !shouldRemoveCurrent; j++) { - JavaType t1 = binding.getJavaArgumentType(j); - if (t1.isCPrimitivePointerType() && !t1.isCVoidPointerType()) { - for (int k = j + 1; k < binding.getNumArguments() && !shouldRemoveCurrent; k++) { - JavaType t2 = binding.getJavaArgumentType(k); - if (t2.isCPrimitivePointerType() && !t2.isCVoidPointerType()) { - // The "NIO-ness" of the converted arguments in the - // new binding must match - JavaType nt1 = mb.getJavaArgumentType(j); - JavaType nt2 = mb.getJavaArgumentType(k); - if (nt1.isNIOBuffer() != nt2.isNIOBuffer()) { - shouldRemoveCurrent = true; - } - } - } - } - } - if (shouldRemoveCurrent) { - result.remove(i); - --i; - } + } + + if (canProduceArrayVariant != null) { + canProduceArrayVariant[0] = arrayPossible; + } - ++i; + return result; + } + + // Expands a MethodBinding containing C primitive pointer types into + // multiple variants taking Java primitive arrays and NIO buffers, subject + // to the per-function "NIO only" rule in the configuration file + private List/*<MethodBinding>*/ expandMethodBinding(MethodBinding binding) { + List result = new ArrayList(); + // Indicates whether it is possible to produce an array variant + // Prevents e.g. char* -> String conversions from emitting two entry points + boolean[] canProduceArrayVariant = new boolean[1]; + + if (binding.signatureUsesCPrimitivePointers() || + binding.signatureUsesCVoidPointers() || + binding.signatureUsesCArrays()) { + result.add(lowerMethodBindingPointerTypes(binding, false, canProduceArrayVariant)); + + // FIXME: should add new configuration flag for this + if (canProduceArrayVariant[0] && + (binding.signatureUsesCPrimitivePointers() || + binding.signatureUsesCArrays()) && + !cfg.nioDirectOnly(binding.getName())) { + result.add(lowerMethodBindingPointerTypes(binding, true, null)); } + } else { + result.add(binding); } return result; diff --git a/src/net/java/games/gluegen/JavaMethodBindingEmitter.java b/src/net/java/games/gluegen/JavaMethodBindingEmitter.java index 1d227dfc9..8c5cd2caf 100644 --- a/src/net/java/games/gluegen/JavaMethodBindingEmitter.java +++ b/src/net/java/games/gluegen/JavaMethodBindingEmitter.java @@ -39,8 +39,9 @@ package net.java.games.gluegen; -import java.util.*; import java.io.*; +import java.util.*; +import java.text.MessageFormat; import net.java.games.gluegen.cgram.types.*; import net.java.games.gluegen.cgram.*; @@ -58,20 +59,22 @@ public class JavaMethodBindingEmitter extends FunctionEmitter public static final EmissionModifier NATIVE = new EmissionModifier("native"); public static final EmissionModifier SYNCHRONIZED = new EmissionModifier("synchronized"); - protected static final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter(); - protected static final CommentEmitter defaultInterfaceCommentEmitter = + protected final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter(); + protected final CommentEmitter defaultInterfaceCommentEmitter = new InterfaceCommentEmitter(); // Exception type raised in the generated code if runtime checks fail private String runtimeExceptionType; - protected MethodBinding binding; + protected boolean emitBody; + protected boolean eraseBufferAndArrayTypes; + protected boolean directNIOOnly; protected boolean forImplementingMethodCall; - protected boolean forArrayImplementingMethodCall = false; - - protected boolean prefixedMethod = false; + protected boolean forDirectBufferImplementation; + protected boolean forIndirectBufferAndArrayImplementation; + protected boolean isUnimplemented; - protected boolean indirectBufferInterface = false; + protected MethodBinding binding; // A non-null value indicates that rather than returning a compound // type accessor we are returning an array of such accessors; this @@ -80,26 +83,45 @@ public class JavaMethodBindingEmitter extends FunctionEmitter // number of elements of the returned array. private String returnedArrayLengthExpression; - public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType) - { - this(binding, output, runtimeExceptionType, false, false); - } - - public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType, boolean forImplementingMethodCall, boolean forArrayImplementingMethodCall) + public JavaMethodBindingEmitter(MethodBinding binding, + PrintWriter output, + String runtimeExceptionType, + boolean emitBody, + boolean eraseBufferAndArrayTypes, + boolean directNIOOnly, + boolean forImplementingMethodCall, + boolean forDirectBufferImplementation, + boolean forIndirectBufferAndArrayImplementation, + boolean isUnimplemented) { super(output); this.binding = binding; - this.forImplementingMethodCall = forImplementingMethodCall; - this.forArrayImplementingMethodCall = forArrayImplementingMethodCall; this.runtimeExceptionType = runtimeExceptionType; - setCommentEmitter(defaultInterfaceCommentEmitter); + this.emitBody = emitBody; + this.eraseBufferAndArrayTypes = eraseBufferAndArrayTypes; + this.directNIOOnly = directNIOOnly; + this.forImplementingMethodCall = forImplementingMethodCall; + this.forDirectBufferImplementation = forDirectBufferImplementation; + this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation; + this.isUnimplemented = isUnimplemented; + if (forImplementingMethodCall) { + setCommentEmitter(defaultJavaCommentEmitter); + } else { + setCommentEmitter(defaultInterfaceCommentEmitter); + } } public JavaMethodBindingEmitter(JavaMethodBindingEmitter arg) { super(arg); - runtimeExceptionType = arg.runtimeExceptionType; binding = arg.binding; + runtimeExceptionType = arg.runtimeExceptionType; + emitBody = arg.emitBody; + eraseBufferAndArrayTypes = arg.eraseBufferAndArrayTypes; + directNIOOnly = arg.directNIOOnly; forImplementingMethodCall = arg.forImplementingMethodCall; + forDirectBufferImplementation = arg.forDirectBufferImplementation; + forIndirectBufferAndArrayImplementation = arg.forIndirectBufferAndArrayImplementation; + isUnimplemented = arg.isUnimplemented; returnedArrayLengthExpression = arg.returnedArrayLengthExpression; } @@ -111,16 +133,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter return binding.getName(); } - public boolean isIndirectBufferInterface() { - return indirectBufferInterface; - } - - - public void setIndirectBufferInterface(boolean indirect) { - indirectBufferInterface = indirect; - } - - /** The type of exception (must subclass <code>java.lang.RuntimeException</code>) raised if runtime checks fail in the generated code. */ @@ -139,23 +151,78 @@ public class JavaMethodBindingEmitter extends FunctionEmitter returnedArrayLengthExpression = expr; } + /** Indicates whether this emitter will print only a signature, or + whether it will emit Java code for the body of the method as + well. */ + public boolean signatureOnly() { + return !emitBody; + } + + /** Accessor for subclasses. */ + public void setEmitBody(boolean emitBody) { + this.emitBody = emitBody; + } + + /** Accessor for subclasses. */ + public void setEraseBufferAndArrayTypes(boolean erase) { + this.eraseBufferAndArrayTypes = erase; + } + + /** Accessor for subclasses. */ + public void setForImplementingMethodCall(boolean impl) { + this.forImplementingMethodCall = impl; + } + protected void emitReturnType(PrintWriter writer) { writer.print(getReturnTypeString(false)); } + protected String erasedTypeString(JavaType type, boolean skipBuffers) { + if (eraseBufferAndArrayTypes) { + if (type.isNIOBuffer() || + type.isPrimitiveArray()) { + if (!skipBuffers) { + // Direct buffers and arrays sent down as Object (but + // returned as e.g. ByteBuffer) + return "Object"; + } + } else if (type.isCompoundTypeWrapper()) { + // Compound type wrappers are unwrapped to ByteBuffer + return "java.nio.ByteBuffer"; + } else if (type.isArrayOfCompoundTypeWrappers()) { + return "java.nio.ByteBuffer"; + } + } + return type.getName(); + } + protected String getReturnTypeString(boolean skipArray) { - if (skipArray || (getReturnedArrayLengthExpression() == null && - !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers())) { - return binding.getJavaReturnType().getName(); + // The first arm of the "if" clause is used by the glue code + // generation for arrays of compound type wrappers + if (skipArray || + // The following arm is used by most other kinds of return types + (getReturnedArrayLengthExpression() == null && + !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers()) || + // The following arm is used specifically to get the splitting up + // of one returned ByteBuffer into an array of compound type + // wrappers to work (e.g., XGetVisualInfo) + (eraseBufferAndArrayTypes && + binding.getJavaReturnType().isCompoundTypeWrapper() && + (getReturnedArrayLengthExpression() != null))) { + return erasedTypeString(binding.getJavaReturnType(), true); } - return binding.getJavaReturnType().getName() + "[]"; + return erasedTypeString(binding.getJavaReturnType(), true) + "[]"; } protected void emitName(PrintWriter writer) { if (forImplementingMethodCall) { - writer.print(getImplMethodName()); + if (forIndirectBufferAndArrayImplementation) { + writer.print(getImplMethodName(false)); + } else { + writer.print(getImplMethodName(true)); + } } else { writer.print(getName()); } @@ -165,16 +232,13 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { boolean needComma = false; int numEmitted = 0; - int numBufferOffsetArgs = 0, numBufferOffsetArrayArgs = 0; if (forImplementingMethodCall && binding.hasContainingType()) { // Always emit outgoing "this" argument - writer.print("java.nio.Buffer "); + writer.print("java.nio.ByteBuffer "); writer.print(javaThisArgumentName()); ++numEmitted; needComma = true; - numBufferOffsetArgs++; - writer.print(", int " + byteOffsetConversionArgName(numBufferOffsetArgs)); } for (int i = 0; i < binding.getNumArguments(); i++) { @@ -199,69 +263,354 @@ public class JavaMethodBindingEmitter extends FunctionEmitter writer.print(", "); } - // indirect buffer array sent down as object - if(isIndirectBufferInterface() && type.isNIOBuffer() ) { - writer.print(" Object "); - } else { - writer.print(type.getName()); - } - + writer.print(erasedTypeString(type, false)); writer.print(" "); writer.print(binding.getArgumentName(i)); - ++numEmitted; needComma = true; - // Add Buffer offset argument to store the buffer offset - if((forImplementingMethodCall || prefixedMethod) && - (type.isNIOBuffer() || type.isNIOBufferArray())) { - if(!type.isArray()) { - numBufferOffsetArgs++; - writer.print(", int " + byteOffsetConversionArgName(numBufferOffsetArgs)); - } else { - numBufferOffsetArrayArgs++; - writer.print(", int[] " + - byteOffsetArrayConversionArgName(numBufferOffsetArrayArgs)); - } + // Add Buffer and array index offset arguments after each associated argument + if (forDirectBufferImplementation || forIndirectBufferAndArrayImplementation) { + if (type.isNIOBuffer()) { + writer.print(", int " + byteOffsetArgName(i)); + } else if (type.isNIOBufferArray()) { + writer.print(", int[] " + + byteOffsetArrayArgName(i)); + } } - // Add array index offset argument after each primitive array - if( type.isArray() && !type.isNIOBufferArray() && !type.isStringArray()) { - writer.print(", int " + binding.getArgumentName(i) + "_offset"); + // Add offset argument after each primitive array + if (type.isPrimitiveArray()) { + writer.print(", int " + offsetArgName(i)); } - } return numEmitted; } - protected String getImplMethodName() - { - if( isIndirectBufferInterface() ) - return binding.getName() + "2"; - else if(!forArrayImplementingMethodCall) - return binding.getName() + "0"; - else - return binding.getName() + "1"; + protected String getImplMethodName(boolean direct) { + if (direct) { + return binding.getName() + "0"; + } else { + return binding.getName() + "1"; + } } + protected String byteOffsetArgName(int i) { + return byteOffsetArgName(binding.getArgumentName(i)); + } - protected String byteOffsetConversionArgName(int i) { - return "__byteOffset" + i; + protected String byteOffsetArgName(String s) { + return s + "_byte_offset"; } - protected String byteOffsetArrayConversionArgName(int i) { - return "__byteOffsetArray" + i; + protected String byteOffsetArrayArgName(int i) { + return binding.getArgumentName(i) + "_byte_offset_array"; } + protected String offsetArgName(int i) { + return binding.getArgumentName(i) + "_offset"; + } protected void emitBody(PrintWriter writer) { - writer.println(';'); + if (!emitBody) { + writer.println(';'); + } else { + MethodBinding binding = getBinding(); + writer.println(); + writer.println(" {"); + if (isUnimplemented) { + writer.println(" throw new " + getRuntimeExceptionType() + "(\"Unimplemented\");"); + } else { + emitPreCallSetup(binding, writer); + //emitReturnVariableSetup(binding, writer); + emitReturnVariableSetupAndCall(binding, writer); + } + writer.println(" }"); + } } - protected static String javaThisArgumentName() { + protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) { + emitArrayLengthAndNIOBufferChecks(binding, writer); + } + + protected void emitArrayLengthAndNIOBufferChecks(MethodBinding binding, PrintWriter writer) { + int numBufferOffsetArrayArgs = 0; + boolean firstBuffer = true; + // Check lengths of any incoming arrays if necessary + for (int i = 0; i < binding.getNumArguments(); i++) { + Type type = binding.getCArgumentType(i); + if (type.isArray()) { + ArrayType arrayType = type.asArray(); + writer.println(" if (" + binding.getArgumentName(i) + ".length < " + + arrayType.getLength() + ")"); + writer.println(" throw new " + getRuntimeExceptionType() + + "(\"Length of array \\\"" + binding.getArgumentName(i) + + "\\\" was less than the required " + arrayType.getLength() + "\");"); + } else { + JavaType javaType = binding.getJavaArgumentType(i); + if (javaType.isNIOBuffer()) { + if (directNIOOnly) { + writer.println(" if (!BufferFactory.isDirect(" + binding.getArgumentName(i) + "))"); + writer.println(" throw new " + getRuntimeExceptionType() + "(\"Argument \\\"" + + binding.getArgumentName(i) + "\\\" was not a direct buffer\");"); + } else { + if(firstBuffer) { + firstBuffer = false; + writer.println(" boolean _direct = BufferFactory.isDirect(" + binding.getArgumentName(i) + ");"); + } else { + writer.println(" if (_direct != BufferFactory.isDirect(" + binding.getArgumentName(i) + "))"); + writer.println(" throw new " + getRuntimeExceptionType() + + "(\"Argument \\\"" + binding.getArgumentName(i) + + "\\\" : Buffers passed to this method must all be either direct or indirect\");"); + } + } + } else if (javaType.isNIOBufferArray()) { + // All buffers passed down in an array of NIO buffers must be direct + String argName = binding.getArgumentName(i); + String arrayName = byteOffsetArrayArgName(i); + writer.println(" int[] " + arrayName + " = new int[" + argName + ".length];"); + // Check direct buffer properties of all buffers within + writer.println(" if (" + argName + " != null) {"); + writer.println(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {"); + writer.println(" if (!BufferFactory.isDirect(" + argName + "[_ctr])) {"); + writer.println(" throw new " + getRuntimeExceptionType() + + "(\"Element \" + _ctr + \" of argument \\\"" + + binding.getArgumentName(i) + "\\\" was not a direct buffer\");"); + writer.println(" }"); + // get the Buffer Array offset values and save them into another array to send down to JNI + writer.print (" " + arrayName + "[_ctr] = BufferFactory.getDirectBufferByteOffset("); + writer.println(argName + "[_ctr]);"); + writer.println(" }"); + writer.println(" }"); + } else if (javaType.isPrimitiveArray()) { + String argName = binding.getArgumentName(i); + String offsetArg = offsetArgName(i); + writer.println(" if(" + argName + " != null && " + argName + ".length <= " + offsetArg + ")"); + writer.print (" throw new " + getRuntimeExceptionType()); + writer.println("(\"array offset argument \\\"" + offsetArg + "\\\" (\" + " + offsetArg + + " + \") equals or exceeds array length (\" + " + argName + ".length + \")\");"); + } + } + } + } + + protected void emitCall(MethodBinding binding, PrintWriter writer, boolean direct) { + writer.print(getImplMethodName(direct)); + writer.print("("); + emitCallArguments(binding, writer, direct); + writer.print(");"); + } + + + protected void emitReturnVariableSetupAndCall(MethodBinding binding, PrintWriter writer) { + writer.print(" "); + JavaType returnType = binding.getJavaReturnType(); + boolean needsResultAssignment = false; + + if (!returnType.isVoid()) { + if (returnType.isCompoundTypeWrapper() || + returnType.isNIOByteBuffer()) { + writer.println("ByteBuffer _res;"); + needsResultAssignment = true; + } else if (returnType.isArrayOfCompoundTypeWrappers()) { + writer.println("ByteBuffer[] _res;"); + needsResultAssignment = true; + } + } + + if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) { + // Must generate two calls for this gated on whether the NIO + // buffers coming in are all direct or indirect + writer.println("if (_direct) {"); + writer.print (" "); + } + + if (needsResultAssignment) { + writer.print(" _res = "); + } else { + writer.print(" "); + if (!returnType.isVoid()) { + writer.print("return "); + } + } + + if (binding.signatureUsesJavaPrimitiveArrays() && + !binding.signatureCanUseIndirectNIO()) { + // FIXME: what happens with a C function of the form + // void foo(int* arg0, void* arg1); + // ? + + // Only one call being made in this body, going to indirect + // buffer / array entry point + emitCall(binding, writer, false); + writer.println(); + } else { + emitCall(binding, writer, true); + } + + if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) { + // Must generate two calls for this gated on whether the NIO + // buffers coming in are all direct or indirect + writer.println(); + writer.println(" } else {"); + writer.print (" "); + if (needsResultAssignment) { + writer.print(" _res = "); + } else { + writer.print(" "); + if (!returnType.isVoid()) { + writer.print("return "); + } + } + emitCall(binding, writer, false); + writer.println(); + writer.println(" }"); + } else { + writer.println(); + } + if (needsResultAssignment) { + emitCallResultReturn(binding, writer); + } + } + + protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean direct) { + boolean needComma = false; + int numArgsEmitted = 0; + + if (binding.hasContainingType()) { + // Emit this pointer + assert(binding.getContainingType().isCompoundTypeWrapper()); + writer.print("getBuffer()"); + needComma = true; + ++numArgsEmitted; + } + for (int i = 0; i < binding.getNumArguments(); i++) { + JavaType type = binding.getJavaArgumentType(i); + if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) { + // Don't need to expose these at the Java level + continue; + } + + if (type.isVoid()) { + // Make sure this is the only param to the method; if it isn't, + // there's something wrong with our parsing of the headers. + assert(binding.getNumArguments() == 1); + continue; + } + + if (needComma) { + writer.print(", "); + } + + if (type.isCompoundTypeWrapper()) { + writer.print("(("); + } + + if (type.isNIOBuffer() && !direct) { + writer.print("BufferFactory.getArray(" + binding.getArgumentName(i) + ")"); + } else { + writer.print(binding.getArgumentName(i)); + } + + if (type.isCompoundTypeWrapper()) { + writer.print(" == null) ? null : "); + writer.print(binding.getArgumentName(i)); + writer.print(".getBuffer())"); + } + needComma = true; + ++numArgsEmitted; + if (type.isNIOBuffer()) { + if (direct) { + writer.print(", BufferFactory.getDirectBufferByteOffset(" + binding.getArgumentName(i) + ")"); + } else { + writer.print(", BufferFactory.getIndirectBufferByteOffset(" + binding.getArgumentName(i) + ")"); + } + } else if (type.isNIOBufferArray()) { + writer.print(", " + byteOffsetArrayArgName(i)); + } + + // Add Array offset parameter for primitive arrays + if (type.isPrimitiveArray()) { + if(type.isFloatArray()) { + writer.print(", BufferFactory.SIZEOF_FLOAT * "); + } else if(type.isDoubleArray()) { + writer.print(", BufferFactory.SIZEOF_DOUBLE * "); + } else if(type.isByteArray()) { + writer.print(", "); + } else if(type.isLongArray()) { + writer.print(", BufferFactory.SIZEOF_LONG * "); + } else if(type.isShortArray()) { + writer.print(", BufferFactory.SIZEOF_SHORT * "); + } else if(type.isIntArray()) { + writer.print(", BufferFactory.SIZEOF_INT * "); + } else { + throw new RuntimeException("Unsupported type for calculating array offset argument for " + + binding.getArgumentName(i) + + "-- error occurred while processing Java glue code for " + binding.getName()); + } + writer.print(offsetArgName(i)); + } + } + return numArgsEmitted; + } + + protected void emitCallResultReturn(MethodBinding binding, PrintWriter writer) { + JavaType returnType = binding.getJavaReturnType(); + + if (returnType.isCompoundTypeWrapper()) { + String fmt = getReturnedArrayLengthExpression(); + writer.println(" if (_res == null) return null;"); + if (fmt == null) { + writer.print(" return new " + returnType.getName() + "(_res.order(ByteOrder.nativeOrder()))"); + } else { + writer.println(" _res.order(ByteOrder.nativeOrder());"); + String[] argumentNames = new String[binding.getNumArguments()]; + for (int i = 0; i < binding.getNumArguments(); i++) { + argumentNames[i] = binding.getArgumentName(i); + } + String expr = new MessageFormat(fmt).format(argumentNames); + 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 " + binding.getName() + ")"); + } + writer.println(" " + 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 * " + cReturnType.getSize() + ");"); + writer.println(" _res.limit ((1 + _count) * " + cReturnType.getSize() + ");"); + writer.println(" ByteBuffer _tmp = _res.slice();"); + writer.println(" _tmp.order(ByteOrder.nativeOrder());"); + writer.println(" _res.position(0);"); + writer.println(" _res.limit(_res.capacity());"); + writer.println(" _retarray[_count] = new " + getReturnTypeString(true) + "(_tmp);"); + writer.println(" }"); + writer.print (" return _retarray"); + } + writer.println(";"); + } else if (returnType.isNIOBuffer()) { + writer.println(" if (_res == null) return null;"); + writer.println(" return _res.order(ByteOrder.nativeOrder());"); + } else if (returnType.isArrayOfCompoundTypeWrappers()) { + writer.println(" if (_res == null) return null;"); + writer.println(" " + getReturnTypeString(false) + " _retarray = new " + getReturnTypeString(true) + "[_res.length];"); + writer.println(" for (int _count = 0; _count < _res.length; _count++) {"); + writer.println(" _retarray[_count] = new " + getReturnTypeString(true) + "(_res[_count]);"); + writer.println(" }"); + writer.println(" return _retarray;"); + } + } + + public static String javaThisArgumentName() { return "jthis0"; } @@ -278,7 +627,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter * includes the C signature of the native method that is being bound by the * emitter java method. */ - protected static class DefaultCommentEmitter implements CommentEmitter { + protected class DefaultCommentEmitter implements CommentEmitter { public void emit(FunctionEmitter emitter, PrintWriter writer) { emitBeginning(emitter, writer); emitBindingCSignature(((JavaMethodBindingEmitter)emitter).getBinding(), writer); @@ -295,9 +644,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter protected void emitEnding(FunctionEmitter emitter, PrintWriter writer) { // If argument type is a named enum, then emit a comment detailing the // acceptable values of that enum. + // If we're emitting a direct buffer variant only, then declare + // that the NIO buffer arguments must be direct. MethodBinding binding = ((JavaMethodBindingEmitter)emitter).getBinding(); for (int i = 0; i < binding.getNumArguments(); i++) { Type type = binding.getCArgumentType(i); + JavaType javaType = binding.getJavaArgumentType(i); // don't emit param comments for anonymous enums, since we can't // distinguish between the values found within multiple anonymous // enums in the same C translation unit. @@ -314,12 +666,19 @@ public class JavaMethodBindingEmitter extends FunctionEmitter writer.print(enumType.getEnumName(j)); } writer.println("</code>"); + } else if (directNIOOnly && javaType.isNIOBuffer()) { + writer.println(); + writer.print(emitter.getBaseIndentString()); + writer.print(" "); + writer.print("@param "); + writer.print(binding.getArgumentName(i)); + writer.print(" a direct {@link " + javaType.getName() + "}"); } } } } - protected static class InterfaceCommentEmitter + protected class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { protected void emitBeginning(FunctionEmitter emitter, diff --git a/src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java b/src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java deleted file mode 100644 index 3cbc8081d..000000000 --- a/src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package net.java.games.gluegen; - -import java.io.*; -import java.util.*; -import java.text.MessageFormat; - -import net.java.games.gluegen.cgram.types.*; -import net.java.games.jogl.util.BufferUtils; - -/** Emits the Java-side component of the Java<->C JNI binding. */ -public class JavaMethodBindingImplEmitter extends JavaMethodBindingEmitter -{ - private boolean isUnimplemented; - - public JavaMethodBindingImplEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType) - { - this(binding, output, runtimeExceptionType, false, false); - } - - public JavaMethodBindingImplEmitter(MethodBinding binding, - PrintWriter output, - String runtimeExceptionType, - boolean isUnimplemented, - boolean arrayImplExpansion) - { - super(binding, output, runtimeExceptionType); - setCommentEmitter(defaultJavaCommentEmitter); - this.isUnimplemented = isUnimplemented; - this.forArrayImplementingMethodCall = arrayImplExpansion; - } - - public JavaMethodBindingImplEmitter(JavaMethodBindingEmitter arg) { - super(arg); - if (arg instanceof JavaMethodBindingImplEmitter) { - this.isUnimplemented = ((JavaMethodBindingImplEmitter) arg).isUnimplemented; - } - } - - protected void emitBody(PrintWriter writer) - { - MethodBinding binding = getBinding(); - if (needsBody()) { - writer.println(); - writer.println(" {"); - if (isUnimplemented) { - writer.println(" throw new " + getRuntimeExceptionType() + "(\"Unimplemented\");"); - } else { - emitPreCallSetup(binding, writer); - //emitReturnVariableSetup(binding, writer); - emitReturnVariableSetupAndCall(binding, writer); - } - writer.println(" }"); - } else { - writer.println(";"); - } - } - - - protected boolean generateIndirectBufferInterface = false; - - public boolean isGenerateIndirectBufferInterface() { - return generateIndirectBufferInterface; - } - - public void setGenerateIndirectBufferInterface(boolean generateIndirect) { - generateIndirectBufferInterface = generateIndirect; - } - - - protected boolean isUnimplemented() { - return isUnimplemented; - } - - protected boolean needsBody() { - return (isUnimplemented || - getBinding().signatureUsesNIO() || - getBinding().signatureUsesCArrays() || - getBinding().signatureUsesPrimitiveArrays() || - getBinding().hasContainingType()); - } - - protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) { - if(isGenerateIndirectBufferInterface()) { - // case for when indirect Buffer is a possibility - emitArrayLengthAndNIOInDirectBufferChecks(binding, writer); - } else { - emitArrayLengthAndNIOBufferChecks(binding, writer); - } - } - - - protected void emitArrayLengthAndNIOBufferChecks(MethodBinding binding, PrintWriter writer) { - int numBufferOffsetArrayArgs = 0; - // Check lengths of any incoming arrays if necessary - for (int i = 0; i < binding.getNumArguments(); i++) { - Type type = binding.getCArgumentType(i); - JavaType javaType = binding.getJavaArgumentType(i); - if (type.isArray()) { - ArrayType arrayType = type.asArray(); - writer.println(" if (" + binding.getArgumentName(i) + ".length < " + arrayType.getLength() + ")"); - writer.println(" throw new " + getRuntimeExceptionType() + "(\"Length of array \\\"" + binding.getArgumentName(i) + - "\\\" was less than the required " + arrayType.getLength() + "\");"); - } else { - if (javaType.isNIOBuffer()) { - writer.println(" if (!BufferFactory.isDirect(" + binding.getArgumentName(i) + "))"); - writer.println(" throw new " + getRuntimeExceptionType() + "(\"Argument \\\"" + - binding.getArgumentName(i) + "\\\" was not a direct buffer\");"); - } else if (javaType.isNIOBufferArray()) { - numBufferOffsetArrayArgs++; - String argName = binding.getArgumentName(i); - String arrayName = byteOffsetArrayConversionArgName(numBufferOffsetArrayArgs); - writer.println(" int[] " + arrayName + " = new int[" + argName + ".length];"); - // Check direct buffer properties of all buffers within - writer.println(" if (" + argName + " != null) {"); - writer.println(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {"); - writer.println(" if (!BufferFactory.isDirect(" + argName + "[_ctr])) {"); - writer.println(" throw new " + getRuntimeExceptionType() + - "(\"Element \" + _ctr + \" of argument \\\"" + - binding.getArgumentName(i) + "\\\" was not a direct buffer\");"); - writer.println(" }"); - // get the Buffer Array offset values and save them into another array to send down to JNI - writer.print(" " + arrayName + "[_ctr] = BufferFactory.getDirectBufferByteOffset("); - writer.println(argName + "[_ctr]);"); - writer.println(" }"); - writer.println(" }"); - } else if (javaType.isArray() && !javaType.isNIOBufferArray() &&!javaType.isStringArray()) { - String argName = binding.getArgumentName(i); - String offsetArg = argName + "_offset"; - writer.println(" if(" + argName + " != null && " + argName + ".length <= " + offsetArg + ")"); - writer.print(" throw new " + getRuntimeExceptionType()); - writer.println("(\"array offset argument \\\"" + offsetArg + "\\\" equals or exceeds array length\");"); - } - } - } - } - - - protected void emitArrayLengthAndNIOInDirectBufferChecks(MethodBinding binding, PrintWriter writer) { - int numBufferOffsetArrayArgs = 0; - boolean firstBuffer = true; - // Check lengths of any incoming arrays if necessary - for (int i = 0; i < binding.getNumArguments(); i++) { - Type type = binding.getCArgumentType(i); - if (type.isArray()) { - ArrayType arrayType = type.asArray(); - writer.println(" if (" + binding.getArgumentName(i) + ".length < " + - arrayType.getLength() + ")"); - writer.println(" throw new " + getRuntimeExceptionType() + - "(\"Length of array \\\"" + binding.getArgumentName(i) + - "\\\" was less than the required " + arrayType.getLength() + "\");"); - } else { - JavaType javaType = binding.getJavaArgumentType(i); - if (javaType.isNIOBuffer()) { - if(firstBuffer == true) { - firstBuffer = false; - writer.println(" boolean direct = true, firstTime = true, result = true;"); - } - writer.println(" result = BufferFactory.isDirect(" + binding.getArgumentName(i) + ");"); - writer.println(" if(firstTime == true) {"); - writer.println(" direct = result;"); - writer.println(" firstTime = false;"); - writer.println(" } else {"); - writer.println(" if(direct != result)"); - writer.println(" throw new " + getRuntimeExceptionType() + - "(\"Argument \\\"" + binding.getArgumentName(i) + - "\\\" :Not all Buffers in this method were direct or indirect\");"); - writer.println(" }"); - } else if (javaType.isNIOBufferArray()) { - if(firstBuffer == true) { - firstBuffer = false; - writer.println(" boolean direct = true, firstTime = true, result = true;"); - } - numBufferOffsetArrayArgs++; - String argName = binding.getArgumentName(i); - String arrayName = byteOffsetArrayConversionArgName(numBufferOffsetArrayArgs); - writer.println(" int[] " + arrayName + " = new int[" + argName + ".length];"); - writer.println(" if (" + argName + " != null) {"); - // Check direct/indirect buffer properties of all buffers within - writer.println(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {"); - writer.println(" result = BufferFactory.isDirect(" + argName + "[_ctr]);"); - - writer.println(" if(firstTime == true) {"); - writer.println(" direct = result;"); - writer.println(" firstTime = false;"); - writer.println(" } else {"); - writer.println(" if(direct != result)"); - writer.println(" throw new " + getRuntimeExceptionType() + "(\"Element \" + _ctr + \" of argument \\\"" + binding.getArgumentName(i) + "\\\":Mixture of Direct/Indirect Buffers in Method Args\");"); - writer.println(" }"); - // get the Buffer Array offset values and save them into another array to send down to JNI - writer.println(" if(direct)"); - writer.print(" " + arrayName + "[_ctr] = BufferFactory.getDirectBufferByteOffset("); - writer.println(argName + "[_ctr]);"); - writer.println(" else"); - writer.print(" " + arrayName + "[_ctr] = BufferFactory.getIndirectBufferByteOffset("); - writer.println(argName + "[_ctr]);"); - writer.println(" }"); - writer.println(" }"); - } - } - } - } - - - -/* old method before indirect buffer support was added - protected void emitReturnVariableSetup(MethodBinding binding, PrintWriter writer) { - writer.print(" "); - JavaType returnType = binding.getJavaReturnType(); - if (!returnType.isVoid()) { - if (returnType.isCompoundTypeWrapper() || - returnType.isNIOByteBuffer()) { - writer.println("ByteBuffer _res;"); - writer.print(" _res = "); - } else if (returnType.isArrayOfCompoundTypeWrappers()) { - writer.println("ByteBuffer[] _res;"); - writer.print(" _res = "); - } else { - writer.print("return "); - } - } - } -*/ - - - protected void emitReturnVariableSetupAndCall(MethodBinding binding, PrintWriter writer) { - - boolean returnFunction = false; - - writer.print(" "); - JavaType returnType = binding.getJavaReturnType(); - if (!returnType.isVoid()) { - if (returnType.isCompoundTypeWrapper() || - returnType.isNIOByteBuffer()) { - writer.println("ByteBuffer _res;"); - writer.print(" _res = "); - } else if (returnType.isArrayOfCompoundTypeWrappers()) { - writer.println("ByteBuffer[] _res;"); - writer.print(" _res = "); - } else { - if(isGenerateIndirectBufferInterface()) - returnFunction = true; - else - writer.print("return "); - } - } - - - if(isGenerateIndirectBufferInterface()) { - //binding.setIndirectVariant(false); - //writer.println(" boolean direct = true;"); - writer.println(" if(direct) {"); - writer.print(" "); - }; - if(returnFunction) writer.print("return "); - writer.print(getImplMethodName()); - writer.print("("); - emitCallArguments(binding, writer, false); - writer.print(")"); - if(isGenerateIndirectBufferInterface()) { - writer.println(";"); - //binding.setIndirectVariant(true); - writer.println(" } else { "); - if(returnFunction) writer.print("return "); - // get the indirect Buffer implementation name - setIndirectBufferInterface(true); - writer.print(" " + getImplMethodName()); - writer.print("("); - setIndirectBufferInterface(false); - emitCallArguments(binding, writer, true); - writer.println(");"); - writer.println(" }"); - }; - emitCallResultReturn(binding, writer); - } - - - protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean indirectCase) { - boolean needComma = false; - int numArgsEmitted = 0; - int numBufferOffsetArgs = 0, numBufferOffsetArrayArgs = 0; - boolean generateDirectAndIndirect; - - generateDirectAndIndirect = isGenerateIndirectBufferInterface(); - - if (binding.hasContainingType()) { - // Emit this pointer - assert(binding.getContainingType().isCompoundTypeWrapper()); - writer.print("getBuffer()"); - needComma = true; - ++numArgsEmitted; - numBufferOffsetArgs++; - //writer.print(", " + byteOffsetConversionArgName(numBufferOffsetArgs)); - writer.print(", BufferFactory.getDirectBufferByteOffset(getBuffer())"); - } - for (int i = 0; i < binding.getNumArguments(); i++) { - JavaType type = binding.getJavaArgumentType(i); - if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) { - // Don't need to expose these at the Java level - continue; - } - - if (type.isVoid()) { - // Make sure this is the only param to the method; if it isn't, - // there's something wrong with our parsing of the headers. - assert(binding.getNumArguments() == 1); - continue; - } - - if (needComma) { - writer.print(", "); - } - - if (type.isCompoundTypeWrapper()) { - writer.print("(("); - } - - if(type.isNIOBuffer() && !type.isNIOBufferArray() && generateDirectAndIndirect && indirectCase) { - writer.print("BufferFactory.getArray(" + binding.getArgumentName(i) + ")"); - } else { - writer.print(binding.getArgumentName(i)); - } - - if (type.isCompoundTypeWrapper()) { - writer.print(" == null) ? null : "); - writer.print(binding.getArgumentName(i)); - writer.print(".getBuffer())"); - numBufferOffsetArgs++; - //writer.print(", " + byteOffsetConversionArgName(numBufferOffsetArgs)); - writer.print(", BufferFactory.getDirectBufferByteOffset(((" + binding.getArgumentName(i)); - writer.print(" == null) ? null : " + binding.getArgumentName(i) + ".getBuffer()))"); - } - needComma = true; - ++numArgsEmitted; - if(type.isNIOBuffer() || type.isNIOBufferArray()) { - if(!type.isArray()) { - numBufferOffsetArgs++; - if(generateDirectAndIndirect) { - if(!indirectCase) { - writer.print - (", BufferFactory.getDirectBufferByteOffset(" + binding.getArgumentName(i) + ")"); - } else { - writer.print - (", BufferFactory.getIndirectBufferByteOffset(" + binding.getArgumentName(i) + ")"); - } - } else { - writer.print - (", BufferFactory.getDirectBufferByteOffset(" + binding.getArgumentName(i) + ")"); - } - } else { - numBufferOffsetArrayArgs++; - writer.print(", " + byteOffsetArrayConversionArgName(numBufferOffsetArrayArgs)); - } - } - - // Add Array offset parameter for primitive arrays - if(type.isArray() && !type.isNIOBufferArray() && !type.isStringArray()) { - // writer.print(", " + binding.getArgumentName(i) + "_offset"); - if(type.isFloatArray()) { - writer.print(", BufferFactory.SIZEOF_FLOAT * " + binding.getArgumentName(i) + "_offset"); - } else if(type.isDoubleArray()) { - writer.print(", BufferFactory.SIZEOF_DOUBLE * " + binding.getArgumentName(i) + "_offset"); - } else if(type.isByteArray()) { - writer.print(", " + binding.getArgumentName(i) + "_offset"); - } else if(type.isLongArray()) { - writer.print(", BufferFactory.SIZEOF_LONG * " + binding.getArgumentName(i) + "_offset"); - } else if(type.isShortArray()) { - writer.print(", BufferFactory.SIZEOF_SHORT * " + binding.getArgumentName(i) + "_offset"); - } else if(type.isIntArray()) { - writer.print(", BufferFactory.SIZEOF_INT * " + binding.getArgumentName(i) + "_offset"); - } else { - throw new RuntimeException("Unsupported type for calculating array offset argument for " + - binding.getArgumentName(i) + "-- error occurred while processing Java glue code for " + binding.getName()); - } - } - - } - return numArgsEmitted; - } - - protected void emitCallResultReturn(MethodBinding binding, PrintWriter writer) { - JavaType returnType = binding.getJavaReturnType(); - boolean indirect; - - indirect = isGenerateIndirectBufferInterface(); - - if (returnType.isCompoundTypeWrapper()) { - if(!indirect) writer.println(";"); - String fmt = getReturnedArrayLengthExpression(); - writer.println(" if (_res == null) return null;"); - if (fmt == null) { - writer.print(" return new " + returnType.getName() + "(_res.order(ByteOrder.nativeOrder()))"); - } else { - writer.println(" _res.order(ByteOrder.nativeOrder());"); - String[] argumentNames = new String[binding.getNumArguments()]; - for (int i = 0; i < binding.getNumArguments(); i++) { - argumentNames[i] = binding.getArgumentName(i); - } - String expr = new MessageFormat(fmt).format(argumentNames); - 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 " + binding.getName() + ")"); - } - writer.println(" " + 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 * " + cReturnType.getSize() + ");"); - writer.println(" _res.limit ((1 + _count) * " + cReturnType.getSize() + ");"); - writer.println(" ByteBuffer _tmp = _res.slice();"); - writer.println(" _tmp.order(ByteOrder.nativeOrder());"); - writer.println(" _res.position(0);"); - writer.println(" _res.limit(_res.capacity());"); - writer.println(" _retarray[_count] = new " + getReturnTypeString(true) + "(_tmp);"); - writer.println(" }"); - writer.print (" return _retarray"); - } - writer.println(";"); - } else if (returnType.isNIOBuffer()) { - if(!indirect) writer.println(";"); - writer.println(" if (_res == null) return null;"); - writer.print(" return _res.order(ByteOrder.nativeOrder())"); - writer.println(";"); - } else if (returnType.isArrayOfCompoundTypeWrappers()) { - if(!indirect) writer.println(";"); - writer.println(" if (_res == null) return null;"); - writer.println(" " + getReturnTypeString(false) + " _retarray = new " + getReturnTypeString(true) + "[_res.length];"); - writer.println(" for (int _count = 0; _count < _res.length; _count++) {"); - writer.println(" _retarray[_count] = new " + getReturnTypeString(true) + "(_res[_count]);"); - writer.println(" }"); - writer.print (" return _retarray"); - writer.println(";"); - } else { - if(!indirect) writer.println(";"); - } - } -} - diff --git a/src/net/java/games/gluegen/JavaType.java b/src/net/java/games/gluegen/JavaType.java index 8917bede1..18c9c301d 100644 --- a/src/net/java/games/gluegen/JavaType.java +++ b/src/net/java/games/gluegen/JavaType.java @@ -222,8 +222,7 @@ public class JavaType { } /** - * Returns the name corresponding to this type. Returns null when this - * object does not represent a C-language "struct" type. + * Returns the Java type name corresponding to this type. */ public String getName() { if (clazz != null) { @@ -242,6 +241,16 @@ public class JavaType { or NULL if it can't be represented (i.e., it's a boxing class that we need to call getBuffer() on.) */ public String jniTypeName() { + if (isCompoundTypeWrapper()) { + // These are sent down as Buffers (e.g., jobject) + return "jobject"; + } + + if (isArrayOfCompoundTypeWrappers()) { + // These are returned as arrays of ByteBuffers (e.g., jobjectArray) + return "jobjectArray /* of ByteBuffer */"; + } + if (clazz == null) { return null; } @@ -250,48 +259,41 @@ public class JavaType { return "void"; } - if (clazz.isPrimitive()) { + if (isPrimitive()) { return "j" + clazz.getName(); } - if (clazz.isArray()) { - Class elementType = clazz.getComponentType(); - if (elementType.isPrimitive()) - { - // Type is array-of-primitive - return "j" + elementType.getName() + "Array"; - } - else if (elementType == java.lang.String.class) - { - // Type is array-of-string + if (isPrimitiveArray() || isNIOBuffer()) { + // We now pass primitive arrays and buffers uniformly down to native code as java.lang.Object. + return "jobject"; + } + + if (isArray()) { + if (isStringArray()) { return "jobjectArray /*elements are String*/"; - //return "jobjectArray"; } - else if (java.nio.Buffer.class.isAssignableFrom(elementType)) - { + + Class elementType = clazz.getComponentType(); + + if (isNIOBufferArray()) { return "jobjectArray /*elements are " + elementType.getName() + "*/"; } - else if (elementType.isArray()) - { + + if (elementType.isArray()) { // Type is array-of-arrays-of-something - if (elementType.getComponentType().isPrimitive()) - { + if (elementType.getComponentType().isPrimitive()) { // Type is an array-of-arrays-of-primitive return "jobjectArray /* elements are " + elementType.getComponentType() + "[]*/"; //return "jobjectArray"; - } - else - { + } else { throw new RuntimeException("Multi-dimensional arrays of types that are not primitives or Strings are not supported."); } } - else - { - // Some unusual type that we don't handle - throw new RuntimeException("Unexpected and unsupported type: \"" + this + "\""); - } - } // end array type case + + // Some unusual type that we don't handle + throw new RuntimeException("Unexpected and unsupported array type: \"" + this + "\""); + } if (isString()) { return "jstring"; @@ -452,6 +454,11 @@ public class JavaType { // Internals only below this point // + // For debugging + public void dump() { + System.err.println("[clazz = " + clazz + " , name = " + name + " , elementType = " + elementType + " , primitivePointerType = " + primitivePointerType + "]"); + } + /** * Constructs a representation for a type corresponding to the given Class * argument. diff --git a/src/net/java/games/gluegen/MethodBinding.java b/src/net/java/games/gluegen/MethodBinding.java index 11513ed36..7576ec3f8 100644 --- a/src/net/java/games/gluegen/MethodBinding.java +++ b/src/net/java/games/gluegen/MethodBinding.java @@ -53,9 +53,14 @@ public class MethodBinding { private JavaType javaReturnType; private List javaArgumentTypes; private boolean computedSignatureProperties; + private boolean argumentsUseNIO; private boolean signatureUsesNIO; + private boolean signatureCanUseIndirectNIO; + private boolean signatureUsesCompoundTypeWrappers; + private boolean signatureUsesCVoidPointers; + private boolean signatureUsesCPrimitivePointers; private boolean signatureUsesCArrays; - private boolean signatureUsesPrimitiveArrays; + private boolean signatureUsesJavaPrimitiveArrays; private JavaType containingType; private Type containingCType; private int thisPointerIndex = -1; @@ -68,15 +73,20 @@ public class MethodBinding { public MethodBinding(MethodBinding bindingToCopy) { this.sym = bindingToCopy.sym; - this.containingType = bindingToCopy.containingType; - this.containingCType = bindingToCopy.containingCType; - this.javaReturnType = bindingToCopy.javaReturnType; - this.javaArgumentTypes = (List)((ArrayList)bindingToCopy.javaArgumentTypes).clone(); - this.computedSignatureProperties = bindingToCopy.computedSignatureProperties; - this.signatureUsesNIO = bindingToCopy.signatureUsesNIO; - this.signatureUsesCArrays = bindingToCopy.signatureUsesCArrays; - this.signatureUsesPrimitiveArrays = bindingToCopy.signatureUsesPrimitiveArrays; - this.thisPointerIndex = bindingToCopy.thisPointerIndex; + this.containingType = bindingToCopy.containingType; + this.containingCType = bindingToCopy.containingCType; + this.javaReturnType = bindingToCopy.javaReturnType; + this.javaArgumentTypes = (List)((ArrayList)bindingToCopy.javaArgumentTypes).clone(); + this.computedSignatureProperties = bindingToCopy.computedSignatureProperties; + this.argumentsUseNIO = bindingToCopy.argumentsUseNIO; + this.signatureUsesNIO = bindingToCopy.signatureUsesNIO; + this.signatureCanUseIndirectNIO = bindingToCopy.signatureCanUseIndirectNIO; + this.signatureUsesCompoundTypeWrappers = bindingToCopy.signatureUsesCompoundTypeWrappers; + this.signatureUsesCVoidPointers = bindingToCopy.signatureUsesCVoidPointers; + this.signatureUsesCPrimitivePointers = bindingToCopy.signatureUsesCPrimitivePointers; + this.signatureUsesCArrays = bindingToCopy.signatureUsesCArrays; + this.signatureUsesJavaPrimitiveArrays = bindingToCopy.signatureUsesJavaPrimitiveArrays; + this.thisPointerIndex = bindingToCopy.thisPointerIndex; } /** Constructor for calling a C function. */ @@ -146,11 +156,11 @@ public class MethodBinding { return sym.getName(); } - /** Replaces the C primitive pointer argument at slot <i>argumentNumber</i> - (0..getNumArguments() - 1) with the specified type. If - argumentNumber is less than 0 then replaces the return type. */ - public MethodBinding createCPrimitivePointerVariant(int argumentNumber, - JavaType newArgType) { + /** Creates a new MethodBinding replacing the specified Java + argument type with a new argument type. If argumentNumber is + less than 0 then replaces the return type. */ + public MethodBinding replaceJavaArgumentType(int argumentNumber, + JavaType newArgType) { MethodBinding binding = new MethodBinding(sym); if (argumentNumber < 0) { binding.setJavaReturnType(newArgType); @@ -168,6 +178,16 @@ public class MethodBinding { } /** + * Returns true if any of the outgoing arguments in the method's + * signature require conversion or checking due to the use of New + * I/O. + */ + public boolean argumentsUseNIO() { + computeSignatureProperties(); + return argumentsUseNIO; + } + + /** * Returns true if the return type or any of the outgoing arguments * in the method's signature require conversion or checking due to * the use of New I/O. @@ -178,9 +198,55 @@ public class MethodBinding { } /** - * Returns true if any of the outgoing arguments in the method's - * signature represent fixed-length C arrays which require length - * checking during the call. + * Returns true if it is possible for any of the outgoing arguments + * to be indirect NIO buffers. + */ + public boolean signatureCanUseIndirectNIO() { + computeSignatureProperties(); + return signatureCanUseIndirectNIO; + } + + /** + * Returns true if the return type or any of the outgoing arguments + * in the method's signature use "compound type wrappers", or + * NIO-based wrappers for C data structures. + */ + public boolean signatureUsesCompoundTypeWrappers() { + computeSignatureProperties(); + return signatureUsesCompoundTypeWrappers; + } + + /** + * Returns true if the function needs NIO-related + * wrapping/unwrapping or conversion of various arguments. Currently + * this returns the logical OR of signatureUsesNIO() and + * signatureUsesCompoundTypeWrappers(). + */ + public boolean needsNIOWrappingOrUnwrapping() { + return (signatureUsesNIO() || signatureUsesCompoundTypeWrappers()); + } + + /** + * Returns true if the return type or any of the outgoing arguments + * in the method's signature represent C void* pointers. + */ + public boolean signatureUsesCVoidPointers() { + computeSignatureProperties(); + return signatureUsesCVoidPointers; + } + + /** + * Returns true if the return type or any of the outgoing arguments + * in the method's signature represent C primitive pointers. + */ + public boolean signatureUsesCPrimitivePointers() { + computeSignatureProperties(); + return signatureUsesCPrimitivePointers; + } + + /** + * Returns true if the return type or any of the outgoing arguments + * in the method's signature represent C arrays. */ public boolean signatureUsesCArrays() { computeSignatureProperties(); @@ -188,13 +254,12 @@ public class MethodBinding { } /** - * Returns true if any of the outgoing arguments in the method's - * signature represent primitive arrays which require a - * GetPrimitiveArrayCritical or similar operation during the call. + * Returns true if the return type or any of the outgoing arguments + * in the method's signature represent Java primitive arrays. */ - public boolean signatureUsesPrimitiveArrays() { + public boolean signatureUsesJavaPrimitiveArrays() { computeSignatureProperties(); - return signatureUsesPrimitiveArrays; + return signatureUsesJavaPrimitiveArrays; } /** @@ -205,68 +270,91 @@ public class MethodBinding { if (computedSignatureProperties) return; + argumentsUseNIO = false; signatureUsesNIO = false; + signatureCanUseIndirectNIO = false; + signatureUsesCompoundTypeWrappers = false; + signatureUsesCVoidPointers = false; + signatureUsesCPrimitivePointers = false; signatureUsesCArrays = false; - signatureUsesPrimitiveArrays = false; + signatureUsesJavaPrimitiveArrays = false; - if (javaReturnType.isCompoundTypeWrapper() || - javaReturnType.isNIOByteBuffer() || + if (javaReturnType.isCompoundTypeWrapper()) { + // Needs wrapping and/or setting of byte order (neither of which + // can be done easily from native code) + signatureUsesCompoundTypeWrappers = true; + } + + if (javaReturnType.isNIOByteBuffer() || javaReturnType.isArrayOfCompoundTypeWrappers()) { - // Needs wrapping and/or setting of byte order (neither of - // which can be done easily from native code) + // Needs setting of byte order which can't be done easily from + // native code signatureUsesNIO = true; } + Type cRetType = sym.getReturnType(); + if (cRetType.isArray()) { + // Needs checking of array lengths + signatureUsesCArrays = true; + if (cRetType.asArray().getElementType().isPrimitive()) { + signatureUsesCPrimitivePointers = true; + } + } + + if (cRetType.isPointer()) { + if (cRetType.asPointer().getTargetType().isPrimitive()) { + signatureUsesCPrimitivePointers = true; + } else if (cRetType.asPointer().getTargetType().isVoid()) { + signatureUsesCVoidPointers = true; + } + } + for (int i = 0; i < getNumArguments(); i++) { JavaType javaArgType = getJavaArgumentType(i); Type cArgType = getCArgumentType(i); - if (javaArgType.isCompoundTypeWrapper() || - javaArgType.isNIOBuffer() || + if (javaArgType.isCompoundTypeWrapper()) { + // Needs unwrapping of accessors + signatureUsesCompoundTypeWrappers = true; + } + + if (javaArgType.isNIOBuffer() || javaArgType.isNIOBufferArray()) { - // Needs unwrapping of accessors or checking of direct - // buffer property + // Needs checking of direct buffer property signatureUsesNIO = true; + argumentsUseNIO = true; + + if (javaArgType.isNIOBuffer()) { + // Potential conversion to indirect buffer + signatureCanUseIndirectNIO = true; + } } if (cArgType.isArray()) { // Needs checking of array lengths signatureUsesCArrays = true; + if (cArgType.asArray().getElementType().isPrimitive()) { + signatureUsesCPrimitivePointers = true; + } } - if (javaArgType.isPrimitiveArray() && !javaArgType.isStringArray() ) { + if (cArgType.isPointer()) { + if (cArgType.asPointer().getTargetType().isPrimitive()) { + signatureUsesCPrimitivePointers = true; + } else if (cArgType.asPointer().getTargetType().isVoid()) { + signatureUsesCVoidPointers = true; + } + } + + if (javaArgType.isPrimitiveArray()) { // Needs getPrimitiveArrayCritical or similar construct // depending on native code calling convention - signatureUsesPrimitiveArrays = true; + signatureUsesJavaPrimitiveArrays = true; } } computedSignatureProperties = true; } - - public MethodBinding createNIOBufferVariant() { - if (!signatureUsesNIO()) { - return this; - } - MethodBinding binding = new MethodBinding(sym, containingType, containingCType); - binding.thisPointerIndex = thisPointerIndex; - if (javaReturnType.isCompoundTypeWrapper()) { - binding.setJavaReturnType(JavaType.forNIOByteBufferClass()); - } else if (javaReturnType.isArrayOfCompoundTypeWrappers()) { - binding.setJavaReturnType(JavaType.forNIOByteBufferArrayClass()); - } else { - binding.setJavaReturnType(javaReturnType); - } - for (int i = 0; i < getNumArguments(); i++) { - JavaType type = getJavaArgumentType(i); - if (type.isCompoundTypeWrapper()) { - type = JavaType.forNIOBufferClass(); - } - binding.addJavaArgumentType(type); - } - return binding; - } - /** Indicates whether this MethodBinding is for a function pointer contained in a struct. */ public boolean hasContainingType() { diff --git a/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java b/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java index e233d7155..ceee9f1be 100644 --- a/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java +++ b/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java @@ -44,37 +44,29 @@ import java.util.*; import net.java.games.gluegen.*; import net.java.games.gluegen.cgram.types.*; -public class CGLPAWrapperEmitter extends CMethodBindingEmitter -{ +public class CGLPAWrapperEmitter extends CMethodBindingEmitter { private static final CommentEmitter defaultCommentEmitter = new CGLPAWrapperCommentEmitter(); - private CMethodBindingEmitter emitterBeingWrapped; private String glFuncPtrTypedefValue; private static String procAddressJavaTypeName = JavaType.createForClass(Long.TYPE).jniTypeName(); - protected boolean arrayImplRoutine = false; - - public CGLPAWrapperEmitter(CMethodBindingEmitter methodToWrap) - { + public CGLPAWrapperEmitter(CMethodBindingEmitter methodToWrap) { super( new MethodBinding(methodToWrap.getBinding()) { public String getName() { return GLEmitter.WRAP_PREFIX + super.getName(); } }, - methodToWrap.getIsOverloadedBinding(), + methodToWrap.getDefaultOutput(), methodToWrap.getJavaPackageName(), methodToWrap.getJavaClassName(), + methodToWrap.getIsOverloadedBinding(), methodToWrap.getIsJavaMethodStatic(), - methodToWrap.getDefaultOutput() - ); - -// if(binding.signatureUsesPrimitiveArrays()) -// arrayImplRoutine = true; - - indirectBufferInterface = methodToWrap.isIndirectBufferInterface(); + true, + methodToWrap.forIndirectBufferAndArrayImplementation() + ); if (methodToWrap.getReturnValueCapacityExpression() != null) { setReturnValueCapacityExpression(methodToWrap.getReturnValueCapacityExpression()); @@ -88,8 +80,7 @@ public class CGLPAWrapperEmitter extends CMethodBindingEmitter setCommentEmitter(defaultCommentEmitter); } - protected int emitArguments(PrintWriter writer) - { + protected int emitArguments(PrintWriter writer) { int numEmitted = super.emitArguments(writer); if (numEmitted > 0) { @@ -103,8 +94,7 @@ public class CGLPAWrapperEmitter extends CMethodBindingEmitter return numEmitted; } - protected void emitBodyVariableDeclarations(PrintWriter writer) - { + protected void emitBodyVariableDeclarations(PrintWriter writer) { // create variable for the function pointer with the right type, and set // it to the value of the passed-in glProcAddress FunctionSymbol cSym = getBinding().getCSymbol(); @@ -121,8 +111,7 @@ public class CGLPAWrapperEmitter extends CMethodBindingEmitter } protected void emitBodyVariablePreCallSetup(PrintWriter writer, - boolean emittingPrimitiveArrayCritical) - { + boolean emittingPrimitiveArrayCritical) { super.emitBodyVariablePreCallSetup(writer, emittingPrimitiveArrayCritical); if (!emittingPrimitiveArrayCritical) { @@ -143,23 +132,17 @@ public class CGLPAWrapperEmitter extends CMethodBindingEmitter } } - // FIXME: refactor this and the superclass version so we don't have to copy - // the whole function - protected void emitBodyCallCFunction(PrintWriter writer) - { + protected void emitBodyCallCFunction(PrintWriter writer) { // Make the call to the actual C function writer.print(" "); // WARNING: this code assumes that the return type has already been // typedef-resolved. - Type cReturnType = getBinding().getCReturnType(); + Type cReturnType = binding.getCReturnType(); if (!cReturnType.isVoid()) { writer.print("_res = "); } - - // !!!!!!!!! BEGIN CHANGES FROM SUPERCLASS METHOD - MethodBinding binding = getBinding(); if (binding.hasContainingType()) { // Cannot call GL func through function pointer @@ -171,106 +154,16 @@ public class CGLPAWrapperEmitter extends CMethodBindingEmitter writer.print("(* ptr_"); writer.print(binding.getCSymbol().getName()); writer.print(") "); - - // !!!!!!!!! END CHANGES FROM SUPERCLASS METHOD - - writer.print("("); - for (int i = 0; i < binding.getNumArguments(); i++) { - if (i != 0) { - writer.print(", "); - } - JavaType javaType = binding.getJavaArgumentType(i); - // Handle case where only param is void. - if (javaType.isVoid()) { - // Make sure this is the only param to the method; if it isn't, - // there's something wrong with our parsing of the headers. - assert(binding.getNumArguments() == 1); - continue; - } - - if (javaType.isJNIEnv()) { - writer.print("env"); - } else if (binding.isArgumentThisPointer(i)) { - writer.print(CMethodBindingEmitter.cThisArgumentName()); - } else { - writer.print("("); - writer.print(binding.getCSymbol().getArgumentType(i).getName()); - writer.print(") "); - if (binding.getCArgumentType(i).isPointer() && binding.getJavaArgumentType(i).isPrimitive()) { - writer.print("(intptr_t) "); - } - if (javaType.isArray() || javaType.isNIOBuffer()) { - - Type cArgType = binding.getCSymbol().getArgumentType(i); - boolean containsVoid = false; - // Add special code for accounting for array offsets - // - // For mapping from byte primitive array type to type* case produces code: - // (GLtype*)((char*)_ptr0 + varName_offset) - // where varName_offset is the number of bytes offset as calculated in Java code - - if(javaType.isArray() && !javaType.isNIOBufferArray() && !javaType.isStringArray()) { - writer.print("( (char*)"); - } - /* End of special code section for accounting for array offsets */ - - writer.print(pointerConversionArgumentName(i)); - if (javaArgTypeNeedsDataCopy(javaType)) { - writer.print("_copy"); - } - - /* Add special code for accounting for array offsets */ - if(javaType.isArray() && !javaType.isNIOBufferArray() && !javaType.isStringArray()) { - writer.print(" + " + binding.getArgumentName(i) + "_offset)"); - } - /* End of special code section for accounting for array offsets */ - - } else { - if (javaType.isString()) { writer.print("_UTF8"); } - writer.print(binding.getArgumentName(i)); - } - } - } + emitBodyPassCArguments(writer); writer.println(");"); } protected String jniMangle(MethodBinding binding) { - StringBuffer buf = new StringBuffer(); - buf.append(jniMangle(binding.getName())); - - if( isIndirectBufferInterface() ) - buf.append("2"); - else if(binding.signatureUsesPrimitiveArrays()) - buf.append("1"); - - buf.append("__"); - for (int i = 0; i < binding.getNumArguments(); i++) { - JavaType type = binding.getJavaArgumentType(i); - Class c = type.getJavaClass(); - if (c != null) { - jniMangle(c, buf); - // If Buffer offset arguments were added, we need to mangle the JNI for the - // extra arguments - if(type.isNIOBuffer()) { - jniMangle(Integer.TYPE, buf); - } else if (type.isNIOBufferArray()) { - int[] intArrayType = new int[0]; - c = intArrayType.getClass(); - jniMangle(c , buf); - } - if(type.isArray() && !type.isNIOBufferArray() && !type.isStringArray()) { - jniMangle(Integer.TYPE, buf); - } - } else { - // FIXME: add support for char* -> String conversion - throw new RuntimeException("Unknown kind of JavaType: name="+type.getName()); - } - } - - jniMangle(Long.TYPE, buf); // to account for the additional _addr_ parameter + StringBuffer buf = new StringBuffer(super.jniMangle(binding)); + jniMangle(Long.TYPE, buf, false); // to account for the additional _addr_ parameter return buf.toString(); - } + } /** This class emits the comment for the wrapper method */ private static class CGLPAWrapperCommentEmitter extends CMethodBindingEmitter.DefaultCommentEmitter { diff --git a/src/net/java/games/gluegen/opengl/GLEmitter.java b/src/net/java/games/gluegen/opengl/GLEmitter.java index b3581bd73..e6c44bd4d 100644 --- a/src/net/java/games/gluegen/opengl/GLEmitter.java +++ b/src/net/java/games/gluegen/opengl/GLEmitter.java @@ -145,16 +145,11 @@ public class GLEmitter extends JavaEmitter FunctionEmitter emitter = (FunctionEmitter) iter.next(); if (emitter instanceof JavaMethodBindingEmitter) { - JavaMethodBindingEmitter newEmitter = - generateModifiedEmitter((JavaMethodBindingEmitter)emitter); - if (newEmitter != null) { - modifiedEmitters.add(newEmitter); - } + generateModifiedEmitters((JavaMethodBindingEmitter) emitter, modifiedEmitters); } else if (emitter instanceof CMethodBindingEmitter) { - modifiedEmitters.add( - generateModifiedEmitter((CMethodBindingEmitter)emitter)); + generateModifiedEmitters((CMethodBindingEmitter) emitter, modifiedEmitters); } else { @@ -187,9 +182,40 @@ public class GLEmitter extends JavaEmitter // Internals only below this point // - protected JavaMethodBindingEmitter generateModifiedEmitter(JavaMethodBindingEmitter baseJavaEmitter) - { - if (!(baseJavaEmitter instanceof JavaMethodBindingImplEmitter)) { + protected void generateModifiedEmitters(JavaMethodBindingEmitter baseJavaEmitter, List emitters) { + if (getGLConfig().manuallyImplement(baseJavaEmitter.getName())) { + // User will provide Java-side implementation of this routine; + // pass through any emitters which will produce signatures for + // it unmodified + emitters.add(baseJavaEmitter); + return; + } + + JavaGLPAWrapperEmitter emitter = + new JavaGLPAWrapperEmitter(baseJavaEmitter, + getGLConfig().getProcAddressTableExpr(), + baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PRIVATE)); + emitters.add(emitter); + + // If this emitter doesn't have a body (i.e., is a public native + // call), we need to force it to emit a body, and produce another + // one to act as the entry point + if (baseJavaEmitter.signatureOnly() && + baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PUBLIC) && + baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.NATIVE)) { + emitter.setEmitBody(true); + emitter.removeModifier(JavaMethodBindingEmitter.NATIVE); + emitter = new JavaGLPAWrapperEmitter(baseJavaEmitter, + getGLConfig().getProcAddressTableExpr(), + true); + emitter.setForImplementingMethodCall(true); + emitters.add(emitter); + } + + /***** + FIXME: OLD CODE (DELETE) + + if (baseJavaEmitter.signatureOnly()) { // We only want to wrap the native entry point in the implementation // class, not the public interface in the interface class. // @@ -201,14 +227,11 @@ public class GLEmitter extends JavaEmitter return null; return baseJavaEmitter; } - if (getGLConfig().manuallyImplement(baseJavaEmitter.getName())) { - // User will provide Java-side implementation of this routine - return null; - } return new JavaGLPAWrapperEmitter(baseJavaEmitter, getGLConfig().getProcAddressTableExpr()); + ****/ } - protected CMethodBindingEmitter generateModifiedEmitter(CMethodBindingEmitter baseCEmitter) + protected void generateModifiedEmitters(CMethodBindingEmitter baseCEmitter, List emitters) { // The C-side JNI binding for this particular function will have an // extra final argument, which is the address (the OpenGL procedure @@ -218,7 +241,7 @@ public class GLEmitter extends JavaEmitter if (exp != null) { res.setReturnValueCapacityExpression(exp); } - return res; + emitters.add(res); } protected boolean needsProcAddressWrapper(FunctionSymbol sym) diff --git a/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java b/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java index d0eafa8de..51f5579f4 100644 --- a/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java +++ b/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java @@ -44,18 +44,20 @@ import java.util.*; import net.java.games.gluegen.*; import net.java.games.gluegen.cgram.types.*; -public class JavaGLPAWrapperEmitter extends JavaMethodBindingImplEmitter -{ - private static final CommentEmitter commentEmitterForWrappedMethod = +public class JavaGLPAWrapperEmitter extends JavaMethodBindingEmitter { + private final CommentEmitter commentEmitterForWrappedMethod = new WrappedMethodCommentEmitter(); - private JavaMethodBindingEmitter emitterBeingWrapped; + private boolean changeNameAndArguments; private String getProcAddressTableExpr; - public JavaGLPAWrapperEmitter(JavaMethodBindingEmitter methodToWrap, String getProcAddressTableExpr) - { - super(methodToWrap.getBinding(), methodToWrap.getDefaultOutput(), methodToWrap.getRuntimeExceptionType()); + public JavaGLPAWrapperEmitter(JavaMethodBindingEmitter methodToWrap, + String getProcAddressTableExpr, + boolean changeNameAndArguments) { + super(methodToWrap); + this.changeNameAndArguments = changeNameAndArguments; this.getProcAddressTableExpr = getProcAddressTableExpr; + setCommentEmitter(new WrappedMethodCommentEmitter()); if (methodToWrap.getBinding().hasContainingType()) { @@ -63,111 +65,39 @@ public class JavaGLPAWrapperEmitter extends JavaMethodBindingImplEmitter "Cannot create OpenGL proc. address wrapper; method has containing type: \"" + methodToWrap.getBinding() + "\""); } + } - // make a new emitter that will emit the original method's binding, but - // with WRAP_PREFIX before its name. If a body is needed (for array - // length checking, unwrapping of wrapper objects to java.nio.Buffers, - // etc.) then it will be generated; therefore the emitter being wrapped - // should be an "NIO buffer variant" (i.e., after all unpacking has - // occurred). - emitterBeingWrapped = - new JavaMethodBindingEmitter(methodToWrap.getBinding().createNIOBufferVariant(), - methodToWrap.getDefaultOutput(), - methodToWrap.getRuntimeExceptionType()) - { - - protected void emitName(PrintWriter writer) - { - writer.print(GLEmitter.WRAP_PREFIX); - super.emitName(writer); - - if(getBinding().signatureUsesPrimitiveArrays()) - writer.print("1"); - - } - protected int emitArguments(PrintWriter writer) - { - // following is set to true so that Buffer offset parameters are generated - // in parent class method, when appropriate - prefixedMethod = true; - int numEmitted = super.emitArguments(writer); - if (numEmitted > 0) - { - writer.print(", "); - } - - writer.print("long glProcAddress"); - ++numEmitted; - - return numEmitted; - } - }; - - // copy the modifiers from the original emitter - emitterBeingWrapped.addModifiers(methodToWrap.getModifiers()); - - // Change the access of the method we're wrapping to PRIVATE - EmissionModifier origAccess = null; // null is equivalent if package access - if (emitterBeingWrapped.hasModifier(PUBLIC)) - { - origAccess = PUBLIC; - } - else if (emitterBeingWrapped.hasModifier(PROTECTED)) - { - origAccess = PROTECTED; - } - else if (emitterBeingWrapped.hasModifier(PRIVATE)) - { - origAccess = PRIVATE; - } - - if (origAccess != null) - { - emitterBeingWrapped.removeModifier(origAccess); - } - emitterBeingWrapped.addModifier(PRIVATE); - emitterBeingWrapped.addModifier(NATIVE); - - // Now make our binding use the original access of the wrapped method - this.addModifier(origAccess); - if (emitterBeingWrapped.hasModifier(STATIC)) { - this.addModifier(STATIC); + public String getName() { + String res = super.getName(); + if (changeNameAndArguments) { + return GLEmitter.WRAP_PREFIX + res; } + return res; } - protected boolean needsBody() { - return true; - } + protected int emitArguments(PrintWriter writer) { + int numEmitted = super.emitArguments(writer); + if (changeNameAndArguments) { + if (numEmitted > 0) { + writer.print(", "); + } - protected String getImplMethodName() { - if(getBinding().signatureUsesPrimitiveArrays()) - return GLEmitter.WRAP_PREFIX + getBinding().getName() + "1"; - else - return GLEmitter.WRAP_PREFIX + getBinding().getName(); + writer.print("long glProcAddress"); + ++numEmitted; + } + + return numEmitted; } - public void emit(PrintWriter writer) - { - // Emit a wrapper that will call the method we want to wrap - //writer.println(" // Emitter being wrapped = " + emitterBeingWrapped.getClass().getName()); - super.emit(writer); - writer.println(); - - // emit the wrapped method - CommentEmitter origComment = emitterBeingWrapped.getCommentEmitter(); - emitterBeingWrapped.setCommentEmitter(commentEmitterForWrappedMethod); - emitterBeingWrapped.emit(writer); - emitterBeingWrapped.setCommentEmitter(origComment); - writer.println(); + protected String getImplMethodName(boolean direct) { + return GLEmitter.WRAP_PREFIX + super.getImplMethodName(direct); } protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) { super.emitPreCallSetup(binding, writer); - MethodBinding wrappedBinding = emitterBeingWrapped.getBinding(); String procAddressVariable = - GLEmitter.PROCADDRESS_VAR_PREFIX + wrappedBinding.getName(); - + GLEmitter.PROCADDRESS_VAR_PREFIX + binding.getName(); writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";"); writer.println(" if (__addr_ == 0) {"); writer.println(" throw new GLException(\"Method \\\"" + binding.getName() + "\\\" not available\");"); @@ -184,7 +114,7 @@ public class JavaGLPAWrapperEmitter extends JavaMethodBindingImplEmitter } /** This class emits the comment for the wrapper method */ - private static class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { + private class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) { writer.print("Encapsulates function pointer for OpenGL function <br>: "); } diff --git a/src/net/java/games/gluegen/runtime/BufferFactory.java b/src/net/java/games/gluegen/runtime/BufferFactory.java index cae81b1b3..81334b77a 100644 --- a/src/net/java/games/gluegen/runtime/BufferFactory.java +++ b/src/net/java/games/gluegen/runtime/BufferFactory.java @@ -87,25 +87,25 @@ public class BufferFactory { the total offset for Direct Buffers. */ public static int getDirectBufferByteOffset(Buffer buf) { - if(buf == null) { - return 0; - } - if(buf instanceof ByteBuffer) { - return (buf.position()); - } else if (buf instanceof FloatBuffer) { - return (buf.position() * BufferUtils.SIZEOF_FLOAT); - } else if (buf instanceof IntBuffer) { - return (buf.position() * BufferUtils.SIZEOF_INT); - } else if (buf instanceof ShortBuffer) { - return (buf.position() * BufferUtils.SIZEOF_SHORT); - } else if (buf instanceof DoubleBuffer) { - return (buf.position() * BufferUtils.SIZEOF_DOUBLE); - } else if (buf instanceof LongBuffer) { - return (buf.position() * BufferUtils.SIZEOF_LONG); - } - - throw new RuntimeException("Disallowed array backing store type in buffer " - + buf.getClass().getName()); + if(buf == null) { + return 0; + } + if(buf instanceof ByteBuffer) { + return (buf.position()); + } else if (buf instanceof FloatBuffer) { + return (buf.position() * BufferUtils.SIZEOF_FLOAT); + } else if (buf instanceof IntBuffer) { + return (buf.position() * BufferUtils.SIZEOF_INT); + } else if (buf instanceof ShortBuffer) { + return (buf.position() * BufferUtils.SIZEOF_SHORT); + } else if (buf instanceof DoubleBuffer) { + return (buf.position() * BufferUtils.SIZEOF_DOUBLE); + } else if (buf instanceof LongBuffer) { + return (buf.position() * BufferUtils.SIZEOF_LONG); + } + + throw new RuntimeException("Disallowed array backing store type in buffer " + + buf.getClass().getName()); } @@ -113,25 +113,25 @@ public class BufferFactory { a Buffer object. */ public static Object getArray(Buffer buf) { - if (buf == null) { - return null; - } - if(buf instanceof ByteBuffer) { - return ((ByteBuffer) buf).array(); - } else if (buf instanceof FloatBuffer) { - return ((FloatBuffer) buf).array(); - } else if (buf instanceof IntBuffer) { - return ((IntBuffer) buf).array(); - } else if (buf instanceof ShortBuffer) { - return ((ShortBuffer) buf).array(); - } else if (buf instanceof DoubleBuffer) { - return ((DoubleBuffer) buf).array(); - } else if (buf instanceof LongBuffer) { - return ((LongBuffer) buf).array(); - } - - throw new RuntimeException("Disallowed array backing store type in buffer " - + buf.getClass().getName()); + if (buf == null) { + return null; + } + if(buf instanceof ByteBuffer) { + return ((ByteBuffer) buf).array(); + } else if (buf instanceof FloatBuffer) { + return ((FloatBuffer) buf).array(); + } else if (buf instanceof IntBuffer) { + return ((IntBuffer) buf).array(); + } else if (buf instanceof ShortBuffer) { + return ((ShortBuffer) buf).array(); + } else if (buf instanceof DoubleBuffer) { + return ((DoubleBuffer) buf).array(); + } else if (buf instanceof LongBuffer) { + return ((LongBuffer) buf).array(); + } + + throw new RuntimeException("Disallowed array backing store type in buffer " + + buf.getClass().getName()); } @@ -161,5 +161,4 @@ public class BufferFactory { throw new RuntimeException("Unknown buffer type " + buf.getClass().getName()); } - } diff --git a/src/net/java/games/jogl/Animator.java b/src/net/java/games/jogl/Animator.java index 15d31c224..ac6248487 100644 --- a/src/net/java/games/jogl/Animator.java +++ b/src/net/java/games/jogl/Animator.java @@ -67,6 +67,7 @@ public class Animator { private volatile boolean shouldStop; protected boolean ignoreExceptions; protected boolean printExceptions; + private boolean runAsFastAsPossible; // For efficient rendering of Swing components, in particular when // they overlap one another @@ -119,6 +120,14 @@ public class Animator { this.printExceptions = printExceptions; } + /** Sets a flag in this Animator indicating that it is to run as + fast as possible. By default there is a brief pause in the + animation loop which prevents the CPU from getting swamped. + This method may not have an effect on subclasses. */ + public final void setRunAsFastAsPossible(boolean runFast) { + runAsFastAsPossible = runFast; + } + /** Called every frame to cause redrawing of all of the GLAutoDrawables this Animator manages. Subclasses should call this to get the most optimized painting behavior for the set of @@ -174,10 +183,12 @@ public class Animator { } } display(); - // Avoid swamping the CPU - try { - Thread.sleep(1); - } catch (InterruptedException e) { + if (!runAsFastAsPossible) { + // Avoid swamping the CPU + try { + Thread.sleep(1); + } catch (InterruptedException e) { + } } } } finally { diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java index d3d95166c..c5b3b7d95 100644 --- a/src/net/java/games/jogl/GLJPanel.java +++ b/src/net/java/games/jogl/GLJPanel.java @@ -48,6 +48,7 @@ import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; +import java.nio.*; import java.security.*; import javax.swing.JComponent; import javax.swing.JPanel; @@ -98,8 +99,8 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { private BufferedImage offscreenImage; // One of these is used to store the read back pixels before storing // in the BufferedImage - private byte[] readBackBytes; - private int[] readBackInts; + private ByteBuffer readBackBytes; + private IntBuffer readBackInts; private int readBackWidthInPixels; private int readBackHeightInPixels; // Width of the actual GLJPanel @@ -514,7 +515,7 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { case BufferedImage.TYPE_3BYTE_BGR: glFormat = GL.GL_BGR; glType = GL.GL_UNSIGNED_BYTE; - readBackBytes = new byte[readBackWidthInPixels * readBackHeightInPixels * 3]; + readBackBytes = ByteBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels * 3); break; case BufferedImage.TYPE_INT_RGB: @@ -523,7 +524,7 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { glType = (hardwareAccelerationDisabled ? offscreenContext.getOffscreenContextPixelDataType() : hwGLFormat); - readBackInts = new int[readBackWidthInPixels * readBackHeightInPixels]; + readBackInts = IntBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels); break; default: @@ -554,12 +555,9 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { // Actually read the pixels. gl.glReadBuffer(GL.GL_FRONT); if (readBackBytes != null) { - gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackBytes, 0); + gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackBytes); } else if (readBackInts != null) { - if (DEBUG && VERBOSE) { - System.err.println("GLJPanel$Updater.display(): readBackInts.length == " + readBackInts.length); - } - gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackInts, 0); + gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackInts); } // Restore saved modes. @@ -581,12 +579,12 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { int destIncr = 0; if (readBackBytes != null) { - src = readBackBytes; + src = readBackBytes.array(); dest = ((DataBufferByte) offscreenImage.getRaster().getDataBuffer()).getData(); srcIncr = readBackWidthInPixels * 3; destIncr = offscreenImage.getWidth() * 3; } else { - src = readBackInts; + src = readBackInts.array(); dest = ((DataBufferInt) offscreenImage.getRaster().getDataBuffer()).getData(); srcIncr = readBackWidthInPixels; destIncr = offscreenImage.getWidth(); diff --git a/src/net/java/games/jogl/impl/Project.java b/src/net/java/games/jogl/impl/Project.java index 41cf9d45e..6138a4108 100755 --- a/src/net/java/games/jogl/impl/Project.java +++ b/src/net/java/games/jogl/impl/Project.java @@ -104,11 +104,11 @@ */ package net.java.games.jogl.impl; +import java.nio.*; + import net.java.games.jogl.*; import net.java.games.jogl.util.*; -import java.nio.DoubleBuffer; - /** * Project.java * <p/> @@ -589,6 +589,33 @@ class Project { double y, double deltaX, double deltaY, + IntBuffer viewport) { + if (deltaX <= 0 || deltaY <= 0) { + return; + } + + /* Translate and scale the picked region to the entire window */ + gl.glTranslated((viewport.get(2) - 2 * (x - viewport.get(0))) / deltaX, + (viewport.get(3) - 2 * (y - viewport.get(1))) / deltaY, + 0); + gl.glScaled(viewport.get(2) / deltaX, viewport.get(3) / deltaY, 1.0); + } + + /** + * Method gluPickMatrix + * + * @param x + * @param y + * @param deltaX + * @param deltaY + * @param viewport + * @param viewport_offset + */ + public void gluPickMatrix(GL gl, + double x, + double y, + double deltaX, + double deltaY, int[] viewport, int viewport_offset) { if (deltaX <= 0 || deltaY <= 0) { diff --git a/src/net/java/games/jogl/impl/mipmap/Mipmap.java b/src/net/java/games/jogl/impl/mipmap/Mipmap.java index 8b697f37c..c80d25a12 100644 --- a/src/net/java/games/jogl/impl/mipmap/Mipmap.java +++ b/src/net/java/games/jogl/impl/mipmap/Mipmap.java @@ -263,7 +263,7 @@ public class Mipmap { if( target == GL.GL_TEXTURE_2D || target == GL.GL_PROXY_TEXTURE_2D ) { proxyTarget = GL.GL_PROXY_TEXTURE_2D; gl.glTexImage2D( proxyTarget, 1, internalFormat, widthAtLevelOne, - heightAtLevelOne, 0, format, type, (double[])null, 0 ); + heightAtLevelOne, 0, format, type, null ); } else if( (target == GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) || (target == GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) || (target == GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) || @@ -272,12 +272,12 @@ public class Mipmap { (target == GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) ) { proxyTarget = GL.GL_PROXY_TEXTURE_CUBE_MAP_ARB; gl.glTexImage2D( proxyTarget, 1, internalFormat, widthAtLevelOne, - heightAtLevelOne, 0, format, type, (double[])null, 0 ); + heightAtLevelOne, 0, format, type, null ); } else { assert( target == GL.GL_TEXTURE_1D || target == GL.GL_PROXY_TEXTURE_1D ); proxyTarget = GL.GL_PROXY_TEXTURE_1D; gl.glTexImage1D( proxyTarget, 1, internalFormat, widthAtLevelOne, - 0, format, type, (double[])null, 0 ); + 0, format, type, null ); } gl.glGetTexLevelParameteriv( proxyTarget, 1, GL.GL_TEXTURE_WIDTH, proxyWidth, 0 ); // does it fit? @@ -342,7 +342,7 @@ public class Mipmap { if( target == GL.GL_TEXTURE_3D || target == GL.GL_PROXY_TEXTURE_3D ) { proxyTarget = GL.GL_PROXY_TEXTURE_3D; gl.glTexImage3D( proxyTarget, 1, internalFormat, widthAtLevelOne, - heightAtLevelOne, depthAtLevelOne, 0, format, type, (double[])null, 0 ); + heightAtLevelOne, depthAtLevelOne, 0, format, type, null ); } gl.glGetTexLevelParameteriv( proxyTarget, 1, GL.GL_TEXTURE_WIDTH, proxyWidth, 0 ); // does it fit |