FileDocCategorySizeDatePackage
Type.javaAPI DocAndroid 5.1 API27809Thu Mar 12 22:18:30 GMT 2015com.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 {@code ==}.

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

return
{@code >= -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 {@code "V"} (that is, type {@code void}) as a valid descriptor.

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


                                                                    
         
        Type result;
        synchronized (internTable) {
            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: " + 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: " + descriptor);
                }
                case '/": {
                    if ((i == 1) ||
                        (i == (length - 1)) ||
                        (descriptor.charAt(i - 1) == '/")) {
                        throw new IllegalArgumentException("bad descriptor: " + 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 {@code intern(name)} if {@code name} begins with {@code "["} and calling {@code intern("L" + name + ";")} in all other cases.

param
name {@code non-null;} the name of the class whose type is desired
return
{@code 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 {@code "V"} to return the type for {@code void}. Other than that one caveat, this method is identical to {@link #intern}.

param
descriptor {@code non-null;} the descriptor
return
{@code 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 {@code 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 {@code 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 {@code 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 {@code 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 {@code non-null;} instance to make interned
return
{@code 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;