/* * 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); emitCall(binding, writer); } writer.println(" }"); } else { writer.println(";"); } } 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) { 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.getPositionByteOffset("); 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 + ".length <= " + offsetArg + ")"); writer.print(" throw new " + getRuntimeExceptionType()); writer.println("(\"array offset argument \\\"" + offsetArg + "\\\" equals or exceeds array length\");"); } } } } 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 emitCall(MethodBinding binding, PrintWriter writer) { writer.print(getImplMethodName()); writer.print("("); emitCallArguments(binding, writer); writer.print(")"); emitCallResultReturn(binding, writer); } protected int emitCallArguments(MethodBinding binding, PrintWriter writer) { boolean needComma = false; int numArgsEmitted = 0; int numBufferOffsetArgs = 0, numBufferOffsetArrayArgs = 0; if (binding.hasContainingType()) { // Emit this pointer assert(binding.getContainingType().isCompoundTypeWrapper()); writer.print("getBuffer()"); needComma = true; ++numArgsEmitted; numBufferOffsetArgs++; //writer.print(", " + byteOffsetConversionArgName(numBufferOffsetArgs)); writer.print(", BufferFactory.getPositionByteOffset(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("(("); } 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.getPositionByteOffset(((" + binding.getArgumentName(i)); writer.print(" == null) ? null : " + binding.getArgumentName(i) + ".getBuffer()))"); } needComma = true; ++numArgsEmitted; if(type.isNIOBuffer() || type.isNIOBufferArray()) { if(!type.isArray()) { numBufferOffsetArgs++; writer.print (", BufferFactory.getPositionByteOffset(" + 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(); if (returnType.isCompoundTypeWrapper()) { 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"); } } else if (returnType.isNIOBuffer()) { writer.println(";"); writer.println(" if (_res == null) return null;"); writer.print(" return _res.order(ByteOrder.nativeOrder())"); } else if (returnType.isArrayOfCompoundTypeWrappers()) { 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(";"); } }