xref: /aosp_15_r20/dalvik/dexgen/src/com/android/dexgen/rop/type/Type.java (revision 055d459012065f78d96b68be8421640240ddf631)
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.dexgen.rop.type;
18 
19 import com.android.dexgen.util.Hex;
20 
21 import java.util.HashMap;
22 
23 /**
24  * Representation of a value type, such as may appear in a field, in a
25  * local, on a stack, or in a method descriptor. Instances of this
26  * class are generally interned and may be usefully compared with each
27  * other using {@code ==}.
28  */
29 public final class Type implements TypeBearer, Comparable<Type> {
30     /** {@code non-null;} intern table mapping string descriptors to instances */
31     private static final HashMap<String, Type> internTable =
32         new HashMap<String, Type>(500);
33 
34     /** {@code non-null;} table mapping types as {@code Class} objects to internal form */
35     private static final HashMap<Class, Type> CLASS_TYPE_MAP =
36         new HashMap<Class, Type>();
37 
38     /** basic type constant for {@code void} */
39     public static final int BT_VOID = 0;
40 
41     /** basic type constant for {@code boolean} */
42     public static final int BT_BOOLEAN = 1;
43 
44     /** basic type constant for {@code byte} */
45     public static final int BT_BYTE = 2;
46 
47     /** basic type constant for {@code char} */
48     public static final int BT_CHAR = 3;
49 
50     /** basic type constant for {@code double} */
51     public static final int BT_DOUBLE = 4;
52 
53     /** basic type constant for {@code float} */
54     public static final int BT_FLOAT = 5;
55 
56     /** basic type constant for {@code int} */
57     public static final int BT_INT = 6;
58 
59     /** basic type constant for {@code long} */
60     public static final int BT_LONG = 7;
61 
62     /** basic type constant for {@code short} */
63     public static final int BT_SHORT = 8;
64 
65     /** basic type constant for {@code Object} */
66     public static final int BT_OBJECT = 9;
67 
68     /** basic type constant for a return address */
69     public static final int BT_ADDR = 10;
70 
71     /** count of basic type constants */
72     public static final int BT_COUNT = 11;
73 
74     /** {@code non-null;} instance representing {@code boolean} */
75     public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
76 
77     /** {@code non-null;} instance representing {@code byte} */
78     public static final Type BYTE = new Type("B", BT_BYTE);
79 
80     /** {@code non-null;} instance representing {@code char} */
81     public static final Type CHAR = new Type("C", BT_CHAR);
82 
83     /** {@code non-null;} instance representing {@code double} */
84     public static final Type DOUBLE = new Type("D", BT_DOUBLE);
85 
86     /** {@code non-null;} instance representing {@code float} */
87     public static final Type FLOAT = new Type("F", BT_FLOAT);
88 
89     /** {@code non-null;} instance representing {@code int} */
90     public static final Type INT = new Type("I", BT_INT);
91 
92     /** {@code non-null;} instance representing {@code long} */
93     public static final Type LONG = new Type("J", BT_LONG);
94 
95     /** {@code non-null;} instance representing {@code short} */
96     public static final Type SHORT = new Type("S", BT_SHORT);
97 
98     /** {@code non-null;} instance representing {@code void} */
99     public static final Type VOID = new Type("V", BT_VOID);
100 
101     /** {@code non-null;} instance representing a known-{@code null} */
102     public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
103 
104     /** {@code non-null;} instance representing a subroutine return address */
105     public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
106 
107     static {
108         /*
109          * Put all the primitive types into the intern table. This needs
110          * to happen before the array types below get interned.
111          */
112         putIntern(BOOLEAN);
113         putIntern(BYTE);
114         putIntern(CHAR);
115         putIntern(DOUBLE);
116         putIntern(FLOAT);
117         putIntern(INT);
118         putIntern(LONG);
119         putIntern(SHORT);
120         /*
121          * Note: VOID isn't put in the intern table, since it's special and
122          * shouldn't be found by a normal call to intern().
123          */
124 
125         /*
126          * Create a mapping between types as Java Class objects
127          * and types in dx internal format.
128          */
CLASS_TYPE_MAP.put(boolean.class, BOOLEAN)129         CLASS_TYPE_MAP.put(boolean.class, BOOLEAN);
CLASS_TYPE_MAP.put(short.class, SHORT)130         CLASS_TYPE_MAP.put(short.class, SHORT);
CLASS_TYPE_MAP.put(int.class, INT)131         CLASS_TYPE_MAP.put(int.class, INT);
CLASS_TYPE_MAP.put(long.class, LONG)132         CLASS_TYPE_MAP.put(long.class, LONG);
CLASS_TYPE_MAP.put(char.class, CHAR)133         CLASS_TYPE_MAP.put(char.class, CHAR);
CLASS_TYPE_MAP.put(byte.class, BYTE)134         CLASS_TYPE_MAP.put(byte.class, BYTE);
CLASS_TYPE_MAP.put(float.class, FLOAT)135         CLASS_TYPE_MAP.put(float.class, FLOAT);
CLASS_TYPE_MAP.put(double.class, DOUBLE)136         CLASS_TYPE_MAP.put(double.class, DOUBLE);
CLASS_TYPE_MAP.put(void.class, VOID)137         CLASS_TYPE_MAP.put(void.class, VOID);
138     }
139 
140     /**
141      * {@code non-null;} instance representing
142      * {@code java.lang.annotation.Annotation}
143      */
144     public static final Type ANNOTATION =
145         intern("Ljava/lang/annotation/Annotation;");
146 
147     /** {@code non-null;} instance representing {@code java.lang.Class} */
148     public static final Type CLASS = intern("Ljava/lang/Class;");
149 
150     /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
151     public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
152 
153     /** {@code non-null;} instance representing {@code java.lang.Object} */
154     public static final Type OBJECT = intern("Ljava/lang/Object;");
155 
156     /** {@code non-null;} instance representing {@code java.io.Serializable} */
157     public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
158 
159     /** {@code non-null;} instance representing {@code java.lang.String} */
160     public static final Type STRING = intern("Ljava/lang/String;");
161 
162     /** {@code non-null;} instance representing {@code java.lang.Throwable} */
163     public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
164 
165     /**
166      * {@code non-null;} instance representing {@code java.lang.Boolean}; the
167      * suffix on the name helps disambiguate this from the instance
168      * representing a primitive type
169      */
170     public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;");
171 
172     /**
173      * {@code non-null;} instance representing {@code java.lang.Byte}; the
174      * suffix on the name helps disambiguate this from the instance
175      * representing a primitive type
176      */
177     public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;");
178 
179     /**
180      * {@code non-null;} instance representing {@code java.lang.Character}; the
181      * suffix on the name helps disambiguate this from the instance
182      * representing a primitive type
183      */
184     public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;");
185 
186     /**
187      * {@code non-null;} instance representing {@code java.lang.Double}; the
188      * suffix on the name helps disambiguate this from the instance
189      * representing a primitive type
190      */
191     public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;");
192 
193     /**
194      * {@code non-null;} instance representing {@code java.lang.Float}; the
195      * suffix on the name helps disambiguate this from the instance
196      * representing a primitive type
197      */
198     public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;");
199 
200     /**
201      * {@code non-null;} instance representing {@code java.lang.Integer}; the
202      * suffix on the name helps disambiguate this from the instance
203      * representing a primitive type
204      */
205     public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;");
206 
207     /**
208      * {@code non-null;} instance representing {@code java.lang.Long}; the
209      * suffix on the name helps disambiguate this from the instance
210      * representing a primitive type
211      */
212     public static final Type LONG_CLASS = intern("Ljava/lang/Long;");
213 
214     /**
215      * {@code non-null;} instance representing {@code java.lang.Short}; the
216      * suffix on the name helps disambiguate this from the instance
217      * representing a primitive type
218      */
219     public static final Type SHORT_CLASS = intern("Ljava/lang/Short;");
220 
221     /**
222      * {@code non-null;} instance representing {@code java.lang.Void}; the
223      * suffix on the name helps disambiguate this from the instance
224      * representing a primitive type
225      */
226     public static final Type VOID_CLASS = intern("Ljava/lang/Void;");
227 
228     /** {@code non-null;} instance representing {@code boolean[]} */
229     public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
230 
231     /** {@code non-null;} instance representing {@code byte[]} */
232     public static final Type BYTE_ARRAY = BYTE.getArrayType();
233 
234     /** {@code non-null;} instance representing {@code char[]} */
235     public static final Type CHAR_ARRAY = CHAR.getArrayType();
236 
237     /** {@code non-null;} instance representing {@code double[]} */
238     public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
239 
240     /** {@code non-null;} instance representing {@code float[]} */
241     public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
242 
243     /** {@code non-null;} instance representing {@code int[]} */
244     public static final Type INT_ARRAY = INT.getArrayType();
245 
246     /** {@code non-null;} instance representing {@code long[]} */
247     public static final Type LONG_ARRAY = LONG.getArrayType();
248 
249     /** {@code non-null;} instance representing {@code Object[]} */
250     public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
251 
252     /** {@code non-null;} instance representing {@code short[]} */
253     public static final Type SHORT_ARRAY = SHORT.getArrayType();
254 
255     /** {@code non-null;} field descriptor for the type */
256     private final String descriptor;
257 
258     /**
259      * basic type corresponding to this type; one of the
260      * {@code BT_*} constants
261      */
262     private final int basicType;
263 
264     /**
265      * {@code >= -1;} for an uninitialized type, bytecode index that this
266      * instance was allocated at; {@code Integer.MAX_VALUE} if it
267      * was an incoming uninitialized instance; {@code -1} if this
268      * is an <i>inititialized</i> instance
269      */
270     private final int newAt;
271 
272     /**
273      * {@code null-ok;} the internal-form class name corresponding to this type, if
274      * calculated; only valid if {@code this} is a reference type and
275      * additionally not a return address
276      */
277     private String className;
278 
279     /**
280      * {@code null-ok;} the type corresponding to an array of this type, if
281      * calculated
282      */
283     private Type arrayType;
284 
285     /**
286      * {@code null-ok;} the type corresponding to elements of this type, if
287      * calculated; only valid if {@code this} is an array type
288      */
289     private Type componentType;
290 
291     /**
292      * {@code null-ok;} the type corresponding to the initialized version of
293      * this type, if this instance is in fact an uninitialized type
294      */
295     private Type initializedType;
296 
297     /**
298      * Returns the unique instance corresponding to the type represented by
299      * given {@code Class} object. See vmspec-2 sec4.3.2 for details on the
300      * field descriptor syntax. This method does <i>not</i> allow
301      * {@code "V"} (that is, type {@code void}) as a valid
302      * descriptor.
303      *
304      * @param clazz {@code non-null;} class whose descriptor
305      * will be internalized
306      * @return {@code non-null;} the corresponding instance
307      */
intern(Class clazz)308     public static Type intern(Class clazz) {
309         return intern(getInternalTypeName(clazz));
310     }
311 
312     /**
313      * Returns the unique instance corresponding to the type with the
314      * given descriptor. See vmspec-2 sec4.3.2 for details on the
315      * field descriptor syntax. This method does <i>not</i> allow
316      * {@code "V"} (that is, type {@code void}) as a valid
317      * descriptor.
318      *
319      * @param descriptor {@code non-null;} the descriptor
320      * @return {@code non-null;} the corresponding instance
321      * @throws IllegalArgumentException thrown if the descriptor has
322      * invalid syntax
323      */
intern(String descriptor)324     public static Type intern(String descriptor) {
325 
326         Type result = internTable.get(descriptor);
327         if (result != null) {
328             return result;
329         }
330 
331         char firstChar;
332         try {
333             firstChar = descriptor.charAt(0);
334         } catch (IndexOutOfBoundsException ex) {
335             // Translate the exception.
336             throw new IllegalArgumentException("descriptor is empty");
337         } catch (NullPointerException ex) {
338             // Elucidate the exception.
339             throw new NullPointerException("descriptor == null");
340         }
341 
342         if (firstChar == '[') {
343             /*
344              * Recursively strip away array markers to get at the underlying
345              * type, and build back on to form the result.
346              */
347             result = intern(descriptor.substring(1));
348             return result.getArrayType();
349         }
350 
351         /*
352          * If the first character isn't '[' and it wasn't found in the
353          * intern cache, then it had better be the descriptor for a class.
354          */
355 
356         int length = descriptor.length();
357         if ((firstChar != 'L') ||
358             (descriptor.charAt(length - 1) != ';')) {
359             throw new IllegalArgumentException("bad descriptor" + descriptor);
360         }
361 
362         /*
363          * Validate the characters of the class name itself. Note that
364          * vmspec-2 does not have a coherent definition for valid
365          * internal-form class names, and the definition here is fairly
366          * liberal: A name is considered valid as long as it doesn't
367          * contain any of '[' ';' '.' '(' ')', and it has no more than one
368          * '/' in a row, and no '/' at either end.
369          */
370 
371         int limit = (length - 1); // Skip the final ';'.
372         for (int i = 1; i < limit; i++) {
373             char c = descriptor.charAt(i);
374             switch (c) {
375                 case '[':
376                 case ';':
377                 case '.':
378                 case '(':
379                 case ')': {
380                     throw new IllegalArgumentException("bad descriptor" + descriptor);
381                 }
382                 case '/': {
383                     if ((i == 1) ||
384                         (i == (length - 1)) ||
385                         (descriptor.charAt(i - 1) == '/')) {
386                         throw new IllegalArgumentException("bad descriptor");
387                     }
388                     break;
389                 }
390             }
391         }
392 
393         result = new Type(descriptor, BT_OBJECT);
394         return putIntern(result);
395     }
396 
397     /**
398      * Returns the unique instance corresponding to the type represented by
399      * given {@code Class} object, allowing {@code "V"} to return the type
400      * for {@code void}. Other than that one caveat, this method
401      * is identical to {@link #intern}.
402      *
403      * @param clazz {@code non-null;} class which descriptor
404      * will be internalized
405      * @return {@code non-null;} the corresponding instance
406      */
internReturnType(Class clazz)407     public static Type internReturnType(Class clazz) {
408         return internReturnType(getInternalTypeName(clazz));
409     }
410 
411     /**
412      * Returns the unique instance corresponding to the type with the
413      * given descriptor, allowing {@code "V"} to return the type
414      * for {@code void}. Other than that one caveat, this method
415      * is identical to {@link #intern}.
416      *
417      * @param descriptor {@code non-null;} the descriptor
418      * @return {@code non-null;} the corresponding instance
419      * @throws IllegalArgumentException thrown if the descriptor has
420      * invalid syntax
421      */
internReturnType(String descriptor)422     public static Type internReturnType(String descriptor) {
423         try {
424             if (descriptor.equals("V")) {
425                 // This is the one special case where void may be returned.
426                 return VOID;
427             }
428         } catch (NullPointerException ex) {
429             // Elucidate the exception.
430             throw new NullPointerException("descriptor == null");
431         }
432 
433         return intern(descriptor);
434     }
435 
436     /**
437      * Returns the unique instance corresponding to the type of the
438      * class with the given name. Calling this method is equivalent to
439      * calling {@code intern(name)} if {@code name} begins
440      * with {@code "["} and calling {@code intern("L" + name + ";")}
441      * in all other cases.
442      *
443      * @param name {@code non-null;} the name of the class whose type is desired
444      * @return {@code non-null;} the corresponding type
445      * @throws IllegalArgumentException thrown if the name has
446      * invalid syntax
447      */
internClassName(String name)448     public static Type internClassName(String name) {
449         if (name == null) {
450             throw new NullPointerException("name == null");
451         }
452 
453         if (name.startsWith("[")) {
454             return intern(name);
455         }
456 
457         return intern('L' + name + ';');
458     }
459 
460     /**
461      * Converts type name in the format as returned by reflection
462      * into dex internal form.
463      *
464      * @param clazz {@code non-null;} class whose name will be internalized
465      * @return string with the type name in dex internal format
466      */
getInternalTypeName(Class clazz)467     public static String getInternalTypeName(Class clazz) {
468         if (clazz == null) {
469             throw new NullPointerException("clazz == null");
470         }
471 
472         if (clazz.isPrimitive()) {
473             return CLASS_TYPE_MAP.get(clazz).getDescriptor();
474         }
475 
476         String slashed = clazz.getName().replace('.', '/');
477 
478         if (clazz.isArray()) {
479             return slashed;
480         }
481 
482         return 'L' + slashed + ';';
483     }
484 
485     /**
486      * Constructs an instance corresponding to an "uninitialized type."
487      * This is a private constructor; use one of the public static
488      * methods to get instances.
489      *
490      * @param descriptor {@code non-null;} the field descriptor for the type
491      * @param basicType basic type corresponding to this type; one of the
492      * {@code BT_*} constants
493      * @param newAt {@code >= -1;} allocation bytecode index
494      */
Type(String descriptor, int basicType, int newAt)495     private Type(String descriptor, int basicType, int newAt) {
496         if (descriptor == null) {
497             throw new NullPointerException("descriptor == null");
498         }
499 
500         if ((basicType < 0) || (basicType >= BT_COUNT)) {
501             throw new IllegalArgumentException("bad basicType");
502         }
503 
504         if (newAt < -1) {
505             throw new IllegalArgumentException("newAt < -1");
506         }
507 
508         this.descriptor = descriptor;
509         this.basicType = basicType;
510         this.newAt = newAt;
511         this.arrayType = null;
512         this.componentType = null;
513         this.initializedType = null;
514     }
515 
516     /**
517      * Constructs an instance corresponding to an "initialized type."
518      * This is a private constructor; use one of the public static
519      * methods to get instances.
520      *
521      * @param descriptor {@code non-null;} the field descriptor for the type
522      * @param basicType basic type corresponding to this type; one of the
523      * {@code BT_*} constants
524      */
Type(String descriptor, int basicType)525     private Type(String descriptor, int basicType) {
526         this(descriptor, basicType, -1);
527     }
528 
529     /** {@inheritDoc} */
530     @Override
equals(Object other)531     public boolean equals(Object other) {
532         if (this == other) {
533             /*
534              * Since externally-visible types are interned, this check
535              * helps weed out some easy cases.
536              */
537             return true;
538         }
539 
540         if (!(other instanceof Type)) {
541             return false;
542         }
543 
544         return descriptor.equals(((Type) other).descriptor);
545     }
546 
547     /** {@inheritDoc} */
548     @Override
hashCode()549     public int hashCode() {
550         return descriptor.hashCode();
551     }
552 
553     /** {@inheritDoc} */
compareTo(Type other)554     public int compareTo(Type other) {
555         return descriptor.compareTo(other.descriptor);
556     }
557 
558     /** {@inheritDoc} */
559     @Override
toString()560     public String toString() {
561         return descriptor;
562     }
563 
564     /** {@inheritDoc} */
toHuman()565     public String toHuman() {
566         switch (basicType) {
567             case BT_VOID:    return "void";
568             case BT_BOOLEAN: return "boolean";
569             case BT_BYTE:    return "byte";
570             case BT_CHAR:    return "char";
571             case BT_DOUBLE:  return "double";
572             case BT_FLOAT:   return "float";
573             case BT_INT:     return "int";
574             case BT_LONG:    return "long";
575             case BT_SHORT:   return "short";
576             case BT_OBJECT:  break;
577             default:         return descriptor;
578         }
579 
580         if (isArray()) {
581             return getComponentType().toHuman() + "[]";
582         }
583 
584         // Remove the "L...;" around the type and convert "/" to ".".
585         return getClassName().replace("/", ".");
586     }
587 
588     /** {@inheritDoc} */
getType()589     public Type getType() {
590         return this;
591     }
592 
593     /** {@inheritDoc} */
getFrameType()594     public Type getFrameType() {
595         switch (basicType) {
596             case BT_BOOLEAN:
597             case BT_BYTE:
598             case BT_CHAR:
599             case BT_INT:
600             case BT_SHORT: {
601                 return INT;
602             }
603         }
604 
605         return this;
606     }
607 
608     /** {@inheritDoc} */
getBasicType()609     public int getBasicType() {
610         return basicType;
611     }
612 
613     /** {@inheritDoc} */
getBasicFrameType()614     public int getBasicFrameType() {
615         switch (basicType) {
616             case BT_BOOLEAN:
617             case BT_BYTE:
618             case BT_CHAR:
619             case BT_INT:
620             case BT_SHORT: {
621                 return BT_INT;
622             }
623         }
624 
625         return basicType;
626     }
627 
628     /** {@inheritDoc} */
isConstant()629     public boolean isConstant() {
630         return false;
631     }
632 
633     /**
634      * Gets the descriptor.
635      *
636      * @return {@code non-null;} the descriptor
637      */
getDescriptor()638     public String getDescriptor() {
639         return descriptor;
640     }
641 
642     /**
643      * Gets the name of the class this type corresponds to, in internal
644      * form. This method is only valid if this instance is for a
645      * normal reference type (that is, a reference type and
646      * additionally not a return address).
647      *
648      * @return {@code non-null;} the internal-form class name
649      */
getClassName()650     public String getClassName() {
651         if (className == null) {
652             if (!isReference()) {
653                 throw new IllegalArgumentException("not an object type: " +
654                                                    descriptor);
655             }
656 
657             if (descriptor.charAt(0) == '[') {
658                 className = descriptor;
659             } else {
660                 className = descriptor.substring(1, descriptor.length() - 1);
661             }
662         }
663 
664         return className;
665     }
666 
667     /**
668      * Gets the category. Most instances are category 1. {@code long}
669      * and {@code double} are the only category 2 types.
670      *
671      * @see #isCategory1
672      * @see #isCategory2
673      * @return the category
674      */
getCategory()675     public int getCategory() {
676         switch (basicType) {
677             case BT_LONG:
678             case BT_DOUBLE: {
679                 return 2;
680             }
681         }
682 
683         return 1;
684     }
685 
686     /**
687      * Returns whether or not this is a category 1 type.
688      *
689      * @see #getCategory
690      * @see #isCategory2
691      * @return whether or not this is a category 1 type
692      */
isCategory1()693     public boolean isCategory1() {
694         switch (basicType) {
695             case BT_LONG:
696             case BT_DOUBLE: {
697                 return false;
698             }
699         }
700 
701         return true;
702     }
703 
704     /**
705      * Returns whether or not this is a category 2 type.
706      *
707      * @see #getCategory
708      * @see #isCategory1
709      * @return whether or not this is a category 2 type
710      */
isCategory2()711     public boolean isCategory2() {
712         switch (basicType) {
713             case BT_LONG:
714             case BT_DOUBLE: {
715                 return true;
716             }
717         }
718 
719         return false;
720     }
721 
722     /**
723      * Gets whether this type is "intlike." An intlike type is one which, when
724      * placed on a stack or in a local, is automatically converted to an
725      * {@code int}.
726      *
727      * @return whether this type is "intlike"
728      */
isIntlike()729     public boolean isIntlike() {
730         switch (basicType) {
731             case BT_BOOLEAN:
732             case BT_BYTE:
733             case BT_CHAR:
734             case BT_INT:
735             case BT_SHORT: {
736                 return true;
737             }
738         }
739 
740         return false;
741     }
742 
743     /**
744      * Gets whether this type is a primitive type. All types are either
745      * primitive or reference types.
746      *
747      * @return whether this type is primitive
748      */
isPrimitive()749     public boolean isPrimitive() {
750         switch (basicType) {
751             case BT_BOOLEAN:
752             case BT_BYTE:
753             case BT_CHAR:
754             case BT_DOUBLE:
755             case BT_FLOAT:
756             case BT_INT:
757             case BT_LONG:
758             case BT_SHORT:
759             case BT_VOID: {
760                 return true;
761             }
762         }
763 
764         return false;
765     }
766 
767     /**
768      * Gets whether this type is a normal reference type. A normal
769      * reference type is a reference type that is not a return
770      * address. This method is just convenient shorthand for
771      * {@code getBasicType() == Type.BT_OBJECT}.
772      *
773      * @return whether this type is a normal reference type
774      */
isReference()775     public boolean isReference() {
776         return (basicType == BT_OBJECT);
777     }
778 
779     /**
780      * Gets whether this type is an array type. If this method returns
781      * {@code true}, then it is safe to use {@link #getComponentType}
782      * to determine the component type.
783      *
784      * @return whether this type is an array type
785      */
isArray()786     public boolean isArray() {
787         return (descriptor.charAt(0) == '[');
788     }
789 
790     /**
791      * Gets whether this type is an array type or is a known-null, and
792      * hence is compatible with array types.
793      *
794      * @return whether this type is an array type
795      */
isArrayOrKnownNull()796     public boolean isArrayOrKnownNull() {
797         return isArray() || equals(KNOWN_NULL);
798     }
799 
800     /**
801      * Gets whether this type represents an uninitialized instance. An
802      * uninitialized instance is what one gets back from the {@code new}
803      * opcode, and remains uninitialized until a valid constructor is
804      * invoked on it.
805      *
806      * @return whether this type is "uninitialized"
807      */
isUninitialized()808     public boolean isUninitialized() {
809         return (newAt >= 0);
810     }
811 
812     /**
813      * Gets the bytecode index at which this uninitialized type was
814      * allocated.  This returns {@code Integer.MAX_VALUE} if this
815      * type is an uninitialized incoming parameter (i.e., the
816      * {@code this} of an {@code <init>} method) or
817      * {@code -1} if this type is in fact <i>initialized</i>.
818      *
819      * @return {@code >= -1;} the allocation bytecode index
820      */
getNewAt()821     public int getNewAt() {
822         return newAt;
823     }
824 
825     /**
826      * Gets the initialized type corresponding to this instance, but only
827      * if this instance is in fact an uninitialized object type.
828      *
829      * @return {@code non-null;} the initialized type
830      */
getInitializedType()831     public Type getInitializedType() {
832         if (initializedType == null) {
833             throw new IllegalArgumentException("initialized type: " +
834                                                descriptor);
835         }
836 
837         return initializedType;
838     }
839 
840     /**
841      * Gets the type corresponding to an array of this type.
842      *
843      * @return {@code non-null;} the array type
844      */
getArrayType()845     public Type getArrayType() {
846         if (arrayType == null) {
847             arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT));
848         }
849 
850         return arrayType;
851     }
852 
853     /**
854      * Gets the component type of this type. This method is only valid on
855      * array types.
856      *
857      * @return {@code non-null;} the component type
858      */
getComponentType()859     public Type getComponentType() {
860         if (componentType == null) {
861             if (descriptor.charAt(0) != '[') {
862                 throw new IllegalArgumentException("not an array type: " +
863                                                    descriptor);
864             }
865             componentType = intern(descriptor.substring(1));
866         }
867 
868         return componentType;
869     }
870 
871     /**
872      * Returns a new interned instance which is identical to this one, except
873      * it is indicated as uninitialized and allocated at the given bytecode
874      * index. This instance must be an initialized object type.
875      *
876      * @param newAt {@code >= 0;} the allocation bytecode index
877      * @return {@code non-null;} an appropriately-constructed instance
878      */
asUninitialized(int newAt)879     public Type asUninitialized(int newAt) {
880         if (newAt < 0) {
881             throw new IllegalArgumentException("newAt < 0");
882         }
883 
884         if (!isReference()) {
885             throw new IllegalArgumentException("not a reference type: " +
886                                                descriptor);
887         }
888 
889         if (isUninitialized()) {
890             /*
891              * Dealing with uninitialized types as a starting point is
892              * a pain, and it's not clear that it'd ever be used, so
893              * just disallow it.
894              */
895             throw new IllegalArgumentException("already uninitialized: " +
896                                                descriptor);
897         }
898 
899         /*
900          * Create a new descriptor that is unique and shouldn't conflict
901          * with "normal" type descriptors
902          */
903         String newDesc = 'N' + Hex.u2(newAt) + descriptor;
904         Type result = new Type(newDesc, BT_OBJECT, newAt);
905         result.initializedType = this;
906         return putIntern(result);
907     }
908 
909     /**
910      * Puts the given instance in the intern table if it's not already
911      * there. If a conflicting value is already in the table, then leave it.
912      * Return the interned value.
913      *
914      * @param type {@code non-null;} instance to make interned
915      * @return {@code non-null;} the actual interned object
916      */
putIntern(Type type)917     private static Type putIntern(Type type) {
918         synchronized (internTable) {
919             String descriptor = type.getDescriptor();
920             Type already = internTable.get(descriptor);
921             if (already != null) {
922                 return already;
923             }
924             internTable.put(descriptor, type);
925             return type;
926         }
927     }
928 }