/* * 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.jogamp.gluegen; import java.nio.*; import com.jogamp.gluegen.cgram.types.*; /** * Describes a java-side representation of a type that is used to represent * the same data on both the Java-side and C-side during a JNI operation. Also * contains some utility methods for creating common types. */ public class JavaType { /* * Represents C arrays that will / can be represented * with NIO buffers (resolved down to another JavaType later in processing) */ private enum C_PTR { VOID, CHAR, SHORT, INT32, INT64, FLOAT, DOUBLE; } private final Class<?> clazz; // Primitive types and other types representable as Class objects private final String structName; // Types we're generating glue code for (i.e., C structs) private final Type elementType; // Element type if this JavaType represents a C array private final C_PTR primitivePointerType; private final boolean opaqued; private static JavaType nioBufferType; private static JavaType nioByteBufferType; private static JavaType nioShortBufferType; private static JavaType nioIntBufferType; private static JavaType nioLongBufferType; private static JavaType nioPointerBufferType; private static JavaType nioFloatBufferType; private static JavaType nioDoubleBufferType; private static JavaType nioByteBufferArrayType; @Override public boolean equals(final Object arg) { if ((arg == null) || (!(arg instanceof JavaType))) { return false; } final JavaType t = (JavaType) arg; return (this == t || (t.clazz == clazz && ((structName == null ? t.structName == null : structName.equals(t.structName)) || ((structName != null) && (t.structName != null) && (structName.equals(t.structName)))) && ((elementType == t.elementType) || (elementType != null) && (t.elementType != null) && (elementType.equals(t.elementType))) && (primitivePointerType == t.primitivePointerType))); } @Override public int hashCode() { if (clazz == null) { if (structName == null) { return 0; } return structName.hashCode(); } return clazz.hashCode(); } public JavaType getElementType() { return new JavaType(elementType); } public Type getElementCType() { return elementType; } /** Creates a JavaType corresponding to the given opaque Java type. This can be used to represent arrays of primitive values or Strings; the emitters understand how to perform proper conversion from the corresponding C type. */ public static JavaType createForOpaqueClass(final Class<?> clazz) { return new JavaType(clazz, true); } /** Creates a JavaType corresponding to the given Java type. This can be used to represent arrays of primitive values or Strings; the emitters understand how to perform proper conversion from the corresponding C type. */ public static JavaType createForClass(final Class<?> clazz) { return new JavaType(clazz, false); } /** Creates a JavaType corresponding to the specified C CompoundType name; for example, if "Foo" is supplied, then this JavaType represents a "Foo *" by way of a StructAccessor. */ public static JavaType createForCStruct(final String name) { return new JavaType(name); } /** Creates a JavaType corresponding to an array of the given element type. This is used to represent arrays of "Foo **" which should be mapped to Foo[] in Java. */ public static JavaType createForCArray(final Type elementType) { return new JavaType(elementType); } public static JavaType createForCVoidPointer() { return new JavaType(C_PTR.VOID); } public static JavaType createForCCharPointer() { return new JavaType(C_PTR.CHAR); } public static JavaType createForCShortPointer() { return new JavaType(C_PTR.SHORT); } public static JavaType createForCInt32Pointer() { return new JavaType(C_PTR.INT32); } public static JavaType createForCInt64Pointer() { return new JavaType(C_PTR.INT64); } public static JavaType createForCFloatPointer() { return new JavaType(C_PTR.FLOAT); } public static JavaType createForCDoublePointer() { return new JavaType(C_PTR.DOUBLE); } public static JavaType createForJNIEnv() { return createForCStruct("JNIEnv"); } public static JavaType forNIOBufferClass() { if (nioBufferType == null) { nioBufferType = createForClass(java.nio.Buffer.class); } return nioBufferType; } public static JavaType forNIOByteBufferClass() { if (nioByteBufferType == null) { nioByteBufferType = createForClass(java.nio.ByteBuffer.class); } return nioByteBufferType; } public static JavaType forNIOShortBufferClass() { if (nioShortBufferType == null) { nioShortBufferType = createForClass(java.nio.ShortBuffer.class); } return nioShortBufferType; } public static JavaType forNIOIntBufferClass() { if (nioIntBufferType == null) { nioIntBufferType = createForClass(java.nio.IntBuffer.class); } return nioIntBufferType; } public static JavaType forNIOLongBufferClass() { if (nioLongBufferType == null) { nioLongBufferType = createForClass(java.nio.LongBuffer.class); } return nioLongBufferType; } public static JavaType forNIOPointerBufferClass() { if(nioPointerBufferType == null) nioPointerBufferType = createForClass(com.jogamp.common.nio.PointerBuffer.class); return nioPointerBufferType; } public static JavaType forNIOFloatBufferClass() { if (nioFloatBufferType == null) { nioFloatBufferType = createForClass(java.nio.FloatBuffer.class); } return nioFloatBufferType; } public static JavaType forNIODoubleBufferClass() { if (nioDoubleBufferType == null) { nioDoubleBufferType = createForClass(java.nio.DoubleBuffer.class); } return nioDoubleBufferType; } public static JavaType forNIOByteBufferArrayClass() { if (nioByteBufferArrayType == null) { final ByteBuffer[] tmp = new ByteBuffer[0]; nioByteBufferArrayType = createForClass(tmp.getClass()); } return nioByteBufferArrayType; } /** * Returns the Java Class corresponding to this type. Returns null if this * object corresponds to a C primitive array type. */ public Class<?> getJavaClass() { return clazz; } /** * Returns the Java type name corresponding to this type. */ public String getName() { if (clazz != null) { if (clazz.isArray()) { return arrayName(clazz); } return clazz.getName(); } if (elementType != null) { return elementType.getName(); } return structName; } /** * Returns the descriptor (internal type signature) corresponding to * this type. */ public String getDescriptor() { // FIXME: this is not completely accurate at this point (for // example, it knows nothing about the packages for compound // types) if (clazz != null) { return descriptor(clazz); } if (elementType != null) { if(elementType.getName()==null) { throw new RuntimeException("elementType.name is null: "+getDebugString()); } return "[" + descriptor(elementType.getName()); } if( null != structName ) { return descriptor(structName); } return "ANON_NIO"; } /** Returns the String corresponding to the JNI type for this type, or NULL if it can't be represented (i.e., it's a boxing class that we need to call getBuffer() on.) */ public String jniTypeName() { if (isCompoundTypeWrapper()) { // These are sent down as Buffers (e.g., jobject) return "jobject"; } if (isArrayOfCompoundTypeWrappers()) { // These are returned as arrays of ByteBuffers (e.g., jobjectArray) return "jobjectArray /* of ByteBuffer */"; } if (clazz == null) { return null; } if (isVoid()) { return "void"; } if (isPrimitive()) { return "j" + clazz.getName(); } if (isPrimitiveArray() || isNIOBuffer()) { // We now pass primitive arrays and buffers uniformly down to native code as java.lang.Object. return "jobject"; } if (isArray()) { if (isStringArray()) { return "jobjectArray /*elements are String*/"; } final Class<?> elementType = clazz.getComponentType(); if (isNIOBufferArray()) { return "jobjectArray /*elements are " + elementType.getName() + "*/"; } if (elementType.isArray()) { // Type is array-of-arrays-of-something if (elementType.getComponentType().isPrimitive()) { // Type is an array-of-arrays-of-primitive return "jobjectArray /* elements are " + elementType.getComponentType() + "[]*/"; //return "jobjectArray"; } else { throw new RuntimeException("Multi-dimensional arrays of types that are not primitives or Strings are not supported."); } } // Some unusual type that we don't handle throw new RuntimeException("Unexpected and unsupported array type: \"" + this + "\""); } if (isString()) { return "jstring"; } return "jobject"; } public boolean isOpaqued() { return opaqued; } public boolean isNIOBuffer() { return clazz != null && ( java.nio.Buffer.class.isAssignableFrom(clazz) || com.jogamp.common.nio.NativeBuffer.class.isAssignableFrom(clazz)) ; } public boolean isNIOByteBuffer() { return (clazz == java.nio.ByteBuffer.class); } public boolean isNIOByteBufferArray() { return (this == nioByteBufferArrayType); } public boolean isNIOBufferArray() { return (isArray() && (java.nio.Buffer.class.isAssignableFrom(clazz.getComponentType()))); } public boolean isNIOLongBuffer() { return (clazz == java.nio.LongBuffer.class); } public boolean isNIOPointerBuffer() { return (clazz == com.jogamp.common.nio.PointerBuffer.class); } public boolean isString() { return (clazz == java.lang.String.class); } public boolean isArray() { return ((clazz != null) && clazz.isArray()); } public boolean isFloatArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == Float.TYPE); } public boolean isDoubleArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == Double.TYPE); } public boolean isByteArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == Byte.TYPE); } public boolean isIntArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == Integer.TYPE); } public boolean isShortArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == Short.TYPE); } public boolean isLongArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == Long.TYPE); } public boolean isStringArray() { return (clazz != null && clazz.isArray() && clazz.getComponentType() == java.lang.String.class); } public boolean isPrimitive() { return ((clazz != null) && !isArray() && clazz.isPrimitive() && (clazz != Void.TYPE)); } public boolean isPrimitiveArray() { return (isArray() && (clazz.getComponentType().isPrimitive())); } public boolean isShort() { return (clazz == Short.TYPE); } public boolean isFloat() { return (clazz == Float.TYPE); } public boolean isDouble() { return (clazz == Double.TYPE); } public boolean isByte() { return (clazz == Byte.TYPE); } public boolean isLong() { return (clazz == Long.TYPE); } public boolean isInt() { return (clazz == Integer.TYPE); } public boolean isVoid() { return (clazz == Void.TYPE); } public boolean isCompoundTypeWrapper() { return (clazz == null && structName != null && !isJNIEnv()); } public boolean isArrayOfCompoundTypeWrappers() { return elementType != null; } public boolean isCPrimitivePointerType() { return primitivePointerType != null; } public boolean isCVoidPointerType() { return C_PTR.VOID.equals(primitivePointerType); } public boolean isCCharPointerType() { return C_PTR.CHAR.equals(primitivePointerType); } public boolean isCShortPointerType() { return C_PTR.SHORT.equals(primitivePointerType); } public boolean isCInt32PointerType() { return C_PTR.INT32.equals(primitivePointerType); } public boolean isCInt64PointerType() { return C_PTR.INT64.equals(primitivePointerType); } public boolean isCFloatPointerType() { return C_PTR.FLOAT.equals(primitivePointerType); } public boolean isCDoublePointerType() { return C_PTR.DOUBLE.equals(primitivePointerType); } public boolean isJNIEnv() { return clazz == null && "JNIEnv".equals(structName); } @Override public Object clone() { return new JavaType(primitivePointerType, clazz, structName, elementType); } @Override public String toString() { return getName(); } //---------------------------------------------------------------------- // Internals only below this point // private void append(final StringBuilder sb, final String val, final boolean prepComma) { if( prepComma ) { sb.append(", "); } sb.append(val); } // For debugging public String getDebugString() { final StringBuilder sb = new StringBuilder(); sb.append("JType["); boolean prepComma = false; { final String javaTypeName = getName(); if( null != javaTypeName ) { append(sb, javaTypeName, false); } else { append(sb, "ANON", false); } sb.append(" / "); if( null != structName ) { append(sb, "'"+structName+"'", prepComma); prepComma=true; } else { append(sb, "NIL", prepComma); prepComma=true; } } if( null != clazz ) { append(sb, "clazz = "+clazz.getName(), prepComma); prepComma=true; } if( null != elementType ) { append(sb, "elementType = "+elementType, prepComma); prepComma=true; } if( null != primitivePointerType ) { append(sb, "primitivePointerType = "+primitivePointerType, prepComma); prepComma=true; } append(sb, "is[", prepComma); prepComma=false; { if( isOpaqued() ) { append(sb, "opaque", prepComma); prepComma=true; } if( isArray() ) { append(sb, "array", prepComma); prepComma=true; } if( isArrayOfCompoundTypeWrappers() ) { append(sb, "compoundArray", prepComma); prepComma=true; } if( isCompoundTypeWrapper() ) { append(sb, "compound", prepComma); prepComma=true; } if( isArray() ) { append(sb, "array", prepComma); prepComma=true; } if( isPrimitive() ) { append(sb, "primitive", prepComma); prepComma=true; } if( isPrimitiveArray() ) { append(sb, "primitiveArray", prepComma); prepComma=true; } if( isNIOBuffer() ) { append(sb, "nioBuffer", prepComma); prepComma=true; } if( isNIOBufferArray() ) { append(sb, "nioBufferArray", prepComma); prepComma=true; } if( isCPrimitivePointerType() ) { append(sb, "C-Primitive-Pointer", prepComma); prepComma=true; } } append(sb, "], descriptor '"+getDescriptor()+"']", prepComma); prepComma=true; return sb.toString(); } /** * Constructs a representation for a type corresponding to the given Class * argument. */ private JavaType(final Class<?> clazz, final boolean opaqued) { this.primitivePointerType = null; this.clazz = clazz; this.structName = null; this.elementType = null; this.opaqued = opaqued; } /** Constructs a type representing a named C struct. */ private JavaType(final String structName) { this.primitivePointerType = null; this.clazz = null; this.structName = structName; this.elementType = null; this.opaqued = false; } /** Constructs a type representing a pointer to a C primitive (integer, floating-point, or void pointer) type. */ private JavaType(final C_PTR primitivePointerType) { this.primitivePointerType = primitivePointerType; this.clazz = null; this.structName = null; this.elementType = null; this.opaqued = false; } /** Constructs a type representing an array of C pointers. */ private JavaType(final Type elementType) { this.primitivePointerType = null; this.clazz = null; this.structName = null; this.elementType = elementType; this.opaqued = false; } /** clone only */ private JavaType(final C_PTR primitivePointerType, final Class<?> clazz, final String name, final Type elementType) { this.primitivePointerType = primitivePointerType; this.clazz = clazz; this.structName = name; this.elementType = elementType; this.opaqued = false; } private String arrayName(Class<?> clazz) { final StringBuilder buf = new StringBuilder(); int arrayCount = 0; while (clazz.isArray()) { ++arrayCount; clazz = clazz.getComponentType(); } buf.append(clazz.getName()); while (--arrayCount >= 0) { buf.append("[]"); } return buf.toString(); } private String arrayDescriptor(Class<?> clazz) { final StringBuilder buf = new StringBuilder(); while (clazz.isArray()) { buf.append("["); clazz = clazz.getComponentType(); } buf.append(descriptor(clazz)); return buf.toString(); } private String descriptor(final Class<?> clazz) { if (clazz.isPrimitive()) { if (clazz == Boolean.TYPE) return "Z"; if (clazz == Byte.TYPE) return "B"; if (clazz == Double.TYPE) return "D"; if (clazz == Float.TYPE) return "F"; if (clazz == Integer.TYPE) return "I"; if (clazz == Long.TYPE) return "J"; if (clazz == Short.TYPE) return "S"; if (clazz == Void.TYPE) return "V"; throw new RuntimeException("Unexpected primitive type " + clazz.getName()); } if (clazz.isArray()) { return arrayDescriptor(clazz); } return descriptor(clazz.getName()); } private String descriptor(final String referenceTypeName) { return "L" + referenceTypeName.replace('.', '/') + ";"; } }