aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/games/gluegen/CMethodBindingEmitter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java/games/gluegen/CMethodBindingEmitter.java')
-rw-r--r--src/net/java/games/gluegen/CMethodBindingEmitter.java1343
1 files changed, 0 insertions, 1343 deletions
diff --git a/src/net/java/games/gluegen/CMethodBindingEmitter.java b/src/net/java/games/gluegen/CMethodBindingEmitter.java
deleted file mode 100644
index f8afd06e4..000000000
--- a/src/net/java/games/gluegen/CMethodBindingEmitter.java
+++ /dev/null
@@ -1,1343 +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;
-
-import net.java.games.gluegen.cgram.types.*;
-
-/** Emits the C-side component of the Java<->C JNI binding. */
-public class CMethodBindingEmitter extends FunctionEmitter
-{
- protected static final CommentEmitter defaultCommentEmitter =
- new DefaultCommentEmitter();
-
- protected static final String arrayResLength = "_array_res_length";
- protected static final String arrayRes = "_array_res";
- protected static final String arrayIdx = "_array_idx";
-
- private MethodBinding binding;
-
- /** Name of the package in which the corresponding Java method resides.*/
- private String packageName;
-
- /** Name of the class in which the corresponding Java method resides.*/
- private String className;
-
- /**
- * Whether or not the Java<->C JNI binding for this emitter's MethodBinding
- * is overloaded.
- */
- private boolean isOverloadedBinding;
-
- /**
- * Whether or not the Java-side of the Java<->C JNI binding for this
- * emitter's MethodBinding is static.
- */
- private boolean isJavaMethodStatic;
-
- /**
- * Optional List of Strings containing temporary C variables to declare.
- */
- private List/*<String>*/ temporaryCVariableDeclarations;
-
- /**
- * Optional List of Strings containing assignments to temporary C variables
- * to make after the call is completed.
- */
- private List/*<String>*/ temporaryCVariableAssignments;
-
- /**
- * Capacity of the return value in the event that it is encapsulated in a
- * java.nio.Buffer. Is ignored if binding.getJavaReturnType().isNIOBuffer()
- * == false;
- */
- private MessageFormat returnValueCapacityExpression = null;
-
- /**
- * Length of the returned array. Is ignored if
- * binding.getJavaReturnType().isArray() is false.
- */
- private MessageFormat returnValueLengthExpression = null;
-
- // Note: the VC++ 6.0 compiler emits hundreds of warnings when the
- // (necessary) null-checking code is enabled. This appears to just
- // be a compiler bug, but would be good to track down exactly why it
- // is happening. When the null checking is enabled for just the
- // GetPrimitiveArrayCritical calls, there are five warnings
- // generated for several thousand new if tests added to the code.
- // Which ones are the ones at fault? The line numbers for the
- // warnings are incorrect.
- private static final boolean EMIT_NULL_CHECKS = true;
-
- /**
- * Constructs an emitter for the specified binding, and sets a default
- * comment emitter that will emit the signature of the C function that is
- * being bound.
- */
- public CMethodBindingEmitter(MethodBinding binding,
- boolean isOverloadedBinding,
- String javaPackageName,
- String javaClassName,
- boolean isJavaMethodStatic,
- PrintWriter output)
- {
- super(output);
-
- assert(binding != null);
- assert(javaClassName != null);
- assert(javaPackageName != null);
-
- this.binding = binding;
- this.packageName = javaPackageName;
- this.className = javaClassName;
- this.isOverloadedBinding = isOverloadedBinding;
- this.isJavaMethodStatic = isJavaMethodStatic;
- setCommentEmitter(defaultCommentEmitter);
- }
-
- public final MethodBinding getBinding() { return binding; }
-
- public String getName() {
- return binding.getName();
- }
-
- /**
- * Get the expression for the capacity of the returned java.nio.Buffer.
- */
- public final MessageFormat getReturnValueCapacityExpression()
- {
- return returnValueCapacityExpression;
- }
-
- /**
- * If this function returns a void* encapsulated in a
- * java.nio.Buffer, 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
- * Java-side binding, returns an expression that will (when compiled
- * by a C compiler) evaluate to an integer-valued expression. The
- * value of this expression is the capacity of the java.nio.Buffer
- * returned from this method.
- *
- * @throws IllegalArgumentException if the <code>
- * binding.getJavaReturnType().isNIOBuffer() == false
- * </code>
- */
- public final void setReturnValueCapacityExpression(MessageFormat expression)
- {
- returnValueCapacityExpression = expression;
-
- if (!binding.getJavaReturnType().isNIOBuffer())
- {
- throw new IllegalArgumentException(
- "Cannot specify return value capacity for a method that does not " +
- "return java.nio.Buffer: \"" + binding + "\"");
- }
- }
-
- /**
- * Get the expression for the length of the returned array
- */
- public final MessageFormat getReturnValueLengthExpression()
- {
- return returnValueLengthExpression;
- }
-
- /**
- * If this function returns an array, sets the expression for the
- * length of the returned array.
- *
- * @param expression a MessageFormat which, when applied to an array
- * of type String[] that contains each of the arguments names of the
- * Java-side binding, returns an expression that will (when compiled
- * by a C compiler) evaluate to an integer-valued expression. The
- * value of this expression is the length of the array returned from
- * this method.
- *
- * @throws IllegalArgumentException if the <code>
- * binding.getJavaReturnType().isNIOBuffer() == false
- * </code>
- */
- public final void setReturnValueLengthExpression(MessageFormat expression)
- {
- returnValueLengthExpression = expression;
-
- if (!binding.getJavaReturnType().isArray())
- {
- throw new IllegalArgumentException(
- "Cannot specify return value length for a method that does not " +
- "return an array: \"" + binding + "\"");
- }
- }
-
- /**
- * Returns the List of Strings containing declarations for temporary
- * C variables to be assigned to after the underlying function call.
- */
- public final List/*<String>*/ getTemporaryCVariableDeclarations() {
- return temporaryCVariableDeclarations;
- }
-
- /**
- * Sets up a List of Strings containing declarations for temporary C
- * variables to be assigned to after the underlying function call. A
- * null argument indicates that no manual declarations are to be made.
- */
- public final void setTemporaryCVariableDeclarations(List/*<String>*/ arg) {
- temporaryCVariableDeclarations = arg;
- }
-
- /**
- * Returns the List of Strings containing assignments for temporary
- * C variables which are made after the underlying function call. A
- * null argument indicates that no manual assignments are to be
- * made.
- */
- public final List/*<String>*/ getTemporaryCVariableAssignments() {
- return temporaryCVariableAssignments;
- }
-
- /**
- * Sets up a List of Strings containing assignments for temporary C
- * variables which are made after the underlying function call. A
- * null argument indicates that no manual assignments are to be made.
- */
- public final void setTemporaryCVariableAssignments(List/*<String>*/ arg) {
- temporaryCVariableAssignments = arg;
- }
-
- /**
- * Get the name of the class in which the corresponding Java method
- * resides.
- */
- public String getJavaPackageName() { return packageName; }
-
- /**
- * Get the name of the package in which the corresponding Java method
- * resides.
- */
- public String getJavaClassName() { return className; }
-
- /**
- * Is the Java<->C JNI binding for this emitter's MethodBinding one of
- * several overloaded methods with the same name?
- */
- public final boolean getIsOverloadedBinding() { return isOverloadedBinding; }
-
- /**
- * Is the Java side of the Java<->C JNI binding for this emitter's
- * MethodBinding a static method?.
- */
- public final boolean getIsJavaMethodStatic() { return isJavaMethodStatic; }
-
- protected void emitReturnType(PrintWriter writer)
- {
- writer.print("JNIEXPORT ");
- writer.print(binding.getJavaReturnType().jniTypeName());
- writer.print(" JNICALL");
- }
-
- protected void emitName(PrintWriter writer)
- {
- writer.println(); // start name on new line
- writer.print("Java_");
- writer.print(jniMangle(getJavaPackageName()));
- writer.print("_");
- writer.print(jniMangle(getJavaClassName()));
- writer.print("_");
- if (isOverloadedBinding)
- {
- writer.print(jniMangle(binding));
- //System.err.println("OVERLOADED MANGLING FOR " + binding.getName() +
- // " = " + jniMangle(binding));
- }
- else
- {
- writer.print(jniMangle(binding.getName()));
- //System.err.println(" NORMAL MANGLING FOR " + binding.getName() +
- // " = " + jniMangle(binding.getName()));
- }
- }
-
- protected int emitArguments(PrintWriter writer)
- {
- writer.print("JNIEnv *env, ");
- int numEmitted = 1; // initially just the JNIEnv
- if (isJavaMethodStatic && !binding.hasContainingType())
- {
- writer.print("jclass");
- }
- else
- {
- writer.print("jobject");
- }
- writer.print(" _unused");
- ++numEmitted;
-
- if (binding.hasContainingType())
- {
- // "this" argument always comes down in argument 0 as direct buffer
- writer.print(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
- }
- for (int i = 0; i < binding.getNumArguments(); i++) {
- JavaType javaArgType = binding.getJavaArgumentType(i);
- // Handle case where only param is void
- if (javaArgType.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 (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
- continue;
- }
- writer.print(", ");
- writer.print(javaArgType.jniTypeName());
- writer.print(" ");
- writer.print(binding.getArgumentName(i));
- ++numEmitted;
- }
-
- return numEmitted;
- }
-
-
- protected void emitBody(PrintWriter writer)
- {
- writer.println(" {");
- emitBodyVariableDeclarations(writer);
- emitBodyUserVariableDeclarations(writer);
- emitBodyVariablePreCallSetup(writer, false);
- emitBodyVariablePreCallSetup(writer, true);
- emitBodyCallCFunction(writer);
- emitBodyUserVariableAssignments(writer);
- emitBodyVariablePostCallCleanup(writer, true);
- emitBodyVariablePostCallCleanup(writer, false);
- emitBodyReturnResult(writer);
- writer.println("}");
- writer.println();
- }
-
- protected void emitBodyVariableDeclarations(PrintWriter writer)
- {
- // Emit declarations for all pointer and String conversion variables
- if (binding.hasContainingType()) {
- emitPointerDeclaration(writer,
- binding.getContainingType(),
- binding.getContainingCType(),
- CMethodBindingEmitter.cThisArgumentName(),
- null);
- }
-
- boolean emittedDataCopyTemps = false;
- for (int i = 0; i < binding.getNumArguments(); i++) {
- JavaType type = binding.getJavaArgumentType(i);
- if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
- continue;
- }
-
- if (type.isArray() || type.isNIOBuffer()) {
- String convName = pointerConversionArgumentName(i);
- // handle array/buffer argument types
- boolean needsDataCopy =
- emitPointerDeclaration(writer,
- binding.getJavaArgumentType(i),
- binding.getCArgumentType(i),
- convName,
- binding.getArgumentName(i));
- if (needsDataCopy && !emittedDataCopyTemps) {
- // emit loop counter and array length variables used during data
- // copy
- writer.println(" jobject _tmpObj;");
- writer.println(" int _copyIndex;");
- writer.println(" jsize _tmpArrayLen;");
- emittedDataCopyTemps = true;
- }
- } else if (type.isString()) {
- writer.print(" const char* _UTF8");
- writer.print(binding.getArgumentName(i));
- writer.println(" = NULL;");
- }
-
- }
-
- // Emit declaration for return value if necessary
- Type cReturnType = binding.getCReturnType();
-
- JavaType javaReturnType = binding.getJavaReturnType();
- String capitalizedComponentType = null;
- if (!cReturnType.isVoid()) {
- writer.print(" ");
- // 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");
- }
-
- 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(";");
- }
- }
- }
- }
-
- /** Emits the user-defined C variable declarations from the
- TemporaryCVariableDeclarations directive in the .cfg file. */
- protected void emitBodyUserVariableDeclarations(PrintWriter writer) {
- if (temporaryCVariableDeclarations != null) {
- for (Iterator iter = temporaryCVariableDeclarations.iterator(); iter.hasNext(); ) {
- String val = (String) iter.next();
- writer.print(" ");
- writer.println(val);
- }
- }
- }
-
- /**
- * Code to init the variables that were declared in
- * emitBodyVariableDeclarations(), PRIOR TO calling the actual C
- * function.
- */
- protected void emitBodyVariablePreCallSetup(PrintWriter writer,
- boolean emittingPrimitiveArrayCritical)
- {
- 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
- if (binding.hasContainingType()) {
- emitPointerConversion(writer, binding,
- binding.getContainingType(),
- binding.getContainingCType(),
- JavaMethodBindingEmitter.javaThisArgumentName(),
- CMethodBindingEmitter.cThisArgumentName());
- }
-
- for (int i = 0; i < binding.getNumArguments(); i++) {
- JavaType type = binding.getJavaArgumentType(i);
- if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
- continue;
- }
- if (type.isNIOBuffer()) {
- emitPointerConversion(writer, binding, type,
- binding.getCArgumentType(i),
- binding.getArgumentName(i),
- pointerConversionArgumentName(i));
- }
- }
- }
-
- // Convert all arrays to pointers, and get UTF-8 versions of jstring args
- for (int i = 0; i < binding.getNumArguments(); i++) {
- JavaType javaArgType = binding.getJavaArgumentType(i);
-
- if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
- continue;
- }
-
- if (javaArgType.isArray()) {
- 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
- // we're calling
- if ((!needsDataCopy && !emittingPrimitiveArrayCritical) ||
- (needsDataCopy && emittingPrimitiveArrayCritical)) {
- continue;
- }
-
- if (EMIT_NULL_CHECKS) {
- writer.print(" if (");
- writer.print(binding.getArgumentName(i));
- writer.println(" != NULL) {");
- }
-
- Type cArgType = binding.getCArgumentType(i);
- String cArgTypeName = cArgType.getName();
-
- String convName = pointerConversionArgumentName(i);
-
- if (!needsDataCopy) {
- writer.print(" ");
- writer.print(convName);
- writer.print(" = (");
- if (javaArgType.isArray() &&
- javaArgType.getJavaClass().getComponentType() == java.lang.String.class) {
- // java-side type is String[]
- cArgTypeName = "jstring *";
- }
- writer.print(cArgTypeName);
- writer.print(") (*env)->GetPrimitiveArrayCritical(env, ");
- writer.print(binding.getArgumentName(i));
- writer.println(", NULL);");
- } else {
- // Handle the case where the array elements are of a type that needs a
- // data copy operation to convert from the java memory model to the C
- // memory model (e.g., int[][], String[], etc)
- //
- // FIXME: should factor out this whole block of code into a separate
- // method for clarity and maintenance purposes
- if (cArgType.toString().indexOf("const") == -1) {
- // FIXME: if the arg type is non-const, the sematics might be that
- // the function modifies the argument -- we don't yet support
- // this.
- //
- // Note: the check for "const" in the CVAttributes string isn't
- // truly checking the constness of the target types at both
- // pointer depths. However, it's a quick approximation, and quite
- // often C code doesn't get the constness right anyhow.
- throw new RuntimeException(
- "Cannot copy data for ptr-to-ptr arg type \"" + cArgType +
- "\": support for non-const ptr-to-ptr types not implemented.");
- }
-
- writer.println();
- writer.println(" /* Copy contents of " + binding.getArgumentName(i) +
- " into " + convName + "_copy */");
-
- // get length of array being copied
- String arrayLenName = "_tmpArrayLen";
- writer.print(" ");
- writer.print(arrayLenName);
- writer.print(" = (*env)->GetArrayLength(env, ");
- writer.print(binding.getArgumentName(i));
- writer.println(");");
-
- // allocate an array to hold each element
- if (cArgType.pointerDepth() != 2) {
- throw new RuntimeException(
- "Could not copy data for type \"" + cArgType +
- "\"; copying only supported for types of the form " +
- "ptr-to-ptr-to-type.");
- }
- PointerType cArgPtrType = cArgType.asPointer();
- if (cArgPtrType == null) {
- throw new RuntimeException(
- "Could not copy data for type \"" + cArgType +
- "\"; currently only pointer types supported.");
- }
- PointerType cArgElementType = cArgPtrType.getTargetType().asPointer();
- emitMalloc(
- writer,
- convName+"_copy",
- cArgElementType.getName(),
- arrayLenName,
- "Could not allocate buffer for copying data in argument \\\""+binding.getArgumentName(i)+"\\\"");
-
- // 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(binding.getArgumentName(i));
- writer.println(", _copyIndex);");
-
- if (subArrayElementJNITypeString == "jstring")
- {
- writer.print(" ");
- emitGetStringUTFChars(writer,
- "(jstring) _tmpObj",
- convName+"_copy[_copyIndex]");
- }
- else if (isNIOBufferClass(subArrayElementJavaType))
- {
- emitGetDirectBufferAddress(writer,
- "_tmpObj",
- cArgElementType.getName(),
- convName + "_copy[_copyIndex]");
- }
- 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?
- // Probably depends on const-ness of the argument.
- // 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)+"\\\"");
- // 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");
-
-
- }
- writer.println(" }");
-
- writer.println();
- } // end of data copy
-
- if (EMIT_NULL_CHECKS) {
- writer.println(" }");
- }
-
- } else if (javaArgType.isString()) {
- if (emittingPrimitiveArrayCritical) {
- continue;
- }
-
- if (EMIT_NULL_CHECKS) {
- writer.print(" if (");
- writer.print(binding.getArgumentName(i));
- writer.println(" != NULL) {");
- }
-
- emitGetStringUTFChars(writer,
- binding.getArgumentName(i),
- "_UTF8" + binding.getArgumentName(i));
-
- if (EMIT_NULL_CHECKS) {
- writer.println(" }");
- }
- } else if (javaArgType.isArrayOfCompoundTypeWrappers()) {
-
- // FIXME
- throw new RuntimeException("Outgoing arrays of StructAccessors not yet implemented");
- }
- }
- }
-
-
- /**
- * Code to clean up any variables that were declared in
- * emitBodyVariableDeclarations(), AFTER calling the actual C function.
- */
- protected void emitBodyVariablePostCallCleanup(PrintWriter writer,
- boolean emittingPrimitiveArrayCritical)
- {
- // Release primitive arrays and temporary UTF8 strings if necessary
- for (int i = 0; i < binding.getNumArguments(); i++) {
- JavaType javaArgType = binding.getJavaArgumentType(i);
- if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
- continue;
- }
- if (javaArgType.isArray()) {
- boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType);
- Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType();
-
- if ((!needsDataCopy && !emittingPrimitiveArrayCritical) ||
- (needsDataCopy && emittingPrimitiveArrayCritical)) {
- continue;
- }
-
- if (EMIT_NULL_CHECKS) {
- writer.print(" if (");
- writer.print(binding.getArgumentName(i));
- writer.println(" != NULL) {");
- }
-
- String convName = pointerConversionArgumentName(i);
-
- if (!needsDataCopy) {
- // Release array
- writer.print(" (*env)->ReleasePrimitiveArrayCritical(env, ");
- writer.print(binding.getArgumentName(i));
- writer.print(", ");
- writer.print(convName);
- writer.println(", JNI_ABORT);");
- } else {
- // clean up the case where the array elements are of a type that needed
- // a data copy operation to convert from the java memory model to the
- // C memory model (e.g., int[][], String[], etc)
- //
- // FIXME: should factor out this whole block of code into a separate
- // method for clarity and maintenance purposes
- Type cArgType = binding.getCArgumentType(i);
- String cArgTypeName = cArgType.getName();
-
- if (cArgType.toString().indexOf("const") == -1) {
- // FIXME: handle any cleanup from treatment of non-const args,
- // assuming they were treated differently in
- // emitBodyVariablePreCallSetup() (see the similar section in that
- // method for details).
- throw new RuntimeException(
- "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType +
- "\": support for cleaning up non-const ptr-to-ptr types not implemented.");
- }
-
- writer.println(" /* Clean up " + convName + "_copy */");
-
- // Only need to perform cleanup for individual array
- // elements if they are not direct buffers
- if (!isNIOBufferClass(subArrayElementJavaType)) {
- // Re-fetch length of array that was copied
- String arrayLenName = "_tmpArrayLen";
- writer.print(" ");
- writer.print(arrayLenName);
- writer.print(" = (*env)->GetArrayLength(env, ");
- writer.print(binding.getArgumentName(i));
- writer.println(");");
-
- // free each element
- PointerType cArgPtrType = cArgType.asPointer();
- if (cArgPtrType == null) {
- throw new RuntimeException(
- "Could not copy data for type \"" + cArgType +
- "\"; currently only pointer types supported.");
- }
- PointerType cArgElementType = cArgPtrType.getTargetType().asPointer();
-
- // process each element in the array
- writer.println(" for (_copyIndex = 0; _copyIndex < " + arrayLenName +"; ++_copyIndex) {");
-
- // 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(binding.getArgumentName(i));
- writer.println(", _copyIndex);");
-
- if (subArrayElementJNITypeString == "jstring") {
- writer.print(" (*env)->ReleaseStringUTFChars(env, ");
- writer.print("(jstring) _tmpObj");
- writer.print(", ");
- writer.print(convName+"_copy[_copyIndex]");
- writer.println(");");
- } else {
- if (true) throw new RuntimeException(
- "Cannot yet handle type \"" + cArgType.getName() +
- "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays");
- }
- writer.println(" }");
- }
-
- // free the main array
- writer.print(" free((void*) ");
- writer.print(convName+"_copy");
- writer.println(");");
- } // end of cleaning up copied data
-
- if (EMIT_NULL_CHECKS) {
- writer.println(" }");
- }
- } else if (javaArgType.isString()) {
- if (emittingPrimitiveArrayCritical) {
- continue;
- }
-
- if (EMIT_NULL_CHECKS) {
- writer.print(" if (");
- writer.print(binding.getArgumentName(i));
- writer.println(" != NULL) {");
- }
-
- writer.print(" (*env)->ReleaseStringUTFChars(env, ");
- writer.print(binding.getArgumentName(i));
- writer.print(", _UTF8");
- writer.print(binding.getArgumentName(i));
- writer.println(");");
-
- if (EMIT_NULL_CHECKS) {
- writer.println(" }");
- }
- } else if (javaArgType.isArrayOfCompoundTypeWrappers()) {
-
- // FIXME
- throw new RuntimeException("Outgoing arrays of StructAccessors not yet implemented");
-
- }
- }
- }
-
- 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("(");
- for (int i = 0; i < binding.getNumArguments(); i++) {
- if (i != 0) {
- writer.print(", ");
- }
- JavaType javaArgType = binding.getJavaArgumentType(i);
- // Handle case where only param is void.
- if (javaArgType.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 (javaArgType.isJNIEnv()) {
- writer.print("env");
- } else if (binding.isArgumentThisPointer(i)) {
- writer.print(CMethodBindingEmitter.cThisArgumentName());
- } else {
- writer.print("(");
- Type cArgType = binding.getCSymbol().getArgumentType(i);
- writer.print(cArgType.getName());
- writer.print(") ");
- if (binding.getCArgumentType(i).isPointer() && binding.getJavaArgumentType(i).isPrimitive()) {
- writer.print("(intptr_t) ");
- }
- if (javaArgType.isArray() || javaArgType.isNIOBuffer()) {
- writer.print(pointerConversionArgumentName(i));
- if (javaArgTypeNeedsDataCopy(javaArgType)) {
- writer.print("_copy");
- }
- } else {
- if (javaArgType.isString()) { writer.print("_UTF8"); }
- writer.print(binding.getArgumentName(i));
- }
- }
- }
- writer.println(");");
- }
-
- /** Emits the user-defined C variable assignments from the
- TemporaryCVariableAssignments directive in the .cfg file. */
- protected void emitBodyUserVariableAssignments(PrintWriter writer) {
- if (temporaryCVariableAssignments != null) {
- for (Iterator iter = temporaryCVariableAssignments.iterator(); iter.hasNext(); ) {
- String val = (String) iter.next();
- writer.print(" ");
- writer.println(val);
- }
- }
- }
-
- // 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
- // typedef-resolved.
- Type cReturnType = binding.getCReturnType();
-
- // Return result if necessary
- if (!cReturnType.isVoid()) {
- JavaType javaReturnType = binding.getJavaReturnType();
- if (javaReturnType.isPrimitive()) {
- writer.print(" return ");
- if (cReturnType.isPointer()) {
- // Pointer being converted to int or long: cast this result
- // (through intptr_t to avoid compiler warnings with gcc)
- writer.print("(" + javaReturnType.jniTypeName() + ") (intptr_t) ");
- }
- writer.println("_res;");
- } else if (javaReturnType.isNIOBuffer()) {
- writer.println(" if (_res == NULL) return NULL;");
- writer.print(" return (*env)->NewDirectByteBuffer(env, _res, ");
- // See whether capacity has been specified
- if (returnValueCapacityExpression != null) {
- String[] argumentNames = new String[binding.getNumArguments()];
- for (int i = 0; i < binding.getNumArguments(); i++)
- {
- argumentNames[i] = binding.getArgumentName(i);
- }
- writer.print(
- returnValueCapacityExpression.format(argumentNames));
- } else {
- int sz = 0;
- if (cReturnType.isPointer() &&
- cReturnType.asPointer().getTargetType().isCompound()) {
- sz = cReturnType.asPointer().getTargetType().getSize();
- if (sz == -1) {
- throw new InternalError(
- "Error emitting code for compound return type "+
- "for function \"" + binding + "\": " +
- "Structs to be emitted should have been laid out by this point " +
- "(type " + cReturnType.asPointer().getTargetType().getName() + " / " +
- cReturnType.asPointer().getTargetType() + " was not)"
- );
- }
- } else {
- sz = cReturnType.getSize();
- }
- writer.print(sz);
- System.err.println(
- "WARNING: No capacity specified for java.nio.Buffer return " +
- "value for function \"" + binding + "\";" +
- " assuming size of equivalent C return type (" + sz + " bytes): " + binding);
- }
- writer.println(");");
- } 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 {
- // 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(";");
- }
- }
- }
- }
-
- protected static String cThisArgumentName() {
- return "this0";
- }
-
- // Mangle a class, package or function name
- protected String jniMangle(String name) {
- return name.replaceAll("_", "_1").replace('.', '_');
- }
-
- protected String jniMangle(MethodBinding binding) {
- StringBuffer buf = new StringBuffer();
- buf.append(jniMangle(binding.getName()));
- 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);
- } 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()) {
- if (c == Boolean.TYPE) res.append("Z");
- else if (c == Byte.TYPE) res.append("B");
- else if (c == Character.TYPE) res.append("C");
- else if (c == Short.TYPE) res.append("S");
- else if (c == Integer.TYPE) res.append("I");
- 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 {
- res.append("L");
- res.append(c.getName().replace('.', '_'));
- 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)
- {
- writer.print(" if (");
- writer.print(varName);
- writer.println(" == NULL) {");
- writer.println(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryError\"),");
- writer.print(" \"" + errorMessage);
- writer.print(" in native dispatcher for \\\"");
- writer.print(binding.getName());
- writer.println("\\\"\");");
- writer.print(" return");
- if (!binding.getJavaReturnType().isVoid()) {
- writer.print(" 0");
- }
- writer.println(";");
- writer.println(" }");
- }
-
- private void emitMalloc(PrintWriter writer,
- String targetVarName,
- String elementTypeString,
- String numElementsExpression,
- String mallocFailureErrorString)
- {
- writer.print(" ");
- writer.print(targetVarName);
- writer.print(" = (");
- writer.print(elementTypeString);
- writer.print(" *) malloc(");
- writer.print(numElementsExpression);
- writer.print(" * sizeof(");
- writer.print(elementTypeString);
- writer.println("));");
- // Catch memory allocation failure
- if (EMIT_NULL_CHECKS) {
- emitOutOfMemoryCheck(
- writer, targetVarName,
- mallocFailureErrorString);
- }
- }
-
- private void emitGetStringUTFChars(PrintWriter writer,
- String sourceVarName,
- String receivingVarName)
- {
- writer.print(" if (");
- writer.print(sourceVarName);
- writer.println(" != NULL) {");
- writer.print(" ");
- writer.print(receivingVarName);
- writer.print(" = (*env)->GetStringUTFChars(env, ");
- writer.print(sourceVarName);
- writer.println(", (jboolean*)NULL);");
- // Catch memory allocation failure in the event that the VM didn't pin
- // the String and failed to allocate a copy
- if (EMIT_NULL_CHECKS) {
- emitOutOfMemoryCheck(
- writer, receivingVarName,
- "Failed to get UTF-8 chars for argument \\\""+sourceVarName+"\\\"");
- }
- writer.println(" } else {");
- writer.print(" ");
- writer.print(receivingVarName);
- writer.println(" = NULL;");
- writer.println(" }");
- }
-
- private void emitGetDirectBufferAddress(PrintWriter writer,
- String sourceVarName,
- String receivingVarTypeString,
- String receivingVarName) {
- if (EMIT_NULL_CHECKS) {
- writer.print(" if (");
- writer.print(sourceVarName);
- writer.println(" != NULL) {");
- }
- writer.print(" ");
- writer.print(receivingVarName);
- writer.print(" = (");
- writer.print(receivingVarTypeString);
- writer.print(") (*env)->GetDirectBufferAddress(env, ");
- writer.print(sourceVarName);
- writer.println(");");
- if (EMIT_NULL_CHECKS) {
- writer.println(" } else {");
- writer.print(" ");
- writer.print(receivingVarName);
- writer.println(" = NULL;");
- 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
- // an extra variable named XXX_copy (where XXX is the value of the
- // cVariableName argument) will be emitted and TRUE will be returned.
- private boolean emitPointerDeclaration(PrintWriter writer,
- JavaType javaType,
- Type cType,
- String cVariableName,
- String javaArgumentName) {
- String ptrTypeString = null;
- boolean needsDataCopy = false;
-
- // Emit declaration for the pointer variable.
- //
- // Note that we don't need to obey const/volatile for outgoing arguments
- //
- if (javaType.isNIOBuffer())
- {
- ptrTypeString = cType.getName();
- }
- 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())
- {
- 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
- {
- // 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())
- {
- // FIXME
- throw new RuntimeException("Outgoing arrays of StructAccessors not yet implemented");
- }
- else
- {
- ptrTypeString = cType.getName();
- }
-
- if (!needsDataCopy)
- {
- // declare the pointer variable
- writer.print(" ");
- writer.print(ptrTypeString);
- writer.print(" ");
- writer.print(cVariableName);
- writer.println(" = NULL;");
- }
- 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) {
- writer.print(" const char **");
- } else {
- writer.print(ptrTypeString);
- }
- writer.print(" ");
- writer.print(cVariableName);
- writer.print("_copy = NULL; /* copy of data in ");
- writer.print(javaArgumentName);
- writer.println(", laid out according to C memory model */");
- }
-
- return needsDataCopy;
- }
-
- private void emitPointerConversion(PrintWriter writer,
- MethodBinding binding,
- JavaType type,
- Type cType,
- String incomingArgumentName,
- String cVariableName) {
- emitGetDirectBufferAddress(writer,
- incomingArgumentName,
- cType.getName(),
- cVariableName);
-
- /*
- 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(" }");
- }
- */
- }
-
- protected String pointerConversionArgumentName(int i) {
- return "_ptr" + i;
- }
-
- /**
- * Class that emits a generic comment for CMethodBindingEmitters; the comment
- * includes the C signature of the native method that is being bound by the
- * emitter java method.
- */
- protected static class DefaultCommentEmitter implements CommentEmitter {
- public void emit(FunctionEmitter emitter, PrintWriter writer) {
- emitBeginning((CMethodBindingEmitter)emitter, writer);
- emitEnding((CMethodBindingEmitter)emitter, writer);
- }
- protected void emitBeginning(CMethodBindingEmitter emitter, PrintWriter writer) {
- writer.println(" Java->C glue code:");
- writer.print(" * Java package: ");
- writer.print(emitter.getJavaPackageName());
- writer.print(".");
- writer.println(emitter.getJavaClassName());
- writer.print(" * Java method: ");
- MethodBinding binding = emitter.getBinding();
- writer.println(binding);
- writer.println(" * C function: " + binding.getCSymbol());
- }
- protected void emitEnding(CMethodBindingEmitter emitter, PrintWriter writer) {
- }
- }
-
- protected boolean javaArgTypeNeedsDataCopy(JavaType javaArgType) {
- if (javaArgType.isArray()) {
- Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType();
- return (subArrayElementJavaType.isArray() ||
- subArrayElementJavaType == java.lang.String.class ||
- isNIOBufferClass(subArrayElementJavaType));
- }
- return false;
- }
-
- protected static boolean isNIOBufferClass(Class c) {
- return java.nio.Buffer.class.isAssignableFrom(c);
- }
-}
-