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
17package com.android.dexgen.rop.type;
18
19import com.android.dexgen.util.Hex;
20
21import 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 */
29public 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         */
129        CLASS_TYPE_MAP.put(boolean.class, BOOLEAN);
130        CLASS_TYPE_MAP.put(short.class, SHORT);
131        CLASS_TYPE_MAP.put(int.class, INT);
132        CLASS_TYPE_MAP.put(long.class, LONG);
133        CLASS_TYPE_MAP.put(char.class, CHAR);
134        CLASS_TYPE_MAP.put(byte.class, BYTE);
135        CLASS_TYPE_MAP.put(float.class, FLOAT);
136        CLASS_TYPE_MAP.put(double.class, DOUBLE);
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
525    private Type(String descriptor, int basicType) {
526        this(descriptor, basicType, -1);
527    }
528
529    /** {@inheritDoc} */
530    @Override
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
549    public int hashCode() {
550        return descriptor.hashCode();
551    }
552
553    /** {@inheritDoc} */
554    public int compareTo(Type other) {
555        return descriptor.compareTo(other.descriptor);
556    }
557
558    /** {@inheritDoc} */
559    @Override
560    public String toString() {
561        return descriptor;
562    }
563
564    /** {@inheritDoc} */
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} */
589    public Type getType() {
590        return this;
591    }
592
593    /** {@inheritDoc} */
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} */
609    public int getBasicType() {
610        return basicType;
611    }
612
613    /** {@inheritDoc} */
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} */
629    public boolean isConstant() {
630        return false;
631    }
632
633    /**
634     * Gets the descriptor.
635     *
636     * @return {@code non-null;} the descriptor
637     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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}