FileDocCategorySizeDatePackage
Type.javaAPI DocAndroid 1.5 API27588Wed May 06 22:41:02 BST 2009com.android.dx.rop.type

Type

public final class Type extends Object implements Comparable, TypeBearer
Representation of a value type, such as may appear in a field, in a local, on a stack, or in a method descriptor. Instances of this class are generally interned and may be usefully compared with each other using ==.

Fields Summary
private static final HashMap
internTable
non-null; intern table mapping string descriptors to instances
public static final int
BT_VOID
basic type constant for void
public static final int
BT_BOOLEAN
basic type constant for boolean
public static final int
BT_BYTE
basic type constant for byte
public static final int
BT_CHAR
basic type constant for char
public static final int
BT_DOUBLE
basic type constant for double
public static final int
BT_FLOAT
basic type constant for float
public static final int
BT_INT
basic type constant for int
public static final int
BT_LONG
basic type constant for long
public static final int
BT_SHORT
basic type constant for short
public static final int
BT_OBJECT
basic type constant for Object
public static final int
BT_ADDR
basic type constant for a return address
public static final int
BT_COUNT
count of basic type constants
public static final Type
BOOLEAN
non-null; instance representing boolean
public static final Type
BYTE
non-null; instance representing byte
public static final Type
CHAR
non-null; instance representing char
public static final Type
DOUBLE
non-null; instance representing double
public static final Type
FLOAT
non-null; instance representing float
public static final Type
INT
non-null; instance representing int
public static final Type
LONG
non-null; instance representing long
public static final Type
SHORT
non-null; instance representing short
public static final Type
VOID
non-null; instance representing void
public static final Type
KNOWN_NULL
non-null; instance representing a known-null
public static final Type
RETURN_ADDRESS
non-null; instance representing a subroutine return address
public static final Type
ANNOTATION
non-null; instance representing java.lang.annotation.Annotation
public static final Type
CLASS
non-null; instance representing java.lang.Class
public static final Type
CLONEABLE
non-null; instance representing java.lang.Cloneable
public static final Type
OBJECT
non-null; instance representing java.lang.Object
public static final Type
SERIALIZABLE
non-null; instance representing java.io.Serializable
public static final Type
STRING
non-null; instance representing java.lang.String
public static final Type
THROWABLE
non-null; instance representing java.lang.Throwable
public static final Type
BOOLEAN_CLASS
non-null; instance representing java.lang.Boolean; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
BYTE_CLASS
non-null; instance representing java.lang.Byte; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
CHARACTER_CLASS
non-null; instance representing java.lang.Character; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
DOUBLE_CLASS
non-null; instance representing java.lang.Double; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
FLOAT_CLASS
non-null; instance representing java.lang.Float; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
INTEGER_CLASS
non-null; instance representing java.lang.Integer; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
LONG_CLASS
non-null; instance representing java.lang.Long; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
SHORT_CLASS
non-null; instance representing java.lang.Short; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
VOID_CLASS
non-null; instance representing java.lang.Void; the suffix on the name helps disambiguate this from the instance representing a primitive type
public static final Type
BOOLEAN_ARRAY
non-null; instance representing boolean[]
public static final Type
BYTE_ARRAY
non-null; instance representing byte[]
public static final Type
CHAR_ARRAY
non-null; instance representing char[]
public static final Type
DOUBLE_ARRAY
non-null; instance representing double[]
public static final Type
FLOAT_ARRAY
non-null; instance representing float[]
public static final Type
INT_ARRAY
non-null; instance representing int[]
public static final Type
LONG_ARRAY
non-null; instance representing long[]
public static final Type
OBJECT_ARRAY
non-null; instance representing Object[]
public static final Type
SHORT_ARRAY
non-null; instance representing short[]
private final String
descriptor
non-null; field descriptor for the type
private final int
basicType
basic type corresponding to this type; one of the BT_* constants
private final int
newAt
>= -1; for an uninitialized type, bytecode index that this instance was allocated at; Integer.MAX_VALUE if it was an incoming uninitialized instance; -1 if this is an inititialized instance
private String
className
null-ok; the internal-form class name corresponding to this type, if calculated; only valid if this is a reference type and additionally not a return address
private Type
arrayType
null-ok; the type corresponding to an array of this type, if calculated
private Type
componentType
null-ok; the type corresponding to elements of this type, if calculated; only valid if this is an array type
private Type
initializedType
null-ok; the type corresponding to the initialized version of this type, if this instance is in fact an uninitialized type
Constructors Summary
private Type(String descriptor, int basicType, int newAt)
Constructs an instance corresponding to an "uninitialized type." This is a private constructor; use one of the public static methods to get instances.

param
descriptor non-null; the field descriptor for the type
param
basicType basic type corresponding to this type; one of the BT_* constants
param
newAt >= -1 allocation bytecode index

        if (descriptor == null) {
            throw new NullPointerException("descriptor == null");
        }

        if ((basicType < 0) || (basicType >= BT_COUNT)) {
            throw new IllegalArgumentException("bad basicType");
        }

        if (newAt < -1) {
            throw new IllegalArgumentException("newAt < -1");
        }

        this.descriptor = descriptor;
        this.basicType = basicType;
        this.newAt = newAt;
        this.arrayType = null;
        this.componentType = null;
        this.initializedType = null;
    
private Type(String descriptor, int basicType)
Constructs an instance corresponding to an "initialized type." This is a private constructor; use one of the public static methods to get instances.

param
descriptor non-null; the field descriptor for the type
param
basicType basic type corresponding to this type; one of the BT_* constants

        this(descriptor, basicType, -1);
    
Methods Summary
public com.android.dx.rop.type.TypeasUninitialized(int newAt)
Returns a new interned instance which is identical to this one, except it is indicated as uninitialized and allocated at the given bytecode index. This instance must be an initialized object type.

param
newAt >= 0; the allocation bytecode index
return
non-null; an appropriately-constructed instance

        if (newAt < 0) {
            throw new IllegalArgumentException("newAt < 0");
        }

        if (!isReference()) {
            throw new IllegalArgumentException("not a reference type: " +
                                               descriptor);
        }

        if (isUninitialized()) {
            /*
             * Dealing with uninitialized types as a starting point is
             * a pain, and it's not clear that it'd ever be used, so
             * just disallow it.
             */
            throw new IllegalArgumentException("already uninitialized: " +
                                               descriptor);
        }

        /*
         * Create a new descriptor that is unique and shouldn't conflict
         * with "normal" type descriptors
         */
        String newDesc = 'N" + Hex.u2(newAt) + descriptor;
        Type result = new Type(newDesc, BT_OBJECT, newAt);
        result.initializedType = this;
        return putIntern(result);
    
public intcompareTo(com.android.dx.rop.type.Type other)
{@inheritDoc}

        return descriptor.compareTo(other.descriptor);
    
public booleanequals(java.lang.Object other)
{@inheritDoc}

        if (this == other) {
            /*
             * Since externally-visible types are interned, this check
             * helps weed out some easy cases.
             */
            return true;
        }

        if (!(other instanceof Type)) {
            return false;
        }

        return descriptor.equals(((Type) other).descriptor);
    
public com.android.dx.rop.type.TypegetArrayType()
Gets the type corresponding to an array of this type.

return
non-null; the array type

        if (arrayType == null) {
            arrayType = putIntern(new Type('[" + descriptor, BT_OBJECT));
        }

        return arrayType;
    
public intgetBasicFrameType()
{@inheritDoc}

        switch (basicType) {
            case BT_BOOLEAN:
            case BT_BYTE:
            case BT_CHAR:
            case BT_INT:
            case BT_SHORT: {
                return BT_INT;
            }
        }

        return basicType;
    
public intgetBasicType()
{@inheritDoc}

        return basicType;
    
public intgetCategory()
Gets the category. Most instances are category 1. long and double are the only category 2 types.

see
#isCategory1
see
#isCategory2
return
the category

        switch (basicType) {
            case BT_LONG:
            case BT_DOUBLE: {
                return 2;
            }
        }

        return 1;
    
public java.lang.StringgetClassName()
Gets the name of the class this type corresponds to, in internal form. This method is only valid if this instance is for a normal reference type (that is, a reference type and additionally not a return address).

return
non-null; the internal-form class name

        if (className == null) {
            if (!isReference()) {
                throw new IllegalArgumentException("not an object type: " +
                                                   descriptor);
            }

            if (descriptor.charAt(0) == '[") {
                className = descriptor;
            } else {
                className = descriptor.substring(1, descriptor.length() - 1);
            }
        }

        return className;
    
public com.android.dx.rop.type.TypegetComponentType()
Gets the component type of this type. This method is only valid on array types.

return
non-null; the component type

        if (componentType == null) {
            if (descriptor.charAt(0) != '[") {
                throw new IllegalArgumentException("not an array type: " +
                                                   descriptor);
            }
            componentType = intern(descriptor.substring(1));
        }

        return componentType;
    
public java.lang.StringgetDescriptor()
Gets the descriptor.

return
non-null; the descriptor

        return descriptor;
    
public com.android.dx.rop.type.TypegetFrameType()
{@inheritDoc}

        switch (basicType) {
            case BT_BOOLEAN:
            case BT_BYTE:
            case BT_CHAR:
            case BT_INT:
            case BT_SHORT: {
                return INT;
            }
        }

        return this;
    
public com.android.dx.rop.type.TypegetInitializedType()
Gets the initialized type corresponding to this instance, but only if this instance is in fact an uninitialized object type.

return
non-null; the initialized type

        if (initializedType == null) {
            throw new IllegalArgumentException("initialized type: " +
                                               descriptor);
        }

        return initializedType;
    
public intgetNewAt()
Gets the bytecode index at which this uninitialized type was allocated. This returns Integer.MAX_VALUE if this type is an uninitialized incoming parameter (i.e., the this of an <init> method) or -1 if this type is in fact initialized.

return
>= -1; the allocation bytecode index

        return newAt;
    
public com.android.dx.rop.type.TypegetType()
{@inheritDoc}

        return this;
    
public inthashCode()
{@inheritDoc}

        return descriptor.hashCode();
    
public static com.android.dx.rop.type.Typeintern(java.lang.String descriptor)
Returns the unique instance corresponding to the type with the given descriptor. See vmspec-2 sec4.3.2 for details on the field descriptor syntax. This method does not allow "V" (that is, type void) as a valid descriptor.

param
descriptor non-null; the descriptor
return
non-null; the corresponding instance
throws
IllegalArgumentException thrown if the descriptor has invalid syntax


                                                                 
         
        Type result = internTable.get(descriptor);
        if (result != null) {
            return result;
        }

        char firstChar;
        try {
            firstChar = descriptor.charAt(0);
        } catch (IndexOutOfBoundsException ex) {
            // Translate the exception.
            throw new IllegalArgumentException("descriptor is empty");
        } catch (NullPointerException ex) {
            // Elucidate the exception.
            throw new NullPointerException("descriptor == null");
        }

        if (firstChar == '[") {
            /*
             * Recursively strip away array markers to get at the underlying
             * type, and build back on to form the result.
             */
            result = intern(descriptor.substring(1));
            return result.getArrayType();
        }

        /*
         * If the first character isn't '[' and it wasn't found in the
         * intern cache, then it had better be the descriptor for a class.
         */

        int length = descriptor.length();
        if ((firstChar != 'L") ||
            (descriptor.charAt(length - 1) != ';")) {
            throw new IllegalArgumentException("bad descriptor");
        }

        /*
         * Validate the characters of the class name itself. Note that
         * vmspec-2 does not have a coherent definition for valid
         * internal-form class names, and the definition here is fairly
         * liberal: A name is considered valid as long as it doesn't
         * contain any of '[' ';' '.' '(' ')', and it has no more than one
         * '/' in a row, and no '/' at either end.
         */

        int limit = (length - 1); // Skip the final ';'.
        for (int i = 1; i < limit; i++) {
            char c = descriptor.charAt(i);
            switch (c) {
                case '[":
                case ';": 
                case '.": 
                case '(":
                case ')": {
                    throw new IllegalArgumentException("bad descriptor");
                }
                case '/": {
                    if ((i == 1) ||
                        (i == (length - 1)) ||
                        (descriptor.charAt(i - 1) == '/")) {
                        throw new IllegalArgumentException("bad descriptor");
                    }
                    break;
                }
            }
        }

        result = new Type(descriptor, BT_OBJECT);
        return putIntern(result);
    
public static com.android.dx.rop.type.TypeinternClassName(java.lang.String name)
Returns the unique instance corresponding to the type of the class with the given name. Calling this method is equivalent to calling intern(name) if name begins with "[" and calling intern("L" + name + ";") in all other cases.

param
name non-null; the name of the class whose type is desired
return
non-null; the corresponding type
throws
IllegalArgumentException thrown if the name has invalid syntax

        if (name == null) {
            throw new NullPointerException("name == null");
        }

        if (name.startsWith("[")) {
            return intern(name);
        }

        return intern('L" + name + ';");
    
public static com.android.dx.rop.type.TypeinternReturnType(java.lang.String descriptor)
Returns the unique instance corresponding to the type with the given descriptor, allowing "V" to return the type for void. Other than that one caveat, this method is identical to {@link #intern}.

param
descriptor non-null; the descriptor
return
non-null; the corresponding instance
throws
IllegalArgumentException thrown if the descriptor has invalid syntax

        try {
            if (descriptor.equals("V")) {
                // This is the one special case where void may be returned.
                return VOID;
            }
        } catch (NullPointerException ex) {
            // Elucidate the exception.
            throw new NullPointerException("descriptor == null");
        }

        return intern(descriptor);
    
public booleanisArray()
Gets whether this type is an array type. If this method returns true, then it is safe to use {@link #getComponentType} to determine the component type.

return
whether this type is an array type

        return (descriptor.charAt(0) == '[");
    
public booleanisArrayOrKnownNull()
Gets whether this type is an array type or is a known-null, and hence is compatible with array types.

return
whether this type is an array type

        return isArray() || equals(KNOWN_NULL);
    
public booleanisCategory1()
Returns whether or not this is a category 1 type.

see
#getCategory
see
#isCategory2
return
whether or not this is a category 1 type

        switch (basicType) {
            case BT_LONG:
            case BT_DOUBLE: {
                return false;
            }
        }

        return true;
    
public booleanisCategory2()
Returns whether or not this is a category 2 type.

see
#getCategory
see
#isCategory1
return
whether or not this is a category 2 type

        switch (basicType) {
            case BT_LONG:
            case BT_DOUBLE: {
                return true;
            }
        }

        return false;
    
public booleanisConstant()
{@inheritDoc}

        return false;
    
public booleanisIntlike()
Gets whether this type is "intlike." An intlike type is one which, when placed on a stack or in a local, is automatically converted to an int.

return
whether this type is "intlike"

        switch (basicType) {
            case BT_BOOLEAN:
            case BT_BYTE:
            case BT_CHAR:
            case BT_INT:
            case BT_SHORT: {
                return true;
            }
        }

        return false;
    
public booleanisPrimitive()
Gets whether this type is a primitive type. All types are either primitive or reference types.

return
whether this type is primitive

        switch (basicType) {
            case BT_BOOLEAN:
            case BT_BYTE:
            case BT_CHAR:
            case BT_DOUBLE:
            case BT_FLOAT:
            case BT_INT:
            case BT_LONG:
            case BT_SHORT:
            case BT_VOID: {
                return true;
            }
        }

        return false;
    
public booleanisReference()
Gets whether this type is a normal reference type. A normal reference type is a reference type that is not a return address. This method is just convenient shorthand for getBasicType() == Type.BT_OBJECT.

return
whether this type is a normal reference type

        return (basicType == BT_OBJECT);
    
public booleanisUninitialized()
Gets whether this type represents an uninitialized instance. An uninitialized instance is what one gets back from the new opcode, and remains uninitialized until a valid constructor is invoked on it.

return
whether this type is "uninitialized"

        return (newAt >= 0);
    
private static com.android.dx.rop.type.TypeputIntern(com.android.dx.rop.type.Type type)
Puts the given instance in the intern table if it's not already there. If a conflicting value is already in the table, then leave it. Return the interned value.

param
type non-null; instance to make interned
return
non-null; the actual interned object

        synchronized (internTable) {
            String descriptor = type.getDescriptor();
            Type already = internTable.get(descriptor);
            if (already != null) {
                return already;
            }
            internTable.put(descriptor, type);
            return type;
        }
    
public java.lang.StringtoHuman()
{@inheritDoc}

        switch (basicType) {
            case BT_VOID:    return "void";
            case BT_BOOLEAN: return "boolean";
            case BT_BYTE:    return "byte";
            case BT_CHAR:    return "char";
            case BT_DOUBLE:  return "double";
            case BT_FLOAT:   return "float";
            case BT_INT:     return "int";
            case BT_LONG:    return "long";
            case BT_SHORT:   return "short";
            case BT_OBJECT:  break;
            default:         return descriptor;
        }

        if (isArray()) {
            return getComponentType().toHuman() + "[]";
        }

        // Remove the "L...;" around the type and convert "/" to ".".
        return getClassName().replace("/", ".");
    
public java.lang.StringtoString()
{@inheritDoc}

        return descriptor;