/* * 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 net.java.games.gluegen.cgram.types.*; import net.java.games.gluegen.cgram.*; /** * An emitter that emits only the interface for a Java<->C JNI binding. */ public class JavaMethodBindingEmitter extends FunctionEmitter { public static final EmissionModifier PUBLIC = new EmissionModifier("public"); public static final EmissionModifier PROTECTED = new EmissionModifier("protected"); public static final EmissionModifier PRIVATE = new EmissionModifier("private"); public static final EmissionModifier ABSTRACT = new EmissionModifier("abstract"); public static final EmissionModifier FINAL = new EmissionModifier("final"); 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 = new InterfaceCommentEmitter(); // Exception type raised in the generated code if runtime checks fail private String runtimeExceptionType; protected MethodBinding binding; protected boolean forImplementingMethodCall; protected boolean forArrayImplementingMethodCall = false; protected boolean prefixedMethod = false; // A non-null value indicates that rather than returning a compound // type accessor we are returning an array of such accessors; this // expression is a MessageFormat string taking the names of the // incoming Java arguments as parameters and computing as an int the // 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) { super(output); this.binding = binding; this.forImplementingMethodCall = forImplementingMethodCall; this.forArrayImplementingMethodCall = forArrayImplementingMethodCall; this.runtimeExceptionType = runtimeExceptionType; setCommentEmitter(defaultInterfaceCommentEmitter); } public JavaMethodBindingEmitter(JavaMethodBindingEmitter arg) { super(arg); runtimeExceptionType = arg.runtimeExceptionType; binding = arg.binding; forImplementingMethodCall = arg.forImplementingMethodCall; returnedArrayLengthExpression = arg.returnedArrayLengthExpression; } public final MethodBinding getBinding() { return binding; } public boolean isForImplementingMethodCall() { return forImplementingMethodCall; } public String getName() { return binding.getName(); } /** The type of exception (must subclass java.lang.RuntimeException) raised if runtime checks fail in the generated code. */ public String getRuntimeExceptionType() { return runtimeExceptionType; } /** If the underlying function returns an array (currently only arrays of compound types are supported) as opposed to a pointer to an object, this method should be called to provide a MessageFormat string containing an expression that computes the number of elements of the returned array. The parameters to the MessageFormat expression are the names of the incoming Java arguments. */ public void setReturnedArrayLengthExpression(String expr) { returnedArrayLengthExpression = expr; } protected void emitReturnType(PrintWriter writer) { writer.print(getReturnTypeString(false)); } protected String getReturnTypeString(boolean skipArray) { if (skipArray || (getReturnedArrayLengthExpression() == null && !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers())) { return binding.getJavaReturnType().getName(); } return binding.getJavaReturnType().getName() + "[]"; } protected void emitName(PrintWriter writer) { if (forImplementingMethodCall) { writer.print(getImplMethodName()); } else { writer.print(getName()); } } protected int emitArguments(PrintWriter writer) { 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(javaThisArgumentName()); ++numEmitted; needComma = true; numBufferOffsetArgs++; writer.print(", int " + byteOffsetConversionArgName(numBufferOffsetArgs)); } for (int i = 0; i < binding.getNumArguments(); i++) { JavaType type = binding.getJavaArgumentType(i); 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. if (binding.getNumArguments() != 1) { throw new InternalError( "\"void\" argument type found in " + "multi-argument function \"" + binding + "\""); } continue; } if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) { // Don't need to expose these at the Java level continue; } if (needComma) { writer.print(", "); } writer.print(type.getName()); 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 array index offset argument after each primitive array if( type.isArray() && !type.isNIOBufferArray() && !type.isStringArray()) { writer.print(", int " + binding.getArgumentName(i) + "_offset"); } } return numEmitted; } protected String getImplMethodName() { if(!forArrayImplementingMethodCall) return binding.getName() + "0"; else return binding.getName() + "1"; } protected String byteOffsetConversionArgName(int i) { return "__byteOffset" + i; } protected String byteOffsetArrayConversionArgName(int i) { return "__byteOffsetArray" + i; } protected void emitBody(PrintWriter writer) { writer.println(';'); } protected static String javaThisArgumentName() { return "jthis0"; } protected String getCommentStartString() { return "/** "; } protected String getBaseIndentString() { return " "; } protected String getReturnedArrayLengthExpression() { return returnedArrayLengthExpression; } /** * Class that emits a generic comment for JavaMethodBindingEmitters; the comment * includes the C signature of the native method that is being bound by the * emitter java method. */ protected static class DefaultCommentEmitter implements CommentEmitter { public void emit(FunctionEmitter emitter, PrintWriter writer) { emitBeginning(emitter, writer); emitBindingCSignature(((JavaMethodBindingEmitter)emitter).getBinding(), writer); emitEnding(emitter, writer); } protected void emitBeginning(FunctionEmitter emitter, PrintWriter writer) { writer.print("Entry point to C language function:
"); } protected void emitBindingCSignature(MethodBinding binding, PrintWriter writer) { writer.print(" "); writer.print(binding.getCSymbol()); writer.print(" "); } 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. MethodBinding binding = ((JavaMethodBindingEmitter)emitter).getBinding(); for (int i = 0; i < binding.getNumArguments(); i++) { Type type = binding.getCArgumentType(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. if (type.isEnum() && type.getName() != HeaderParser.ANONYMOUS_ENUM_NAME) { EnumType enumType = (EnumType)type; writer.println(); writer.print(emitter.getBaseIndentString()); writer.print(" "); writer.print("@param "); writer.print(binding.getArgumentName(i)); writer.print(" valid values are: "); for (int j = 0; j < enumType.getNumEnumerates(); ++j) { if (j>0) writer.print(", "); writer.print(enumType.getEnumName(j)); } writer.println(""); } } } } protected static class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { protected void emitBeginning(FunctionEmitter emitter, PrintWriter writer) { writer.print("Interface to C language function:
"); } } }