diff options
author | Sven Gothel <[email protected]> | 2010-11-06 23:13:39 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-11-06 23:13:39 +0100 |
commit | 6f2d046c8d532db94f6af5003e341104d5bf4aff (patch) | |
tree | 723c31b8f9c1097ae48486acbf68e4e06fab2517 /src/java/com/sun/gluegen/JavaEmitter.java | |
parent | ec6d61f4597af32c22319c4bda3c9dd9ab80bf25 (diff) |
Renamed com.sun.gluegen -> com.jogamp.gluegen
Diffstat (limited to 'src/java/com/sun/gluegen/JavaEmitter.java')
-rw-r--r-- | src/java/com/sun/gluegen/JavaEmitter.java | 1950 |
1 files changed, 0 insertions, 1950 deletions
diff --git a/src/java/com/sun/gluegen/JavaEmitter.java b/src/java/com/sun/gluegen/JavaEmitter.java deleted file mode 100644 index 5fc07b0..0000000 --- a/src/java/com/sun/gluegen/JavaEmitter.java +++ /dev/null @@ -1,1950 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2010 JogAmp Community. 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 com.sun.gluegen; - -import com.jogamp.common.nio.Buffers; -import com.jogamp.common.os.DynamicLookupHelper; -import java.io.*; -import java.util.*; -import java.text.MessageFormat; - -import com.sun.gluegen.cgram.types.*; -import java.nio.Buffer; -import java.util.logging.Logger; - -import static java.util.logging.Level.*; -import static com.sun.gluegen.JavaEmitter.MethodAccess.*; - -// PROBLEMS: -// - what if something returns 'const int *'? Could we -// return an IntBuffer that has read-only behavior? Or do we copy the array -// (but we don't know its size!). What do we do if it returns a non-const -// int*? Should the user be allowed to write back to the returned pointer? -// -// - Non-const array types must be properly released with JNI_COMMIT -// in order to see side effects if the array was copied. - - -public class JavaEmitter implements GlueEmitter { - - private StructLayout layout; - private TypeDictionary typedefDictionary; - private TypeDictionary structDictionary; - private Map<Type, Type> canonMap; - protected JavaConfiguration cfg; - - /** - * Style of code emission. Can emit everything into one class - * (AllStatic), separate interface and implementing classes - * (InterfaceAndImpl), only the interface (InterfaceOnly), or only - * the implementation (ImplOnly). - */ - public enum EmissionStyle {AllStatic, InterfaceAndImpl, InterfaceOnly, ImplOnly}; - - /** - * Access control for emitted Java methods. - */ - public enum MethodAccess {PUBLIC, PROTECTED, PRIVATE, PACKAGE_PRIVATE, PUBLIC_ABSTRACT} - - private PrintWriter javaWriter; // Emits either interface or, in AllStatic mode, everything - private PrintWriter javaImplWriter; // Only used in non-AllStatic modes for impl class - private PrintWriter cWriter; - private MachineDescription machDesc32; - private MachineDescription machDesc64; - - protected final static Logger LOG = Logger.getLogger(JavaEmitter.class.getPackage().getName()); - - public void readConfigurationFile(String filename) throws Exception { - cfg = createConfig(); - cfg.read(filename); - } - - public void setMachineDescription(MachineDescription md32, MachineDescription md64) { - - if ((md32 == null) && (md64 == null)) { - throw new RuntimeException("Must specify at least one MachineDescription"); - } - - machDesc32 = md32; - machDesc64 = md64; - } - - class ConstantRenamer implements SymbolFilter { - - private List<ConstantDefinition> constants; - - public void filterSymbols(List<ConstantDefinition> constants, List<FunctionSymbol> functions) { - this.constants = constants; - doWork(); - } - - public List<ConstantDefinition> getConstants() { - return constants; - } - - public List<FunctionSymbol> getFunctions() { - return null; - } - - private void doWork() { - List<ConstantDefinition> newConstants = new ArrayList<ConstantDefinition>(); - JavaConfiguration cfg = getConfig(); - for (ConstantDefinition def : constants) { - def.rename(cfg.getJavaSymbolRename(def.getName())); - newConstants.add(def); - } - constants = newConstants; - } - } - - public void beginEmission(GlueEmitterControls controls) throws IOException { - - // Request emission of any structs requested - for (String structs : cfg.forcedStructs()) { - controls.forceStructEmission(structs); - } - - if (!cfg.structsOnly()) { - try { - openWriters(); - } catch (Exception e) { - throw new RuntimeException("Unable to open files for writing", e); - } - emitAllFileHeaders(); - - // Handle renaming of constants - controls.runSymbolFilter(new ConstantRenamer()); - } - } - - public void endEmission() { - if (!cfg.structsOnly()) { - emitAllFileFooters(); - - try { - closeWriters(); - } catch (Exception e) { - throw new RuntimeException("Unable to close open files", e); - } - } - } - - public void beginDefines() throws Exception { - if ((cfg.allStatic() || cfg.emitInterface()) && !cfg.structsOnly()) { - javaWriter().println(); - } - } - - protected static int getJavaRadix(String name, String value) { - // FIXME: need to handle when type specifier is in last char (e.g., - // "1.0d or 2759L", because parseXXX() methods don't allow the type - // specifier character in the string. - // - //char lastChar = value.charAt(value.length()-1); - - try { - // see if it's a long or int - int radix; - String parseValue; - // FIXME: are you allowed to specify hex/octal constants with - // negation, e.g. "-0xFF" or "-056"? If so, need to modify the - // following "if(..)" checks and parseValue computation - if (value.startsWith("0x") || value.startsWith("0X")) { - radix = 16; - parseValue = value.substring(2); - } - else if (value.startsWith("0") && value.length() > 1) { - // TODO: is "0" the prefix in C to indicate octal??? - radix = 8; - parseValue = value.substring(1); - } - else { - radix = 10; - parseValue = value; - } - //System.err.println("parsing " + value + " as long w/ radix " + radix); - long longVal = Long.parseLong(parseValue, radix); - return radix; - } catch (NumberFormatException e) { - try { - // see if it's a double or float - double dVal = Double.parseDouble(value); - return 10; - } catch (NumberFormatException e2) { - throw new RuntimeException( - "Cannot emit define \""+name+"\": value \""+value+ - "\" cannot be assigned to a int, long, float, or double", e2); - } - } - } - - protected static Object getJavaValue(String name, String value) { - - // "calculates" the result type of a simple expression - // example: (2+3)-(2.0f-3.0) -> Double - // example: (1 << 2) -> Integer - - Scanner scanner = new Scanner(value).useDelimiter("[+-/*/></(/)]"); - - Object resultType = null; - - while (scanner.hasNext()) { - - String t = scanner.next().trim(); - - if(0<t.length()) { - Object type = getJavaValue2(name, t); - - //fast path - if(type instanceof Double) - return type; - - if(resultType != null) { - - if(resultType instanceof Integer) { - if(type instanceof Long || type instanceof Float || type instanceof Double) - resultType = type; - }else if(resultType instanceof Long) { - if(type instanceof Float || type instanceof Double) - resultType = type; - }else if(resultType instanceof Float) { - if(type instanceof Float) - resultType = type; - } - }else{ - resultType = type; - } - - //fast path - if(resultType instanceof Double) - return type; - } - } - - return resultType; - } - - private static Object getJavaValue2(String name, String value) { - // FIXME: need to handle when type specifier is in last char (e.g., - // "1.0d or 2759L", because parseXXX() methods don't allow the type - // specifier character in the string. - // - char lastChar = value.charAt(value.length()-1); - - try { - // see if it's a long or int - int radix; - String parseValue; - // FIXME: are you allowed to specify hex/octal constants with - // negation, e.g. "-0xFF" or "-056"? If so, need to modify the - // following "if(..)" checks and parseValue computation - if (value.startsWith("0x") || value.startsWith("0X")) { - radix = 16; - parseValue = value.substring(2); - } else if (value.startsWith("0") && value.length() > 1) { - // TODO: is "0" the prefix in C to indicate octal??? - radix = 8; - parseValue = value.substring(1); - } else { - radix = 10; - parseValue = value; - } - if(lastChar == 'u' || lastChar == 'U') { - parseValue = parseValue.substring(0, parseValue.length()-1); - } - - //System.err.println("parsing " + value + " as long w/ radix " + radix); - long longVal = Long.parseLong(parseValue, radix); - // if constant is small enough, store it as an int instead of a long - if (longVal > Integer.MIN_VALUE && longVal < Integer.MAX_VALUE) { - return (int)longVal; - } - return longVal; - - } catch (NumberFormatException e) { - try { - // see if it's a double or float - double dVal = Double.parseDouble(value); - double absVal = Math.abs(dVal); - // if constant is small enough, store it as a float instead of a double - if (absVal < Float.MIN_VALUE || absVal > Float.MAX_VALUE) { - return new Double(dVal); - } - return new Float((float) dVal); - } catch (NumberFormatException e2) { - throw new RuntimeException( - "Cannot emit define \""+name+"\": value \""+value+ - "\" cannot be assigned to a int, long, float, or double", e2); - } - } - } - - - protected static String getJavaType(String name, String value) { - Object oval = getJavaValue(name, value); - return getJavaType(name, oval); - } - - protected static String getJavaType(String name, Object oval) { - if(oval instanceof Integer) { - return "int"; - } else if(oval instanceof Long) { - return "long"; - } else if(oval instanceof Float) { - return "float"; - } else if(oval instanceof Double) { - return "double"; - } - - throw new RuntimeException( - "Cannot emit define (2) \""+name+"\": value \""+oval+ - "\" cannot be assigned to a int, long, float, or double"); - } - - public void emitDefine(ConstantDefinition def, String optionalComment) throws Exception { - - if (cfg.allStatic() || cfg.emitInterface()) { - // TODO: Some defines (e.g., GL_DOUBLE_EXT in gl.h) are defined in terms - // of other defines -- should we emit them as references to the original - // define (not even sure if the lexer supports this)? Right now they're - // emitted as the numeric value of the original definition. If we decide - // emit them as references we'll also have to emit them in the correct - // order. It's probably not an issue right now because the emitter - // currently only emits only numeric defines -- if it handled #define'd - // objects it would make a bigger difference. - - String name = def.getName(); - String value = def.getValue(); - - if (!cfg.shouldIgnoreInInterface(name)) { - String type = getJavaType(name, value); - if (optionalComment != null && optionalComment.length() != 0) { - javaWriter().println(" /** " + optionalComment + " */"); - } - String suffix = ""; - if(!value.endsWith(")")) { - if (type.equals("float") && !value.endsWith("f")) { - suffix = "f"; - }else if(value.endsWith("u") || value.endsWith("U")) { - value = value.substring(0, value.length()-1); - } - } - - javaWriter().println(" public static final " + type + " " + name + " = " + value + suffix + ";"); - } - } - } - - public void endDefines() throws Exception { - } - - public void beginFunctions(TypeDictionary typedefDictionary, - TypeDictionary structDictionary, - Map<Type, Type> canonMap) throws Exception { - - this.typedefDictionary = typedefDictionary; - this.structDictionary = structDictionary; - this.canonMap = canonMap; - - if ((cfg.allStatic() || cfg.emitInterface()) && !cfg.structsOnly()) { - javaWriter().println(); - } - } - - public Iterator<FunctionSymbol> emitFunctions(List<FunctionSymbol> originalCFunctions) throws Exception { - - // Sometimes headers will have the same function prototype twice, once - // with the argument names and once without. We'll remember the signatures - // we've already processed we don't generate duplicate bindings. - // - // Note: this code assumes that on the equals() method in FunctionSymbol - // only considers function name and argument types (i.e., it does not - // consider argument *names*) when comparing FunctionSymbols for equality - Set<FunctionSymbol> funcsToBindSet = new HashSet<FunctionSymbol>(100); - for (FunctionSymbol cFunc : originalCFunctions) { - if (!funcsToBindSet.contains(cFunc)) { - funcsToBindSet.add(cFunc); - } - } - - // validateFunctionsToBind(funcsToBindSet); - - ArrayList<FunctionSymbol> funcsToBind = new ArrayList<FunctionSymbol>(funcsToBindSet); - // sort functions to make them easier to find in native code - Collections.sort(funcsToBind, new Comparator<FunctionSymbol>() { - public int compare(FunctionSymbol o1, FunctionSymbol o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - - // Bind all the C funcs to Java methods - HashSet<MethodBinding> methodBindingSet = new HashSet<MethodBinding>(); - ArrayList<FunctionEmitter> methodBindingEmitters = new ArrayList<FunctionEmitter>(2*funcsToBind.size()); - for (FunctionSymbol cFunc : funcsToBind) { - // Check to see whether this function should be ignored - if (!cfg.shouldIgnoreInImpl(cFunc.getName())) { - methodBindingEmitters.addAll(generateMethodBindingEmitters(methodBindingSet, cFunc)); - } - - } - - // Emit all the methods - for (FunctionEmitter emitter : methodBindingEmitters) { - try { - if (!emitter.isInterface() || !cfg.shouldIgnoreInInterface(emitter.getName())) { - emitter.emit(); - emitter.getDefaultOutput().println(); // put newline after method body - } - } catch (Exception e) { - throw new RuntimeException( - "Error while emitting binding for \"" + emitter.getName() + "\"", e); - } - } - - // Return the list of FunctionSymbols that we generated gluecode for - return funcsToBind.iterator(); - } - - /** - * Create the object that will read and store configuration information for - * this JavaEmitter. - */ - protected JavaConfiguration createConfig() { - return new JavaConfiguration(); - } - - /** - * Get the configuration information for this JavaEmitter. - */ - protected JavaConfiguration getConfig() { - return cfg; - } - - /** - * 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<FunctionEmitter> 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; - } - - MethodAccess accessControl = cfg.accessControl(binding.getName()); - // We should not emit anything except public APIs into interfaces - if (signatureOnly && (accessControl != PUBLIC)) { - 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()); - List<String> prologue = cfg.javaPrologueForMethod(binding, false, false); - List<String> epilogue = cfg.javaEpilogueForMethod(binding, false, false); - boolean needsBody = (isUnimplemented || - (binding.needsNIOWrappingOrUnwrapping() || - binding.signatureUsesJavaPrimitiveArrays()) || - (prologue != null) || - (epilogue != null)); - - JavaMethodBindingEmitter emitter = - new JavaMethodBindingEmitter(binding, - writer, - cfg.runtimeExceptionType(), - cfg.unsupportedExceptionType(), - !signatureOnly && needsBody, - cfg.tagNativeBinding(), - false, - cfg.nioDirectOnly(binding.getName()), - false, - false, - false, - isUnimplemented, - signatureOnly, - cfg); - switch (accessControl) { - case PUBLIC: emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); break; - case PROTECTED: emitter.addModifier(JavaMethodBindingEmitter.PROTECTED); break; - case PRIVATE: emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); break; - default: break; // package-private adds no modifiers - } - if (cfg.allStatic()) { - emitter.addModifier(JavaMethodBindingEmitter.STATIC); - } - if (!isUnimplemented && !needsBody && !signatureOnly) { - emitter.addModifier(JavaMethodBindingEmitter.NATIVE); - } - emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); - emitter.setPrologue(prologue); - emitter.setEpilogue(epilogue); - 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<FunctionEmitter> allEmitters) { - if (cfg.manuallyImplement(binding.getName())) { - // Don't produce emitters for the implementation class - return; - } - - boolean hasPrologueOrEpilogue = - ((cfg.javaPrologueForMethod(binding, false, false) != null) || - (cfg.javaEpilogueForMethod(binding, false, false) != null)); - - // 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() || - hasPrologueOrEpilogue)) { - 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(), - cfg.unsupportedExceptionType(), - false, - cfg.tagNativeBinding(), - true, - cfg.nioDirectOnly(binding.getName()), - true, - true, - false, - false, - false, - cfg); - 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()) { - CMethodBindingEmitter cEmitter; - // Generate a binding without mixed access (NIO-direct, -indirect, array) - 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() || hasPrologueOrEpilogue), - !cfg.nioDirectOnly(binding.getName()), - machDesc64); - prepCEmitter(binding, cEmitter); - allEmitters.add(cEmitter); - } - } - - protected void prepCEmitter(MethodBinding binding, CMethodBindingEmitter cEmitter) - { - // See whether we need an expression to help calculate the - // length of any return type - JavaType javaReturnType = binding.getJavaReturnType(); - if (javaReturnType.isNIOBuffer() || - javaReturnType.isCompoundTypeWrapper()) { - // See whether capacity has been specified - String capacity = cfg.returnValueCapacity(binding.getName()); - if (capacity != null) { - cEmitter.setReturnValueCapacityExpression( 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) { - cEmitter.setReturnValueLengthExpression( new MessageFormat(len) ); - } - } - cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName())); - cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName())); - } - - /** - * Generate all appropriate Java bindings for the specified C function - * symbols. - */ - protected List<? extends FunctionEmitter> generateMethodBindingEmitters(Set<MethodBinding> methodBindingSet, FunctionSymbol sym) throws Exception { - - ArrayList<FunctionEmitter> allEmitters = new ArrayList<FunctionEmitter>(); - - try { - // Get Java binding for the function - MethodBinding mb = bindFunction(sym, null, null, machDesc64); - - // JavaTypes representing C pointers in the initial - // MethodBinding have not been lowered yet to concrete types - List<MethodBinding> bindings = expandMethodBinding(mb); - - for (MethodBinding binding : bindings) { - - if(!methodBindingSet.add(binding)) { - // skip .. already exisiting binding .. - continue; - } - - 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 + "\""); - } - - // 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. ... - // - // boolean arg_direct = arg != null && Buffers.isDirect(arg); - // - // fooMethod0(arg_direct?arg:Buffers.getArray(arg), - // arg_direct?Buffers.getDirectBufferByteOffset(arg):Buffers.getIndirectBufferByteOffset(arg), - // arg_direct, - // ... ); - // } - // private native void fooMethod1(Object arg, int arg_byte_offset, boolean arg_is_direct, ...); - // - // 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. ... - // - // boolean arg_direct = BufferFactory.isDirect(arg); - // - // fooMethod1(arg_direct?arg:BufferFactory.getArray(arg), - // arg_direct?BufferFactory.getDirectBufferByteOffset(arg):BufferFactory.getIndirectBufferByteOffset(arg), - // arg_direct, - // ... ); - // } - // private native void fooMethod1(Object arg, int arg_byte_offset, boolean arg_is_direct, ...); - // - // Note in particular that the public entry point taking an - // array is merely a special case of the indirect buffer case. - - if (cfg.emitInterface()) { - generatePublicEmitters(binding, allEmitters, true); - } - if (cfg.emitImpl()) { - generatePublicEmitters(binding, allEmitters, false); - generatePrivateEmitters(binding, allEmitters); - } - } // end iteration over expanded bindings - } catch (Exception e) { - throw new RuntimeException("Error while generating bindings for \"" + sym + "\"", e); - } - - return allEmitters; - } - - - public void endFunctions() throws Exception { - if (!cfg.structsOnly()) { - if (cfg.allStatic() || cfg.emitInterface()) { - emitCustomJavaCode(javaWriter(), cfg.className()); - } - if (!cfg.allStatic() && cfg.emitImpl()) { - emitCustomJavaCode(javaImplWriter(), cfg.implClassName()); - } - } - } - - public void beginStructLayout() throws Exception {} - public void layoutStruct(CompoundType t) throws Exception { - getLayout().layout(t); - } - public void endStructLayout() throws Exception {} - - public void beginStructs(TypeDictionary typedefDictionary, - TypeDictionary structDictionary, - Map<Type, Type> canonMap) throws Exception { - this.typedefDictionary = typedefDictionary; - this.structDictionary = structDictionary; - this.canonMap = canonMap; - } - - public void emitStruct(CompoundType structType, String alternateName) throws Exception { - // Emit abstract base class delegating to 32-bit or 64-bit implementations - emitStructImpl(structType, alternateName, machDesc32, machDesc64, true, false); - // Emit concrete implementing class for each variant - emitStructImpl(structType, alternateName, machDesc32, machDesc64, false, true); - emitStructImpl(structType, alternateName, machDesc32, machDesc64, false, false); - } - - public void emitStructImpl(CompoundType structType, - String alternateName, - MachineDescription md32, - MachineDescription md64, - boolean doBaseClass, - boolean do32Bit) throws Exception { - String name = structType.getName(); - if (name == null && alternateName != null) { - name = alternateName; - } - - if (name == null) { - LOG.log(WARNING, "skipping emission of unnamed struct \"{0}\"", structType); - return; - } - - if (cfg.shouldIgnoreInInterface(name)) { - return; - } - - Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structType, 0)); - JavaType containingType = typeToJavaType(containingCType, false, null); - if (!containingType.isCompoundTypeWrapper()) { - return; - } - String containingTypeName = containingType.getName(); - - if ((md32 == null) || (md64 == null)) { - throw new RuntimeException("Must supply both 32- and 64-bit MachineDescriptions to emitStructImpl"); - } - String suffix = ""; - - // The "external" MachineDescription is the one used to determine - // the sizes of the primitive types seen in the public API. For - // example, if a C long is an element of a struct, it is the size - // of a Java int on a 32-bit machine but the size of a Java long - // on a 64-bit machine. To support both of these sizes with the - // same API, the abstract base class must take and return a Java - // long from the setter and getter for this field. However the - // implementation on a 32-bit platform must downcast this to an - // int and set only an int's worth of data in the struct. The - // "internal" MachineDescription is the one used to determine how - // much data to set in or get from the struct and exactly from - // where it comes. - // - // Note that the 64-bit MachineDescription is always used as the - // external MachineDescription. - - MachineDescription extMachDesc = md64; - MachineDescription intMachDesc = null; - - if (!doBaseClass) { - if (do32Bit) { - intMachDesc = md32; - suffix = "32"; - } else { - intMachDesc = md64; - suffix = "64"; - } - } - - boolean needsNativeCode = false; - // Native code for calls through function pointers gets emitted - // into the abstract base class; Java code which accesses fields - // gets emitted into the concrete classes - if (doBaseClass) { - for (int i = 0; i < structType.getNumFields(); i++) { - if (structType.getField(i).getType().isFunctionPointer()) { - needsNativeCode = true; - break; - } - } - } - - String structClassPkg = cfg.packageForStruct(name); - PrintWriter writer = null; - PrintWriter newWriter = null; - try { - writer = openFile( - cfg.javaOutputDir() + File.separator + - CodeGenUtils.packageAsPath(structClassPkg) + - File.separator + containingTypeName + suffix + ".java"); - CodeGenUtils.emitAutogeneratedWarning(writer, this); - if (needsNativeCode) { - String nRoot = cfg.nativeOutputDir(); - if (cfg.nativeOutputUsesJavaHierarchy()) { - nRoot += File.separator + CodeGenUtils.packageAsPath(cfg.packageName()); - } - newWriter = openFile(nRoot + File.separator + containingTypeName + "_JNI.c"); - CodeGenUtils.emitAutogeneratedWarning(newWriter, this); - emitCHeader(newWriter, containingTypeName); - } - } catch(Exception e) { - throw new RuntimeException("Unable to open files for emission of struct class", e); - } - - writer.println(); - writer.println("package " + structClassPkg + ";"); - writer.println(); - writer.println("import java.nio.*;"); - writer.println(); - - writer.println("import " + cfg.gluegenRuntimePackage() + ".*;"); - writer.println("import " + DynamicLookupHelper.class.getPackage().getName() + ".*;"); - writer.println("import " + Buffers.class.getPackage().getName() + ".*;"); - writer.println(); - List<String> imports = cfg.imports(); - for (String str : imports) { - writer.print("import "); - writer.print(str); - writer.println(";"); - } - writer.println(); - List<String> javadoc = cfg.javadocForClass(containingTypeName); - for (String doc : javadoc) { - writer.println(doc); - } - writer.print((doBaseClass ? "public " : "") + (doBaseClass ? "abstract " : "") + "class " + containingTypeName + suffix + " "); - if (!doBaseClass) { - writer.print("extends " + containingTypeName + " "); - } - boolean firstIteration = true; - List<String> userSpecifiedInterfaces = cfg.implementedInterfaces(containingTypeName); - for (String userInterface : userSpecifiedInterfaces) { - if (firstIteration) { - writer.print("implements "); - } - firstIteration = false; - writer.print(userInterface); - writer.print(" "); - } - writer.println("{"); - writer.println(); - if (doBaseClass) { - writer.println(" StructAccessor accessor;"); - writer.println(); - } - - writer.println(" public static int size() {"); - if (doBaseClass) { - writer.println(" if (Platform.is32Bit()) {"); - writer.println(" return " + containingTypeName + "32" + ".size();"); - writer.println(" } else {"); - writer.println(" return " + containingTypeName + "64" + ".size();"); - writer.println(" }"); - } else { - writer.println(" return " + structType.getSize(intMachDesc) + ";"); - } - writer.println(" }"); - writer.println(); - if (doBaseClass) { - writer.println(" public static " + containingTypeName + " create() {"); - writer.println(" return create(Buffers.newDirectByteBuffer(size()));"); - writer.println(" }"); - writer.println(); - writer.println(" public static " + containingTypeName + " create(java.nio.ByteBuffer buf) {"); - writer.println(" if (Platform.is32Bit()) {"); - writer.println(" return new " + containingTypeName + "32(buf);"); - writer.println(" } else {"); - writer.println(" return new " + containingTypeName + "64(buf);"); - writer.println(" }"); - writer.println(" }"); - writer.println(); - writer.println(" " + containingTypeName + "(java.nio.ByteBuffer buf) {"); - writer.println(" accessor = new StructAccessor(buf);"); - writer.println(" }"); - writer.println(); - writer.println(" public java.nio.ByteBuffer getBuffer() {"); - writer.println(" return accessor.getBuffer();"); - writer.println(" }"); - } else { - writer.println(" " + containingTypeName + suffix + "(java.nio.ByteBuffer buf) {"); - writer.println(" super(buf);"); - writer.println(" }"); - writer.println(); - } - for (int i = 0; i < structType.getNumFields(); i++) { - - Field field = structType.getField(i); - Type fieldType = field.getType(); - - if (!cfg.shouldIgnoreInInterface(name + " " + field.getName())) { - - String renamed = cfg.getJavaSymbolRename(field.getName()); - String fieldName = renamed==null ? field.getName() : renamed; - - if (fieldType.isFunctionPointer()) { - - if (doBaseClass) { - try { - // Emit method call and associated native code - FunctionType funcType = fieldType.asPointer().getTargetType().asFunction(); - FunctionSymbol funcSym = new FunctionSymbol(fieldName, funcType); - MethodBinding binding = bindFunction(funcSym, containingType, containingCType, machDesc64); - binding.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis - writer.println(); - - // Emit public Java entry point for calling this function pointer - JavaMethodBindingEmitter emitter = - new JavaMethodBindingEmitter(binding, - writer, - cfg.runtimeExceptionType(), - cfg.unsupportedExceptionType(), - true, - cfg.tagNativeBinding(), - 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, // FIXME: should unify this with the general emission code - false, - cfg); - emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); - emitter.emit(); - - // Emit private native Java entry point for calling this function pointer - emitter = - new JavaMethodBindingEmitter(binding, - writer, - cfg.runtimeExceptionType(), - cfg.unsupportedExceptionType(), - false, - cfg.tagNativeBinding(), - 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, // FIXME: should unify this with the general emission code - false, - cfg); - emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); - emitter.addModifier(JavaMethodBindingEmitter.NATIVE); - emitter.emit(); - - // Emit (private) C entry point for calling this function pointer - CMethodBindingEmitter cEmitter = - new CMethodBindingEmitter(binding, - newWriter, - structClassPkg, - containingTypeName, - true, // FIXME: this is optional at this point - false, - true, - false, // FIXME: should unify this with the general emission code - machDesc64); - prepCEmitter(binding, cEmitter); - cEmitter.emit(); - } catch (Exception e) { - System.err.println("While processing field " + field + " of type " + name + ":"); - throw(e); - } - } - } else if (fieldType.isCompound()) { - // FIXME: will need to support this at least in order to - // handle the union in jawt_Win32DrawingSurfaceInfo (fabricate - // a name?) - if (fieldType.getName() == null) { - throw new RuntimeException("Anonymous structs as fields not supported yet (field \"" + - field + "\" in type \"" + name + "\")"); - } - - writer.println(); - generateGetterSignature(writer, doBaseClass, fieldType.getName(), capitalizeString(fieldName)); - if (doBaseClass) { - writer.println(";"); - } else { - writer.println(" {"); - writer.println(" return " + fieldType.getName() + ".create(accessor.slice(" + - field.getOffset(intMachDesc) + ", " + fieldType.getSize(intMachDesc) + "));"); - writer.println(" }"); - } - - } else if (fieldType.isArray()) { - - Type baseElementType = field.getType().asArray().getBaseElementType(); - - if(!baseElementType.isPrimitive()) - break; - - String paramType = typeToJavaType(baseElementType, false, extMachDesc).getName(); - String capitalized = capitalizeString(fieldName); - - int slot = -1; - if(!doBaseClass) { - slot = slot(fieldType, (int) field.getOffset(intMachDesc), intMachDesc); - } - - // Setter - writer.println(); - generateSetterSignature(writer, doBaseClass, containingTypeName, capitalized, paramType+"[]"); - if (doBaseClass) { - writer.println(";"); - } else { - writer.println(" {"); - writer.print (" accessor.set" + capitalizeString(paramType) + "sAt(" + slot + ", "); - writer.println("val);"); - writer.println(" return this;"); - writer.println(" }"); - } - writer.println(); - // Getter - generateGetterSignature(writer, doBaseClass, paramType+"[]", capitalized); - if (doBaseClass) { - writer.println(";"); - } else { - writer.println(" {"); - writer.print (" return "); - writer.println("accessor.get" + capitalizeString(paramType) + "sAt(" + slot + ", new " +paramType+"["+fieldType.asArray().getLength()+"]);"); - writer.println(" }"); - } - - } else { - JavaType internalJavaType = null; - JavaType externalJavaType = null; - - try { - externalJavaType = typeToJavaType(fieldType, false, extMachDesc); - if (!doBaseClass) { - internalJavaType = typeToJavaType(fieldType, false, intMachDesc); - } - } catch (Exception e) { - System.err.println("Error occurred while creating accessor for field \"" + - field.getName() + "\" in type \"" + name + "\""); - throw(e); - } - if (externalJavaType.isPrimitive()) { - // Primitive type - String externalJavaTypeName = null; - String internalJavaTypeName = null; - externalJavaTypeName = externalJavaType.getName(); - if (!doBaseClass) { - internalJavaTypeName = internalJavaType.getName(); - } - if (isOpaque(fieldType)) { - externalJavaTypeName = compatiblePrimitiveJavaTypeName(fieldType, externalJavaType, extMachDesc); - if (!doBaseClass) { - internalJavaTypeName = compatiblePrimitiveJavaTypeName(fieldType, internalJavaType, intMachDesc); - } - } - String capitalized = null; - if (!doBaseClass) { - capitalized = capitalizeString(internalJavaTypeName); - } - int slot = -1; - if (!doBaseClass) { - slot = slot(fieldType, (int) field.getOffset(intMachDesc), intMachDesc); - } - writer.println(); - String capitalizedFieldName = capitalizeString(fieldName); - // Setter - generateSetterSignature(writer, doBaseClass, containingTypeName, capitalizedFieldName, externalJavaTypeName); - if (doBaseClass) { - writer.println(";"); - } else { - writer.println(" {"); - writer.print (" accessor.set" + capitalized + "At(" + slot + ", "); - if (!externalJavaTypeName.equals(internalJavaTypeName)) { - writer.print("(" + internalJavaTypeName + ") "); - } - writer.println("val);"); - writer.println(" return this;"); - writer.println(" }"); - } - writer.println(); - // Getter - generateGetterSignature(writer, doBaseClass, externalJavaTypeName, capitalizedFieldName); - if (doBaseClass) { - writer.println(";"); - } else { - writer.println(" {"); - writer.print (" return "); - if (!externalJavaTypeName.equals(internalJavaTypeName)) { - writer.print("(" + externalJavaTypeName + ") "); - } - writer.println("accessor.get" + capitalized + "At(" + slot + ");"); - writer.println(" }"); - } - } else { - // FIXME - LOG.log(WARNING, "Complicated fields (field \"{0}\" of type \"{1}\") not implemented yet", new Object[]{field, name}); - // throw new RuntimeException("Complicated fields (field \"" + field + "\" of type \"" + t + - // "\") not implemented yet"); - } - } - } - } - if (doBaseClass) { - emitCustomJavaCode(writer, containingTypeName); - } - writer.println("}"); - writer.flush(); - writer.close(); - if (needsNativeCode) { - newWriter.flush(); - newWriter.close(); - } - } - public void endStructs() throws Exception {} - - public static int addStrings2Buffer(StringBuilder buf, String sep, String first, Collection<String> col) { - int num = 0; - if(null==buf) { - buf = new StringBuilder(); - } - - Iterator<String> iter = col.iterator(); - if(null!=first) { - buf.append(first); - if( iter.hasNext() ) { - buf.append(sep); - } - num++; - } - while( iter.hasNext() ) { - buf.append(iter.next()); - if( iter.hasNext() ) { - buf.append(sep); - } - num++; - } - return num; - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private void generateGetterSignature(PrintWriter writer, boolean baseClass, String returnTypeName, String capitalizedFieldName) { - writer.print(" public " + (baseClass ? "abstract " : "") + returnTypeName + " get" + capitalizedFieldName + "()"); - } - - private void generateSetterSignature(PrintWriter writer, boolean baseClass, String returnTypeName, String capitalizedFieldName, String paramTypeName) { - writer.print(" public " + (baseClass ? "abstract " : "") + returnTypeName + " set" + capitalizedFieldName + "(" + paramTypeName + " val)"); - } - - private JavaType typeToJavaType(Type cType, boolean outgoingArgument, MachineDescription curMachDesc) { - // Recognize JNIEnv* case up front - PointerType opt = cType.asPointer(); - if ((opt != null) && - (opt.getTargetType().getName() != null) && - (opt.getTargetType().getName().equals("JNIEnv"))) { - return JavaType.createForJNIEnv(); - } - Type t = cType; - - // Opaque specifications override automatic conversions - // in case the identity is being used .. not if ptr-ptr - TypeInfo info = cfg.typeInfo(t, typedefDictionary); - if (info != null) { - boolean isPointerPointer = false; - if (t.pointerDepth() > 0 || t.arrayDimension() > 0) { - Type targetType; // target type - if (t.isPointer()) { - // t is <type>*, we need to get <type> - targetType = t.asPointer().getTargetType(); - } else { - // t is <type>[], we need to get <type> - targetType = t.asArray().getElementType(); - } - if (t.pointerDepth() == 2 || t.arrayDimension() == 2) { - // Get the target type of the target type (targetType was computer earlier - // as to be a pointer to the target type, so now we need to get its - // target type) - if (targetType.isPointer()) { - isPointerPointer = true; - - // t is<type>**, targetType is <type>*, we need to get <type> - Type bottomType = targetType.asPointer().getTargetType(); - LOG.log(INFO, "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr", new Object[]{t, targetType, bottomType}); - } - } - } - if(!isPointerPointer) { - return info.javaType(); - } - } - - if (t.isInt() || t.isEnum()) { - switch ((int) t.getSize(curMachDesc)) { - case 1: return javaType(Byte.TYPE); - case 2: return javaType(Short.TYPE); - case 4: return javaType(Integer.TYPE); - case 8: return javaType(Long.TYPE); - default: throw new RuntimeException("Unknown integer type of size " + - t.getSize(curMachDesc) + " and name " + t.getName()); - } - } else if (t.isFloat()) { - return javaType(Float.TYPE); - } else if (t.isDouble()) { - return javaType(Double.TYPE); - } else if (t.isVoid()) { - return javaType(Void.TYPE); - } else { - if (t.pointerDepth() > 0 || t.arrayDimension() > 0) { - Type targetType; // target type - if (t.isPointer()) { - // t is <type>*, we need to get <type> - targetType = t.asPointer().getTargetType(); - } else { - // t is <type>[], we need to get <type> - targetType = t.asArray().getElementType(); - } - - // Handle Types of form pointer-to-type or array-of-type, like - // char* or int[]; these are expanded out into Java primitive - // arrays, NIO buffers, or both in expandMethodBinding - if (t.pointerDepth() == 1 || t.arrayDimension() == 1) { - if (targetType.isVoid()) { - return JavaType.createForVoidPointer(); - } else if (targetType.isInt()) { - // size_t and intptr_t is always a PointerBuffer since size is arch dependent - if ("size_t".equals(targetType.getName()) || "intptr_t".equals(targetType.getName())) { - return JavaType.forNIOPointerBufferClass(); - } - switch ((int) targetType.getSize(curMachDesc)) { - case 1: return JavaType.createForCCharPointer(); - case 2: return JavaType.createForCShortPointer(); - case 4: return JavaType.createForCInt32Pointer(); - case 8: return JavaType.createForCInt64Pointer(); - default: throw new RuntimeException("Unknown integer array type of size " + - t.getSize(curMachDesc) + " and name " + t.getName()); - } - } else if (targetType.isFloat()) { - return JavaType.createForCFloatPointer(); - } else if (targetType.isDouble()) { - return JavaType.createForCDoublePointer(); - } else if (targetType.isCompound()) { - if (t.isArray()) { - throw new RuntimeException("Arrays of compound types not handled yet"); - } - // Special cases for known JNI types (in particular for converting jawt.h) - if (t.getName() != null && - t.getName().equals("jobject")) { - return javaType(java.lang.Object.class); - } - - String name = targetType.getName(); - if (name == null) { - // Try containing pointer type for any typedefs - name = t.getName(); - if (name == null) { - throw new RuntimeException("Couldn't find a proper type name for pointer type " + t); - } - } - - return JavaType.createForCStruct(cfg.renameJavaType(name)); - } else { - throw new RuntimeException("Don't know how to convert pointer/array type \"" + - t + "\""); - } - } - // Handle Types of form pointer-to-pointer-to-type or - // array-of-arrays-of-type, like char** or int[][] - else if (t.pointerDepth() == 2 || t.arrayDimension() == 2) { - // Get the target type of the target type (targetType was computer earlier - // as to be a pointer to the target type, so now we need to get its - // target type) - Type bottomType; - if (targetType.isPointer()) { - // t is<type>**, targetType is <type>*, we need to get <type> - bottomType = targetType.asPointer().getTargetType(); - return JavaType.forNIOPointerBufferClass(); - } else { - // t is<type>[][], targetType is <type>[], we need to get <type> - bottomType = targetType.asArray().getElementType(); - LOG.log(WARNING, "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2} -> Unhandled!", new Object[]{t, targetType, bottomType}); - } - - // Warning: The below code is not backed up by an implementation, - // the only working variant is a ptr-ptr type which results in a PointerBuffer. - // - if (bottomType.isPrimitive()) { - if (bottomType.isInt()) { - switch ((int) bottomType.getSize(curMachDesc)) { - case 1: return javaType(ArrayTypes.byteBufferArrayClass); - case 2: return javaType(ArrayTypes.shortBufferArrayClass); - case 4: return javaType(ArrayTypes.intBufferArrayClass); - case 8: return javaType(ArrayTypes.longBufferArrayClass); - default: throw new RuntimeException("Unknown two-dimensional integer array type of element size " + - bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()); - } - } else if (bottomType.isFloat()) { - return javaType(ArrayTypes.floatBufferArrayClass); - } else if (bottomType.isDouble()) { - return javaType(ArrayTypes.doubleBufferArrayClass); - } else { - throw new RuntimeException("Unexpected primitive type " + bottomType.getName() + - " in two-dimensional array"); - } - } else if (bottomType.isVoid()) { - return javaType(ArrayTypes.bufferArrayClass); - } else if (targetType.isPointer() && (targetType.pointerDepth() == 1) && - targetType.asPointer().getTargetType().isCompound()) { - // Array of pointers; convert as array of StructAccessors - return JavaType.createForCArray(bottomType); - } else { - throw new RuntimeException( - "Could not convert C type \"" + t + "\" " + - "to appropriate Java type; need to add more support for " + - "depth=2 pointer/array types [debug info: targetType=\"" + - targetType + "\"]"); - } - } else { - // can't handle this type of pointer/array argument - throw new RuntimeException( - "Could not convert C pointer/array \"" + t + "\" to " + - "appropriate Java type; types with pointer/array depth " + - "greater than 2 are not yet supported [debug info: " + - "pointerDepth=" + t.pointerDepth() + " arrayDimension=" + - t.arrayDimension() + " targetType=\"" + targetType + "\"]"); - } - - } else { - throw new RuntimeException( - "Could not convert C type \"" + t + "\" (class " + - t.getClass().getName() + ") to appropriate Java type"); - } - } - } - - private static boolean isIntegerType(Class<?> c) { - return ((c == Byte.TYPE) || - (c == Short.TYPE) || - (c == Character.TYPE) || - (c == Integer.TYPE) || - (c == Long.TYPE)); - } - - private int slot(Type t, int byteOffset, MachineDescription curMachDesc) { - if (t.isInt()) { - switch ((int) t.getSize(curMachDesc)) { - case 1: - case 2: - case 4: - case 8: return byteOffset / (int) t.getSize(curMachDesc); - default: throw new RuntimeException("Illegal type"); - } - } else if (t.isFloat()) { - return byteOffset / 4; - } else if (t.isDouble()) { - return byteOffset / 8; - } else if (t.isPointer()) { - return byteOffset / curMachDesc.pointerSizeInBytes(); - } else if (t.isArray()) { - return slot(t.asArray().getBaseElementType(), byteOffset, curMachDesc); - } else { - throw new RuntimeException("Illegal type " + t); - } - } - - private StructLayout getLayout() { - if (layout == null) { - layout = StructLayout.createForCurrentPlatform(); - } - return layout; - } - - protected PrintWriter openFile(String filename) throws IOException { - //System.out.println("Trying to open: " + filename); - File file = new File(filename); - String parentDir = file.getParent(); - if (parentDir != null) - { - File pDirFile = new File(parentDir); - pDirFile.mkdirs(); - } - return new PrintWriter(new BufferedWriter(new FileWriter(file))); - } - - private boolean isOpaque(Type type) { - return (cfg.typeInfo(type, typedefDictionary) != null); - } - - private String compatiblePrimitiveJavaTypeName(Type fieldType, - JavaType javaType, - MachineDescription curMachDesc) { - Class<?> c = javaType.getJavaClass(); - if (!isIntegerType(c)) { - // FIXME - throw new RuntimeException("Can't yet handle opaque definitions of structs' fields to non-integer types (byte, short, int, long, etc.)"); - } - switch ((int) fieldType.getSize(curMachDesc)) { - case 1: return "byte"; - case 2: return "short"; - case 4: return "int"; - case 8: return "long"; - default: throw new RuntimeException("Can't handle opaque definitions if the starting type isn't compatible with integral types"); - } - } - - private void openWriters() throws IOException { - String jRoot = null; - if (cfg.allStatic() || cfg.emitInterface()) { - jRoot = cfg.javaOutputDir() + File.separator + - CodeGenUtils.packageAsPath(cfg.packageName()); - } - String jImplRoot = null; - if (!cfg.allStatic()) { - jImplRoot = - cfg.javaOutputDir() + File.separator + - CodeGenUtils.packageAsPath(cfg.implPackageName()); - } - String nRoot = cfg.nativeOutputDir(); - if (cfg.nativeOutputUsesJavaHierarchy()) - { - nRoot += - File.separator + CodeGenUtils.packageAsPath(cfg.packageName()); - } - - if (cfg.allStatic() || cfg.emitInterface()) { - javaWriter = openFile(jRoot + File.separator + cfg.className() + ".java"); - } - if (!cfg.allStatic() && cfg.emitImpl()) { - javaImplWriter = openFile(jImplRoot + File.separator + cfg.implClassName() + ".java"); - } - if (cfg.emitImpl()) { - cWriter = openFile(nRoot + File.separator + cfg.implClassName() + "_JNI.c"); - } - - if (javaWriter != null) { - CodeGenUtils.emitAutogeneratedWarning(javaWriter, this); - } - if (javaImplWriter != null) { - CodeGenUtils.emitAutogeneratedWarning(javaImplWriter, this); - } - if (cWriter != null) { - CodeGenUtils.emitAutogeneratedWarning(cWriter, this); - } - } - - protected PrintWriter javaWriter() { - if (!cfg.allStatic() && !cfg.emitInterface()) { - throw new InternalError("Should not call this"); - } - return javaWriter; - } - - protected PrintWriter javaImplWriter() { - if (cfg.allStatic() || !cfg.emitImpl()) { - throw new InternalError("Should not call this"); - } - return javaImplWriter; - } - - protected PrintWriter cWriter() { - if (!cfg.emitImpl()) { - throw new InternalError("Should not call this"); - } - return cWriter; - } - - private void closeWriter(PrintWriter writer) throws IOException { - writer.flush(); - writer.close(); - } - - private void closeWriters() throws IOException { - if (javaWriter != null) { - closeWriter(javaWriter); - } - if (javaImplWriter != null) { - closeWriter(javaImplWriter); - } - if (cWriter != null) { - closeWriter(cWriter); - } - javaWriter = null; - javaImplWriter = null; - cWriter = null; - } - - /** - * Returns the value that was specified by the configuration directive - * "JavaOutputDir", or the default if none was specified. - */ - protected String getJavaOutputDir() { - return cfg.javaOutputDir(); - } - - /** - * Returns the value that was specified by the configuration directive - * "Package", or the default if none was specified. - */ - protected String getJavaPackageName() { - return cfg.packageName(); - } - - /** - * Returns the value that was specified by the configuration directive - * "ImplPackage", or the default if none was specified. - */ - protected String getImplPackageName() { - return cfg.implPackageName(); - } - - /** - * Emit all the strings specified in the "CustomJavaCode" parameters of - * the configuration file. - */ - protected void emitCustomJavaCode(PrintWriter writer, String className) throws Exception { - List<String> code = cfg.customJavaCodeForClass(className); - if (code.isEmpty()) - return; - - writer.println(); - writer.println(" // --- Begin CustomJavaCode .cfg declarations"); - for (String line : code) { - writer.println(line); - } - writer.println(" // ---- End CustomJavaCode .cfg declarations"); - } - - /** - * Write out any header information for the output files (class declaration - * and opening brace, import statements, etc). - */ - protected void emitAllFileHeaders() throws IOException { - try { - List<String> imports = new ArrayList<String>(cfg.imports()); - imports.add(cfg.gluegenRuntimePackage()+".*"); - imports.add(DynamicLookupHelper.class.getPackage().getName()+".*"); - imports.add(Buffers.class.getPackage().getName()+".*"); - imports.add(Buffer.class.getPackage().getName()+".*"); - - if (cfg.allStatic() || cfg.emitInterface()) { - - String[] interfaces; - List<String> userSpecifiedInterfaces = null; - if (cfg.emitInterface()) { - userSpecifiedInterfaces = cfg.extendedInterfaces(cfg.className()); - } else { - userSpecifiedInterfaces = cfg.implementedInterfaces(cfg.className()); - } - interfaces = new String[userSpecifiedInterfaces.size()]; - userSpecifiedInterfaces.toArray(interfaces); - - final List<String> intfDocs = cfg.javadocForClass(cfg.className()); - CodeGenUtils.EmissionCallback docEmitter = - new CodeGenUtils.EmissionCallback() { - public void emit(PrintWriter w) { - for (Iterator iter = intfDocs.iterator(); iter.hasNext(); ) { - w.println((String) iter.next()); - } - } - }; - - String[] accessModifiers = null; - if(cfg.accessControl(cfg.className()) == PUBLIC_ABSTRACT) { - accessModifiers = new String[] { "public", "abstract" }; - } else { - accessModifiers = new String[] { "public" }; - } - - CodeGenUtils.emitJavaHeaders( - javaWriter, - cfg.packageName(), - cfg.className(), - cfg.allStatic() ? true : false, - imports, - accessModifiers, - interfaces, - cfg.extendedParentClass(cfg.className()), - docEmitter); - } - - if (!cfg.allStatic() && cfg.emitImpl()) { - final List<String> implDocs = cfg.javadocForClass(cfg.implClassName()); - CodeGenUtils.EmissionCallback docEmitter = - new CodeGenUtils.EmissionCallback() { - public void emit(PrintWriter w) { - for (Iterator iter = implDocs.iterator(); iter.hasNext(); ) { - w.println((String) iter.next()); - } - } - }; - - String[] interfaces; - List<String> userSpecifiedInterfaces = null; - userSpecifiedInterfaces = cfg.implementedInterfaces(cfg.implClassName()); - int additionalNum = 0; - if (cfg.className() != null) { - additionalNum = 1; - } - interfaces = new String[additionalNum + userSpecifiedInterfaces.size()]; - userSpecifiedInterfaces.toArray(interfaces); - if (additionalNum == 1) { - interfaces[userSpecifiedInterfaces.size()] = cfg.className(); - } - - String[] accessModifiers = null; - if(cfg.accessControl(cfg.implClassName()) == PUBLIC_ABSTRACT) { - accessModifiers = new String[] { "public", "abstract" }; - } else { - accessModifiers = new String[] { "public" }; - } - - CodeGenUtils.emitJavaHeaders( - javaImplWriter, - cfg.implPackageName(), - cfg.implClassName(), - true, - imports, - accessModifiers, - interfaces, - cfg.extendedParentClass(cfg.implClassName()), - docEmitter); - } - - if (cfg.emitImpl()) { - emitCHeader(cWriter(), cfg.implClassName()); - } - } catch (Exception e) { - throw new RuntimeException( - "Error emitting all file headers: cfg.allStatic()=" + cfg.allStatic() + - " cfg.emitImpl()=" + cfg.emitImpl() + " cfg.emitInterface()=" + cfg.emitInterface(), - e); - } - - } - - protected void emitCHeader(PrintWriter cWriter, String className) { - cWriter.println("#include <jni.h>"); - cWriter.println("#include <stdlib.h>"); - cWriter.println(); - - if (getConfig().emitImpl()) { - cWriter.println("#include <assert.h>"); - cWriter.println(); - } - - for (String code : cfg.customCCode()) { - cWriter.println(code); - } - cWriter.println(); - } - - /** - * Write out any footer information for the output files (closing brace of - * class definition, etc). - */ - protected void emitAllFileFooters(){ - if (cfg.allStatic() || cfg.emitInterface()) { - javaWriter().println(); - javaWriter().println("} // end of class " + cfg.className()); - } - if (!cfg.allStatic() && cfg.emitImpl()) { - javaImplWriter().println(); - javaImplWriter().println("} // end of class " + cfg.implClassName()); - } - } - - private JavaType javaType(Class<?> c) { - 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, - MachineDescription curMachDesc) { - - MethodBinding binding = new MethodBinding(sym, containingType, containingCType); - - binding.renameMethodName(cfg.getJavaSymbolRename(sym.getName())); - - // System.out.println("bindFunction(0) "+sym.getReturnType()); - - if (cfg.returnsString(binding.getName())) { - PointerType prt = sym.getReturnType().asPointer(); - if (prt == null || - prt.getTargetType().asInt() == null || - prt.getTargetType().getSize(curMachDesc) != 1) { - throw new RuntimeException( - "Cannot apply ReturnsString configuration directive to \"" + sym + - "\". ReturnsString requires native method to have return type \"char *\""); - } - binding.setJavaReturnType(javaType(java.lang.String.class)); - } else { - binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), false, curMachDesc)); - } - - // System.out.println("bindFunction(1) "+binding.getJavaReturnType()); - - // List of the indices of the arguments in this function that should be - // converted from byte[] or short[] to String - List<Integer> stringArgIndices = cfg.stringArguments(binding.getName()); - - for (int i = 0; i < sym.getNumArguments(); i++) { - Type cArgType = sym.getArgumentType(i); - JavaType mappedType = typeToJavaType(cArgType, true, curMachDesc); - // System.out.println("C arg type -> \"" + cArgType + "\"" ); - // System.out.println(" Java -> \"" + mappedType + "\"" ); - - // Take into account any ArgumentIsString configuration directives that apply - if (stringArgIndices != null && stringArgIndices.contains(i)) { - // System.out.println("Forcing conversion of " + binding.getName() + " arg #" + i + " from byte[] to String "); - if (mappedType.isCVoidPointerType() || - mappedType.isCCharPointerType() || - mappedType.isCShortPointerType() || - mappedType.isNIOPointerBuffer() || - (mappedType.isArray() && - (mappedType.getJavaClass() == ArrayTypes.byteBufferArrayClass) || - (mappedType.getJavaClass() == ArrayTypes.shortBufferArrayClass))) { - // convert mapped type from: - // void*, byte[], and short[] to String - // ByteBuffer[] and ShortBuffer[] to String[] - if (mappedType.isArray() || mappedType.isNIOPointerBuffer()) { - mappedType = javaType(ArrayTypes.stringArrayClass); - } else { - mappedType = javaType(String.class); - } - } - else { - throw new RuntimeException( - "Cannot apply ArgumentIsString configuration directive to " + - "argument " + i + " of \"" + sym + "\": argument type is not " + - "a \"void*\", \"char *\", \"short *\", \"char**\", or \"short**\" equivalent"); - } - } - binding.addJavaArgumentType(mappedType); - //System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType); - } - - // System.out.println("---> " + binding); - // System.out.println(" ---> " + binding.getCSymbol()); - // System.out.println("bindFunction(3) "+binding); - return binding; - } - - private MethodBinding lowerMethodBindingPointerTypes(MethodBinding inputBinding, - boolean convertToArrays, - boolean[] canProduceArrayVariant) { - MethodBinding result = inputBinding; - boolean arrayPossible = false; - - // System.out.println("lowerMethodBindingPointerTypes(0): "+result); - - 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()); - } - } else if (t.isCShortPointerType()) { - arrayPossible = true; - if (convertToArrays) { - result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.shortArrayClass)); - } else { - result = result.replaceJavaArgumentType(i, JavaType.forNIOShortBufferClass()); - } - } 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.forNIOInt64BufferClass()); - } - } 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); - } - } - } - - // System.out.println("lowerMethodBindingPointerTypes(1): "+result); - - // 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.forNIOInt64BufferClass()); - } 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); - } - } - - // System.out.println("lowerMethodBindingPointerTypes(2): "+result); - - if (canProduceArrayVariant != null) { - canProduceArrayVariant[0] = arrayPossible; - } - - 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 - protected List<MethodBinding> expandMethodBinding(MethodBinding binding) { - - List<MethodBinding> result = new ArrayList<MethodBinding>(); - // 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()) && !cfg.nioOnly(binding.getName())) { - result.add(lowerMethodBindingPointerTypes(binding, true, null)); - } - } else { - result.add(binding); - } - - return result; - } - - private String resultName() { - return "_res"; - } - - private Type canonicalize(Type t) { - Type res = canonMap.get(t); - if (res != null) { - return res; - } - canonMap.put(t, t); - return t; - } - - /** - * Converts first letter to upper case. - */ - private final String capitalizeString(String string) { - return Character.toUpperCase(string.charAt(0)) + string.substring(1); - } - -} |