Fields Summary |
---|
private static final HashMap | internTable{@code non-null;} intern table mapping string descriptors to instances |
private static final HashMap | CLASS_TYPE_MAP{@code non-null;} table mapping types as {@code Class} objects to internal form |
public static final int | BT_VOIDbasic type constant for {@code void} |
public static final int | BT_BOOLEANbasic type constant for {@code boolean} |
public static final int | BT_BYTEbasic type constant for {@code byte} |
public static final int | BT_CHARbasic type constant for {@code char} |
public static final int | BT_DOUBLEbasic type constant for {@code double} |
public static final int | BT_FLOATbasic type constant for {@code float} |
public static final int | BT_INTbasic type constant for {@code int} |
public static final int | BT_LONGbasic type constant for {@code long} |
public static final int | BT_SHORTbasic type constant for {@code short} |
public static final int | BT_OBJECTbasic type constant for {@code Object} |
public static final int | BT_ADDRbasic type constant for a return address |
public static final int | BT_COUNTcount 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 | basicTypebasic 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 |
Methods Summary |
---|
public com.android.dexgen.rop.type.Type | asUninitialized(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.
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 int | compareTo(com.android.dexgen.rop.type.Type other){@inheritDoc}
return descriptor.compareTo(other.descriptor);
|
public boolean | equals(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.dexgen.rop.type.Type | getArrayType()Gets the type corresponding to an array of this type.
if (arrayType == null) {
arrayType = putIntern(new Type('[" + descriptor, BT_OBJECT));
}
return arrayType;
|
public int | getBasicFrameType(){@inheritDoc}
switch (basicType) {
case BT_BOOLEAN:
case BT_BYTE:
case BT_CHAR:
case BT_INT:
case BT_SHORT: {
return BT_INT;
}
}
return basicType;
|
public int | getBasicType(){@inheritDoc}
return basicType;
|
public int | getCategory()Gets the category. Most instances are category 1. {@code long}
and {@code double} are the only category 2 types.
switch (basicType) {
case BT_LONG:
case BT_DOUBLE: {
return 2;
}
}
return 1;
|
public java.lang.String | getClassName()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).
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.dexgen.rop.type.Type | getComponentType()Gets the component type of this type. This method is only valid on
array types.
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.String | getDescriptor()Gets the descriptor.
return descriptor;
|
public com.android.dexgen.rop.type.Type | getFrameType(){@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.dexgen.rop.type.Type | getInitializedType()Gets the initialized type corresponding to this instance, but only
if this instance is in fact an uninitialized object type.
if (initializedType == null) {
throw new IllegalArgumentException("initialized type: " +
descriptor);
}
return initializedType;
|
public static java.lang.String | getInternalTypeName(java.lang.Class clazz)Converts type name in the format as returned by reflection
into dex internal form.
if (clazz == null) {
throw new NullPointerException("clazz == null");
}
if (clazz.isPrimitive()) {
return CLASS_TYPE_MAP.get(clazz).getDescriptor();
}
String slashed = clazz.getName().replace('.", '/");
if (clazz.isArray()) {
return slashed;
}
return 'L" + slashed + ';";
|
public int | getNewAt()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 newAt;
|
public com.android.dexgen.rop.type.Type | getType(){@inheritDoc}
return this;
|
public int | hashCode(){@inheritDoc}
return descriptor.hashCode();
|
public static com.android.dexgen.rop.type.Type | intern(java.lang.Class clazz)Returns the unique instance corresponding to the type represented by
given {@code Class} object. 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.
return intern(getInternalTypeName(clazz));
|
public static com.android.dexgen.rop.type.Type | intern(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.
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" + 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");
}
break;
}
}
}
result = new Type(descriptor, BT_OBJECT);
return putIntern(result);
|
public static com.android.dexgen.rop.type.Type | internClassName(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.
if (name == null) {
throw new NullPointerException("name == null");
}
if (name.startsWith("[")) {
return intern(name);
}
return intern('L" + name + ';");
|
public static com.android.dexgen.rop.type.Type | internReturnType(java.lang.Class clazz)Returns the unique instance corresponding to the type represented by
given {@code Class} object, allowing {@code "V"} to return the type
for {@code void}. Other than that one caveat, this method
is identical to {@link #intern}.
return internReturnType(getInternalTypeName(clazz));
|
public static com.android.dexgen.rop.type.Type | internReturnType(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}.
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 boolean | isArray()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 (descriptor.charAt(0) == '[");
|
public boolean | isArrayOrKnownNull()Gets whether this type is an array type or is a known-null, and
hence is compatible with array types.
return isArray() || equals(KNOWN_NULL);
|
public boolean | isCategory1()Returns whether or not this is a category 1 type.
switch (basicType) {
case BT_LONG:
case BT_DOUBLE: {
return false;
}
}
return true;
|
public boolean | isCategory2()Returns whether or not this is a category 2 type.
switch (basicType) {
case BT_LONG:
case BT_DOUBLE: {
return true;
}
}
return false;
|
public boolean | isConstant(){@inheritDoc}
return false;
|
public boolean | isIntlike()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}.
switch (basicType) {
case BT_BOOLEAN:
case BT_BYTE:
case BT_CHAR:
case BT_INT:
case BT_SHORT: {
return true;
}
}
return false;
|
public boolean | isPrimitive()Gets whether this type is a primitive type. All types are either
primitive or reference types.
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 boolean | isReference()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 (basicType == BT_OBJECT);
|
public boolean | isUninitialized()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 (newAt >= 0);
|
private static com.android.dexgen.rop.type.Type | putIntern(com.android.dexgen.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.
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.String | toHuman(){@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.String | toString(){@inheritDoc}
return descriptor;
|