2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.dx.rop.type;
19 import com.android.dx.util.Hex;
20 import java.util.HashMap;
23 * Representation of a value type, such as may appear in a field, in a
24 * local, on a stack, or in a method descriptor. Instances of this
25 * class are generally interned and may be usefully compared with each
26 * other using {@code ==}.
28 public final class Type implements TypeBearer, Comparable<Type> {
30 * {@code non-null;} intern table mapping string descriptors to
33 private static final HashMap<String, Type> internTable =
34 new HashMap<String, Type>(500);
36 /** basic type constant for {@code void} */
37 public static final int BT_VOID = 0;
39 /** basic type constant for {@code boolean} */
40 public static final int BT_BOOLEAN = 1;
42 /** basic type constant for {@code byte} */
43 public static final int BT_BYTE = 2;
45 /** basic type constant for {@code char} */
46 public static final int BT_CHAR = 3;
48 /** basic type constant for {@code double} */
49 public static final int BT_DOUBLE = 4;
51 /** basic type constant for {@code float} */
52 public static final int BT_FLOAT = 5;
54 /** basic type constant for {@code int} */
55 public static final int BT_INT = 6;
57 /** basic type constant for {@code long} */
58 public static final int BT_LONG = 7;
60 /** basic type constant for {@code short} */
61 public static final int BT_SHORT = 8;
63 /** basic type constant for {@code Object} */
64 public static final int BT_OBJECT = 9;
66 /** basic type constant for a return address */
67 public static final int BT_ADDR = 10;
69 /** count of basic type constants */
70 public static final int BT_COUNT = 11;
72 /** {@code non-null;} instance representing {@code boolean} */
73 public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
75 /** {@code non-null;} instance representing {@code byte} */
76 public static final Type BYTE = new Type("B", BT_BYTE);
78 /** {@code non-null;} instance representing {@code char} */
79 public static final Type CHAR = new Type("C", BT_CHAR);
81 /** {@code non-null;} instance representing {@code double} */
82 public static final Type DOUBLE = new Type("D", BT_DOUBLE);
84 /** {@code non-null;} instance representing {@code float} */
85 public static final Type FLOAT = new Type("F", BT_FLOAT);
87 /** {@code non-null;} instance representing {@code int} */
88 public static final Type INT = new Type("I", BT_INT);
90 /** {@code non-null;} instance representing {@code long} */
91 public static final Type LONG = new Type("J", BT_LONG);
93 /** {@code non-null;} instance representing {@code short} */
94 public static final Type SHORT = new Type("S", BT_SHORT);
96 /** {@code non-null;} instance representing {@code void} */
97 public static final Type VOID = new Type("V", BT_VOID);
99 /** {@code non-null;} instance representing a known-{@code null} */
100 public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
102 /** {@code non-null;} instance representing a subroutine return address */
103 public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
107 * Put all the primitive types into the intern table. This needs
108 * to happen before the array types below get interned.
119 * Note: VOID isn't put in the intern table, since it's special and
120 * shouldn't be found by a normal call to intern().
125 * {@code non-null;} instance representing
126 * {@code java.lang.annotation.Annotation}
128 public static final Type ANNOTATION =
129 intern("Ljava/lang/annotation/Annotation;");
131 /** {@code non-null;} instance representing {@code java.lang.Class} */
132 public static final Type CLASS = intern("Ljava/lang/Class;");
134 /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
135 public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
137 /** {@code non-null;} instance representing {@code java.lang.Object} */
138 public static final Type OBJECT = intern("Ljava/lang/Object;");
140 /** {@code non-null;} instance representing {@code java.io.Serializable} */
141 public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
143 /** {@code non-null;} instance representing {@code java.lang.String} */
144 public static final Type STRING = intern("Ljava/lang/String;");
146 /** {@code non-null;} instance representing {@code java.lang.Throwable} */
147 public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
150 * {@code non-null;} instance representing {@code java.lang.Boolean}; the
151 * suffix on the name helps disambiguate this from the instance
152 * representing a primitive type
154 public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;");
157 * {@code non-null;} instance representing {@code java.lang.Byte}; the
158 * suffix on the name helps disambiguate this from the instance
159 * representing a primitive type
161 public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;");
164 * {@code non-null;} instance representing {@code java.lang.Character}; the
165 * suffix on the name helps disambiguate this from the instance
166 * representing a primitive type
168 public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;");
171 * {@code non-null;} instance representing {@code java.lang.Double}; the
172 * suffix on the name helps disambiguate this from the instance
173 * representing a primitive type
175 public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;");
178 * {@code non-null;} instance representing {@code java.lang.Float}; the
179 * suffix on the name helps disambiguate this from the instance
180 * representing a primitive type
182 public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;");
185 * {@code non-null;} instance representing {@code java.lang.Integer}; the
186 * suffix on the name helps disambiguate this from the instance
187 * representing a primitive type
189 public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;");
192 * {@code non-null;} instance representing {@code java.lang.Long}; the
193 * suffix on the name helps disambiguate this from the instance
194 * representing a primitive type
196 public static final Type LONG_CLASS = intern("Ljava/lang/Long;");
199 * {@code non-null;} instance representing {@code java.lang.Short}; the
200 * suffix on the name helps disambiguate this from the instance
201 * representing a primitive type
203 public static final Type SHORT_CLASS = intern("Ljava/lang/Short;");
206 * {@code non-null;} instance representing {@code java.lang.Void}; the
207 * suffix on the name helps disambiguate this from the instance
208 * representing a primitive type
210 public static final Type VOID_CLASS = intern("Ljava/lang/Void;");
212 /** {@code non-null;} instance representing {@code boolean[]} */
213 public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
215 /** {@code non-null;} instance representing {@code byte[]} */
216 public static final Type BYTE_ARRAY = BYTE.getArrayType();
218 /** {@code non-null;} instance representing {@code char[]} */
219 public static final Type CHAR_ARRAY = CHAR.getArrayType();
221 /** {@code non-null;} instance representing {@code double[]} */
222 public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
224 /** {@code non-null;} instance representing {@code float[]} */
225 public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
227 /** {@code non-null;} instance representing {@code int[]} */
228 public static final Type INT_ARRAY = INT.getArrayType();
230 /** {@code non-null;} instance representing {@code long[]} */
231 public static final Type LONG_ARRAY = LONG.getArrayType();
233 /** {@code non-null;} instance representing {@code Object[]} */
234 public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
236 /** {@code non-null;} instance representing {@code short[]} */
237 public static final Type SHORT_ARRAY = SHORT.getArrayType();
239 /** {@code non-null;} field descriptor for the type */
240 private final String descriptor;
243 * basic type corresponding to this type; one of the
244 * {@code BT_*} constants
246 private final int basicType;
249 * {@code >= -1;} for an uninitialized type, bytecode index that this
250 * instance was allocated at; {@code Integer.MAX_VALUE} if it
251 * was an incoming uninitialized instance; {@code -1} if this
252 * is an <i>inititialized</i> instance
254 private final int newAt;
257 * {@code null-ok;} the internal-form class name corresponding to
258 * this type, if calculated; only valid if {@code this} is a
259 * reference type and additionally not a return address
261 private String className;
264 * {@code null-ok;} the type corresponding to an array of this type, if
267 private Type arrayType;
270 * {@code null-ok;} the type corresponding to elements of this type, if
271 * calculated; only valid if {@code this} is an array type
273 private Type componentType;
276 * {@code null-ok;} the type corresponding to the initialized version of
277 * this type, if this instance is in fact an uninitialized type
279 private Type initializedType;
282 * Returns the unique instance corresponding to the type with the
283 * given descriptor. See vmspec-2 sec4.3.2 for details on the
284 * field descriptor syntax. This method does <i>not</i> allow
285 * {@code "V"} (that is, type {@code void}) as a valid
288 * @param descriptor {@code non-null;} the descriptor
289 * @return {@code non-null;} the corresponding instance
290 * @throws IllegalArgumentException thrown if the descriptor has
293 public static Type intern(String descriptor) {
295 synchronized (internTable) {
296 result = internTable.get(descriptor);
298 if (result != null) {
304 firstChar = descriptor.charAt(0);
305 } catch (IndexOutOfBoundsException ex) {
306 // Translate the exception.
307 throw new IllegalArgumentException("descriptor is empty");
308 } catch (NullPointerException ex) {
309 // Elucidate the exception.
310 throw new NullPointerException("descriptor == null");
313 if (firstChar == '[') {
315 * Recursively strip away array markers to get at the underlying
316 * type, and build back on to form the result.
318 result = intern(descriptor.substring(1));
319 return result.getArrayType();
323 * If the first character isn't '[' and it wasn't found in the
324 * intern cache, then it had better be the descriptor for a class.
327 int length = descriptor.length();
328 if ((firstChar != 'L') ||
329 (descriptor.charAt(length - 1) != ';')) {
330 throw new IllegalArgumentException("bad descriptor: " + descriptor);
334 * Validate the characters of the class name itself. Note that
335 * vmspec-2 does not have a coherent definition for valid
336 * internal-form class names, and the definition here is fairly
337 * liberal: A name is considered valid as long as it doesn't
338 * contain any of '[' ';' '.' '(' ')', and it has no more than one
339 * '/' in a row, and no '/' at either end.
342 int limit = (length - 1); // Skip the final ';'.
343 for (int i = 1; i < limit; i++) {
344 char c = descriptor.charAt(i);
351 throw new IllegalArgumentException("bad descriptor: " + descriptor);
355 (i == (length - 1)) ||
356 (descriptor.charAt(i - 1) == '/')) {
357 throw new IllegalArgumentException("bad descriptor: " + descriptor);
364 result = new Type(descriptor, BT_OBJECT);
365 return putIntern(result);
369 * Returns the unique instance corresponding to the type with the
370 * given descriptor, allowing {@code "V"} to return the type
371 * for {@code void}. Other than that one caveat, this method
372 * is identical to {@link #intern}.
374 * @param descriptor {@code non-null;} the descriptor
375 * @return {@code non-null;} the corresponding instance
376 * @throws IllegalArgumentException thrown if the descriptor has
379 public static Type internReturnType(String descriptor) {
381 if (descriptor.equals("V")) {
382 // This is the one special case where void may be returned.
385 } catch (NullPointerException ex) {
386 // Elucidate the exception.
387 throw new NullPointerException("descriptor == null");
390 return intern(descriptor);
394 * Returns the unique instance corresponding to the type of the
395 * class with the given name. Calling this method is equivalent to
396 * calling {@code intern(name)} if {@code name} begins
397 * with {@code "["} and calling {@code intern("L" + name + ";")}
398 * in all other cases.
400 * @param name {@code non-null;} the name of the class whose type
402 * @return {@code non-null;} the corresponding type
403 * @throws IllegalArgumentException thrown if the name has
406 public static Type internClassName(String name) {
408 throw new NullPointerException("name == null");
411 if (name.startsWith("[")) {
415 return intern('L' + name + ';');
419 * Constructs an instance corresponding to an "uninitialized type."
420 * This is a private constructor; use one of the public static
421 * methods to get instances.
423 * @param descriptor {@code non-null;} the field descriptor for the type
424 * @param basicType basic type corresponding to this type; one of the
425 * {@code BT_*} constants
426 * @param newAt {@code >= -1;} allocation bytecode index
428 private Type(String descriptor, int basicType, int newAt) {
429 if (descriptor == null) {
430 throw new NullPointerException("descriptor == null");
433 if ((basicType < 0) || (basicType >= BT_COUNT)) {
434 throw new IllegalArgumentException("bad basicType");
438 throw new IllegalArgumentException("newAt < -1");
441 this.descriptor = descriptor;
442 this.basicType = basicType;
444 this.arrayType = null;
445 this.componentType = null;
446 this.initializedType = null;
450 * Constructs an instance corresponding to an "initialized type."
451 * This is a private constructor; use one of the public static
452 * methods to get instances.
454 * @param descriptor {@code non-null;} the field descriptor for the type
455 * @param basicType basic type corresponding to this type; one of the
456 * {@code BT_*} constants
458 private Type(String descriptor, int basicType) {
459 this(descriptor, basicType, -1);
464 public boolean equals(Object other) {
467 * Since externally-visible types are interned, this check
468 * helps weed out some easy cases.
473 if (!(other instanceof Type)) {
477 return descriptor.equals(((Type) other).descriptor);
482 public int hashCode() {
483 return descriptor.hashCode();
487 public int compareTo(Type other) {
488 return descriptor.compareTo(other.descriptor);
493 public String toString() {
498 public String toHuman() {
500 case BT_VOID: return "void";
501 case BT_BOOLEAN: return "boolean";
502 case BT_BYTE: return "byte";
503 case BT_CHAR: return "char";
504 case BT_DOUBLE: return "double";
505 case BT_FLOAT: return "float";
506 case BT_INT: return "int";
507 case BT_LONG: return "long";
508 case BT_SHORT: return "short";
509 case BT_OBJECT: break;
510 default: return descriptor;
514 return getComponentType().toHuman() + "[]";
517 // Remove the "L...;" around the type and convert "/" to ".".
518 return getClassName().replace("/", ".");
522 public Type getType() {
527 public Type getFrameType() {
542 public int getBasicType() {
547 public int getBasicFrameType() {
562 public boolean isConstant() {
567 * Gets the descriptor.
569 * @return {@code non-null;} the descriptor
571 public String getDescriptor() {
576 * Gets the name of the class this type corresponds to, in internal
577 * form. This method is only valid if this instance is for a
578 * normal reference type (that is, a reference type and
579 * additionally not a return address).
581 * @return {@code non-null;} the internal-form class name
583 public String getClassName() {
584 if (className == null) {
585 if (!isReference()) {
586 throw new IllegalArgumentException("not an object type: " +
590 if (descriptor.charAt(0) == '[') {
591 className = descriptor;
593 className = descriptor.substring(1, descriptor.length() - 1);
601 * Gets the category. Most instances are category 1. {@code long}
602 * and {@code double} are the only category 2 types.
606 * @return the category
608 public int getCategory() {
620 * Returns whether or not this is a category 1 type.
624 * @return whether or not this is a category 1 type
626 public boolean isCategory1() {
638 * Returns whether or not this is a category 2 type.
642 * @return whether or not this is a category 2 type
644 public boolean isCategory2() {
656 * Gets whether this type is "intlike." An intlike type is one which, when
657 * placed on a stack or in a local, is automatically converted to an
660 * @return whether this type is "intlike"
662 public boolean isIntlike() {
677 * Gets whether this type is a primitive type. All types are either
678 * primitive or reference types.
680 * @return whether this type is primitive
682 public boolean isPrimitive() {
701 * Gets whether this type is a normal reference type. A normal
702 * reference type is a reference type that is not a return
703 * address. This method is just convenient shorthand for
704 * {@code getBasicType() == Type.BT_OBJECT}.
706 * @return whether this type is a normal reference type
708 public boolean isReference() {
709 return (basicType == BT_OBJECT);
713 * Gets whether this type is an array type. If this method returns
714 * {@code true}, then it is safe to use {@link #getComponentType}
715 * to determine the component type.
717 * @return whether this type is an array type
719 public boolean isArray() {
720 return (descriptor.charAt(0) == '[');
724 * Gets whether this type is an array type or is a known-null, and
725 * hence is compatible with array types.
727 * @return whether this type is an array type
729 public boolean isArrayOrKnownNull() {
730 return isArray() || equals(KNOWN_NULL);
734 * Gets whether this type represents an uninitialized instance. An
735 * uninitialized instance is what one gets back from the {@code new}
736 * opcode, and remains uninitialized until a valid constructor is
739 * @return whether this type is "uninitialized"
741 public boolean isUninitialized() {
746 * Gets the bytecode index at which this uninitialized type was
747 * allocated. This returns {@code Integer.MAX_VALUE} if this
748 * type is an uninitialized incoming parameter (i.e., the
749 * {@code this} of an {@code <init>} method) or
750 * {@code -1} if this type is in fact <i>initialized</i>.
752 * @return {@code >= -1;} the allocation bytecode index
754 public int getNewAt() {
759 * Gets the initialized type corresponding to this instance, but only
760 * if this instance is in fact an uninitialized object type.
762 * @return {@code non-null;} the initialized type
764 public Type getInitializedType() {
765 if (initializedType == null) {
766 throw new IllegalArgumentException("initialized type: " +
770 return initializedType;
774 * Gets the type corresponding to an array of this type.
776 * @return {@code non-null;} the array type
778 public Type getArrayType() {
779 if (arrayType == null) {
780 arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT));
787 * Gets the component type of this type. This method is only valid on
790 * @return {@code non-null;} the component type
792 public Type getComponentType() {
793 if (componentType == null) {
794 if (descriptor.charAt(0) != '[') {
795 throw new IllegalArgumentException("not an array type: " +
798 componentType = intern(descriptor.substring(1));
801 return componentType;
805 * Returns a new interned instance which is identical to this one, except
806 * it is indicated as uninitialized and allocated at the given bytecode
807 * index. This instance must be an initialized object type.
809 * @param newAt {@code >= 0;} the allocation bytecode index
810 * @return {@code non-null;} an appropriately-constructed instance
812 public Type asUninitialized(int newAt) {
814 throw new IllegalArgumentException("newAt < 0");
817 if (!isReference()) {
818 throw new IllegalArgumentException("not a reference type: " +
822 if (isUninitialized()) {
824 * Dealing with uninitialized types as a starting point is
825 * a pain, and it's not clear that it'd ever be used, so
828 throw new IllegalArgumentException("already uninitialized: " +
833 * Create a new descriptor that is unique and shouldn't conflict
834 * with "normal" type descriptors
836 String newDesc = 'N' + Hex.u2(newAt) + descriptor;
837 Type result = new Type(newDesc, BT_OBJECT, newAt);
838 result.initializedType = this;
839 return putIntern(result);
843 * Puts the given instance in the intern table if it's not already
844 * there. If a conflicting value is already in the table, then leave it.
845 * Return the interned value.
847 * @param type {@code non-null;} instance to make interned
848 * @return {@code non-null;} the actual interned object
850 private static Type putIntern(Type type) {
851 synchronized (internTable) {
852 String descriptor = type.getDescriptor();
853 Type already = internTable.get(descriptor);
854 if (already != null) {
857 internTable.put(descriptor, type);