/* * 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.cgram.types; import com.jogamp.common.os.MachineDataInfo; import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider; import com.jogamp.gluegen.ASTLocusTag; import com.jogamp.gluegen.GlueGen; import com.jogamp.gluegen.TypeConfig; import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Models a C type. Primitive types include int, float, and double. All types have an associated name. Structs and unions are modeled as "compound" types -- composed of fields of primitive or other types. */ public abstract class Type implements SemanticEqualityOp, ASTLocusTagProvider { public final boolean relaxedEqSem; private final int cvAttributes; final ASTLocusTag astLocus; private String name; private SizeThunk size; private int typedefCVAttributes; private boolean isTypedef; private boolean hasCachedHash; private int cachedHash; private boolean hasCachedSemanticHash; private int cachedSemanticHash; protected Type(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) { setName(name); // -> clearCache() this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); this.cvAttributes = cvAttributes; this.astLocus = astLocus; this.size = size; this.typedefCVAttributes = 0; this.isTypedef = false; } Type(final Type o, final int cvAttributes, final ASTLocusTag astLocus) { this.relaxedEqSem = o.relaxedEqSem; this.cvAttributes = cvAttributes; this.astLocus = astLocus; this.name = o.name; this.size = o.size; this.typedefCVAttributes = o.typedefCVAttributes; this.isTypedef = o.isTypedef; clearCache(); } protected final void clearCache() { hasCachedHash = false; cachedHash = 0; hasCachedSemanticHash = false; cachedSemanticHash = 0; } /** * Return a variant of this type matching the given const/volatile * attributes. May return this object if the attributes match. */ public final Type newCVVariant(final int cvAttributes) { if (this.cvAttributes == cvAttributes) { return this; } else { return newVariantImpl(true, cvAttributes, astLocus); } } /** * Clones this instance using a new {@link ASTLocusTag}. */ public Type clone(final ASTLocusTag newLoc) { return newVariantImpl(true, cvAttributes, newLoc); } /** * Create a new variant of this type matching the given parameter * <p> * Implementation <i>must</i> use {@link Type}'s copy-ctor: {@link #Type(Type, int, ASTLocusTag)}! * </p> * @param newCVVariant true if new variant is intended to have new <i>cvAttributes</i> * @param cvAttributes the <i>cvAttributes</i> to be used * @param astLocus the {@link ASTLocusTag} to be used */ abstract Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus); @Override public final ASTLocusTag getASTLocusTag() { return astLocus; } public boolean isAnon() { return null == name; } /** Returns the name of this type. The returned string is suitable for use as a type specifier for native C. Does not include any const/volatile attributes. */ public final String getCName() { return getCName(false); } /** Returns the name of this type, optionally including const/volatile attributes. The returned string is suitable for use as a type specifier for native C. */ public String getCName(final boolean includeCVAttrs) { return getName(includeCVAttrs); } /** Returns the name of this type. The returned string is suitable for use as a type specifier for Java. Does not include any const/volatile attributes. */ public final String getName() { return getName(false); } /** Returns the name of this type, optionally including const/volatile attributes. The returned string is suitable for use as a type specifier for Java. */ public String getName(final boolean includeCVAttrs) { if (!includeCVAttrs) { return name; } return getCVAttributesString() + name; } /** * Returns a string representation of this type. * The returned string is suitable for use as a type specifier for native C. * It does contain an expanded description of structs/unions, * hence may not be suitable for type declarations. */ @Override public String toString() { return getCName(true); } private static StringBuilder append(final StringBuilder sb, final String val, final boolean prepComma) { if( prepComma ) { sb.append(", "); } sb.append(val); return sb; } // For debugging public final String getDebugString() { final StringBuilder sb = new StringBuilder(); boolean prepComma = false; sb.append("CType["); sb.append("(").append(getClass().getSimpleName()).append(") "); if( isTypedef() ) { sb.append("typedef "); } if( null != name ) { sb.append("'").append(name).append("'"); } else { sb.append("ANON"); } final Type targetType = getTargetType(); if( null != targetType && this != targetType ) { sb.append(" -> "); if (!targetType.isFunction()) { sb.append("(" + targetType.toString() + ") * " + getCVAttributesString()); } else { sb.append(((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true)); } } if( GlueGen.debug() ) { sb.append(", o=0x"+Integer.toHexString(objHash())); } sb.append(", size "); prepComma=true; if( null != size ) { final long mdSize; { long _mdSize = -1; try { _mdSize = size.computeSize(MachineDataInfo.StaticConfig.LP64_UNIX.md); } catch (final Exception e) {} mdSize = _mdSize; } sb.append("[fixed ").append(size.hasFixedNativeSize()).append(", lnx64 ").append(mdSize).append("]"); } else { sb.append(" ZERO"); } append(sb, "[", prepComma); prepComma=false; { append(sb, "const[", prepComma); prepComma=false; { if( isConstTypedef() ) { append(sb, "type ", prepComma); prepComma=true; } if( isConstRaw() ) { append(sb, "inst -> ", prepComma); prepComma=false; } if( isConst() ) { append(sb, "true]", prepComma); } else { append(sb, "false]", prepComma); } prepComma=true; } if( isVolatile() ) { append(sb, "volatile ", prepComma); prepComma=true; } if( isPointer() ) { append(sb, "pointer*"+pointerDepth(), prepComma); prepComma=true; } if( isArray() ) { append(sb, "array*"+arrayDimension(), prepComma); prepComma=true; } if( isBit() ) { append(sb, "bit", prepComma); prepComma=true; } if( isCompound() ) { append(sb, "struct{", prepComma).append(asCompound().getStructName()).append(": ").append(asCompound().getNumFields()); append(sb, "}", prepComma); prepComma=true; } if( isDouble() ) { append(sb, "double", prepComma); prepComma=true; } if( isEnum() ) { final EnumType eT = asEnum(); append(sb, "enum ", prepComma).append(" [").append(eT.getUnderlyingType()).append("] {").append(eT.getNumEnumerates()).append(": "); eT.appendEnums(sb, false); prepComma=true; } if( isFloat() ) { append(sb, "float", prepComma); prepComma=true; } if( isFunction() ) { append(sb, "function", prepComma); prepComma=true; } if( isFunctionPointer() ) { append(sb, "funcPointer", prepComma); prepComma=true; } if( isInt() ) { append(sb, "int", prepComma); prepComma=true; } if( isVoid() ) { append(sb, "void", prepComma); prepComma=true; } sb.append("]"); } sb.append("]"); return sb.toString(); } private final int objHash() { return super.hashCode(); } /** * Returns {@code true} if given {@code name} is not {@code null} * and has a length > 0. In this case this instance's names will * be set to the internalized version. * <p> * Otherwise method returns {@code false} * and this instance's name will be set to {@code null}. * </p> * <p> * Method issues {@link #clearCache()}, to force re-evaluation * of hashes. * </p> */ private final boolean setName(final String name) { clearCache(); if( null == name || 0 == name.length() ) { this.name = name; return false; } else { this.name = name.intern(); return true; } } /** * Set the typedef name of this type and renders this type a typedef, * if given {@code name} has a length. * <p> * Method issues {@link #clearCache()}, to force re-evaluation * of hashes. * </p> */ public boolean setTypedefName(final String name) { if( setName(name) ) { // Capture the const/volatile attributes at the time of typedef so // we don't redundantly repeat them in the CV attributes string typedefCVAttributes = cvAttributes; isTypedef = true; return true; } else { return false; } } final void setTypedef(final int typedefedCVAttributes) { this.name = this.name.intern(); // just make sure .. this.typedefCVAttributes = typedefedCVAttributes; this.isTypedef = true; clearCache(); } final int getTypedefCVAttributes() { return typedefCVAttributes; } /** * Indicates whether this type is a typedef type, * i.e. declared via {@link #setTypedefName(String)}. */ public final boolean isTypedef() { return isTypedef; } /** SizeThunk which computes size of this type in bytes. */ public final SizeThunk getSize() { return size; } /** Size of this type in bytes according to the given MachineDataInfo. */ public final long getSize(final MachineDataInfo machDesc) { final SizeThunk thunk = getSize(); if (thunk == null) { throw new RuntimeException("No size set for type \"" + getName() + "\""); } return thunk.computeSize(machDesc); } /** Set the size of this type; only available for CompoundTypes. */ final void setSize(final SizeThunk size) { this.size = size; clearCache(); } /** Casts this to a BitType or returns null if not a BitType. */ public BitType asBit() { return null; } /** Casts this to an IntType or returns null if not an IntType. */ public IntType asInt() { return null; } /** Casts this to an EnumType or returns null if not an EnumType. */ public EnumType asEnum() { return null; } /** Casts this to a FloatType or returns null if not a FloatType. */ public FloatType asFloat() { return null; } /** Casts this to a DoubleType or returns null if not a DoubleType. */ public DoubleType asDouble() { return null; } /** Casts this to a PointerType or returns null if not a PointerType. */ public PointerType asPointer() { return null; } /** Casts this to an ArrayType or returns null if not an ArrayType. */ public ArrayType asArray() { return null; } /** Casts this to a CompoundType or returns null if not a CompoundType. */ public CompoundType asCompound() { return null; } /** Casts this to a FunctionType or returns null if not a FunctionType. */ public FunctionType asFunction() { return null; } /** Casts this to a VoidType or returns null if not a VoidType. */ public VoidType asVoid() { return null; } /** Indicates whether this is a BitType. */ public final boolean isBit() { return (asBit() != null); } /** Indicates whether this is an IntType. */ public final boolean isInt() { return (asInt() != null); } /** Indicates whether this is an EnumType. */ public final boolean isEnum() { return (asEnum() != null); } /** Indicates whether this is a FloatType. */ public final boolean isFloat() { return (asFloat() != null); } /** Indicates whether this is a DoubleType. */ public final boolean isDouble() { return (asDouble() != null); } /** Indicates whether this is a PointerType. */ public final boolean isPointer() { return (asPointer() != null); } /** Indicates whether this is an ArrayType. */ public final boolean isArray() { return (asArray() != null); } /** Indicates whether this is a CompoundType. */ public final boolean isCompound() { return (asCompound() != null); } /** Indicates whether this is a FunctionType. */ public final boolean isFunction() { return (asFunction() != null); } /** Indicates whether this is a VoidType. */ public final boolean isVoid() { return (asVoid() != null); } /** Indicates whether this type is volatile. */ public final boolean isVolatile() { return 0 != ( ( cvAttributes & ~typedefCVAttributes ) & CVAttributes.VOLATILE ); } /** Indicates whether this type is const. */ public final boolean isConst() { return 0 != ( ( cvAttributes & ~typedefCVAttributes ) & CVAttributes.CONST ); } private final boolean isConstTypedef() { return 0 != ( typedefCVAttributes & CVAttributes.CONST ); } private final boolean isConstRaw() { return 0 != ( cvAttributes & CVAttributes.CONST ); } /** Indicates whether this type is a primitive type. */ public boolean isPrimitive(){ return false; } /** Convenience routine indicating whether this Type is a pointer to a function. */ public boolean isFunctionPointer() { return false; } /** * Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness. * <p> * Note: Intermediate 'const' qualifier are not considered, e.g. const pointer. * </p> */ public final boolean isBaseTypeConst() { return getBaseElementType().isConst(); } /** Hashcode for Types. */ @Override public final int hashCode() { if( !hasCachedHash ) { // 31 * x == (x << 5) - x int hash = 31 + ( isTypedef ? 1 : 0 ); hash = ((hash << 5) - hash) + ( null != size ? size.hashCode() : 0 ); hash = ((hash << 5) - hash) + cvAttributes; hash = ((hash << 5) - hash) + typedefCVAttributes; hash = ((hash << 5) - hash) + ( null != name ? name.hashCode() : 0 ); if( !isTypedef ) { hash = ((hash << 5) - hash) + hashCodeImpl(); } cachedHash = hash; hasCachedHash = true; } return cachedHash; } protected abstract int hashCodeImpl(); /** * Equality test for Types inclusive its given {@link #getName() name}. */ @Override public final boolean equals(final Object arg) { if (arg == this) { return true; } else if ( !getClass().isInstance(arg) ) { // implies null == arg || !(arg instanceof Type) return false; } else { final Type t = (Type)arg; if( isTypedef == t.isTypedef && ( ( null != size && size.equals(t.size) ) || ( null == size && null == t.size ) ) && cvAttributes == t.cvAttributes && typedefCVAttributes == t.typedefCVAttributes && ( null == name ? null == t.name : name.equals(t.name) ) ) { if( !isTypedef ) { return equalsImpl(t); } else { return true; } } else { return false; } } } protected abstract boolean equalsImpl(final Type t); @Override public final int hashCodeSemantics() { if( !hasCachedSemanticHash ) { // 31 * x == (x << 5) - x int hash = 31 + ( null != size ? size.hashCodeSemantics() : 0 ); if( !relaxedEqSem ) { hash = ((hash << 5) - hash) + cvAttributes; hash = ((hash << 5) - hash) + typedefCVAttributes; } hash = ((hash << 5) - hash) + hashCodeSemanticsImpl(); cachedSemanticHash = hash; hasCachedSemanticHash = true; } return cachedSemanticHash; } protected abstract int hashCodeSemanticsImpl(); @Override public final boolean equalSemantics(final SemanticEqualityOp arg) { if (arg == this) { return true; } else if ( !(arg instanceof Type) || !getClass().isInstance(arg) ) { // implies null == arg return false; } else { final Type t = (Type) arg; if( ( ( null != size && size.equalSemantics(t.size) ) || ( null == size && null == t.size ) ) && ( relaxedEqSem || ( cvAttributes == t.cvAttributes && typedefCVAttributes == t.typedefCVAttributes ) ) ) { return equalSemanticsImpl(t); } else { return false; } } } protected abstract boolean equalSemanticsImpl(final Type t); /** * Traverse this {@link Type} and all of its component types; for * example, the return type and argument types of a FunctionType. */ public void visit(final TypeVisitor visitor) { visitor.visitType(this); } public final int getCVAttributes() { return cvAttributes; } /** Returns a string indicating the const/volatile attributes of this type. */ public final String getCVAttributesString() { if (isConst() && isVolatile()) return "const volatile "; if (isConst()) return "const "; if (isVolatile()) return "volatile "; return ""; } /** Helper method for determining how many pointer indirections this type represents (i.e., "void **" returns 2). Returns 0 if this type is not a pointer type. */ public int pointerDepth() { return 0; } /** Helper method for determining how many array dimentions this type represents (i.e., "char[][]" returns 2). Returns 0 if this type is not an array type. */ public int arrayDimension() { return 0; } /** * Helper method to returns the bottom-most element type of this type. * <p> * If this is a multidimensional array or pointer method returns the bottom-most element type, * otherwise this. * </p> */ public Type getBaseElementType() { return this; } /** * Helper method to returns the target type of this type, in case another type is being referenced. */ public Type getTargetType() { return this; } }