001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.classloader;
014    
015    import org.jikesrvm.VM;
016    import static org.jikesrvm.SizeConstants.BYTES_IN_ADDRESS;
017    
018    import org.jikesrvm.runtime.ReflectionBase;
019    import org.jikesrvm.util.ImmutableEntryHashSetRVM;
020    
021    // TODO: The following is due to a bug in checkstyle 4.3
022    // CHECKSTYLE:OFF
023    import org.vmmagic.pragma.Uninterruptible;
024    // CHECKSTYLE:ON
025    
026    /**
027     * A class to represent the reference in a class file to some
028     * type (class, primitive or array).
029     * A type reference is uniquely defined by
030     * <ul>
031     * <li> an initiating class loader
032     * <li> a type name
033     * </ul>
034     * Resolving a TypeReference to a RVMType can
035     * be an expensive operation.  Therefore we canonicalize
036     * TypeReference instances and cache the result of resolution.
037     */
038    public final class TypeReference {
039      /**
040       * The initiating class loader
041       */
042      final ClassLoader classloader;
043    
044      /**
045       * The type name. For example, the primitive type int is "I", the
046       * class java.lang.String is "Ljava/lang/String;"
047       */
048      final Atom name;
049    
050      /**
051       * The id of this type reference.
052       */
053      final int id;
054    
055      /**
056       * The RVMType instance that this type reference resolves to.
057       * Null if the reference has not yet been resolved.
058       */
059      private RVMType type;
060    
061      /**
062       * Used to canonicalize TypeReferences
063       */
064      private static final ImmutableEntryHashSetRVM<TypeReference> dictionary =
065        new ImmutableEntryHashSetRVM<TypeReference>();
066    
067      private static final ImmutableEntryHashSetRVM<ClassLoader> clDict = new ImmutableEntryHashSetRVM<ClassLoader>();
068      /**
069       * 2^LOG_ROW_SIZE is the number of elements per row
070       */
071      private static final int LOG_ROW_SIZE = 10;
072      /**
073       * Mask to ascertain row from id number
074       */
075      private static final int ROW_MASK = (1 << LOG_ROW_SIZE)-1;
076      /**
077       * Dictionary of all TypeReference instances.
078       */
079      private static TypeReference[][] types = new TypeReference[3][1<<LOG_ROW_SIZE];
080    
081      /**
082       * Used to assign Ids.  Id 0 is not used. Ids are compressed and
083       * stored in the constant pool (See {@link RVMClass}).
084       */
085      private static int nextId = 1;
086    
087      public static final TypeReference Void = findOrCreate("V");
088      public static final TypeReference Boolean = findOrCreate("Z");
089      public static final TypeReference Byte = findOrCreate("B");
090      public static final TypeReference Char = findOrCreate("C");
091      public static final TypeReference Short = findOrCreate("S");
092      public static final TypeReference Int = findOrCreate("I");
093      public static final TypeReference Long = findOrCreate("J");
094      public static final TypeReference Float = findOrCreate("F");
095      public static final TypeReference Double = findOrCreate("D");
096    
097      public static final TypeReference BooleanArray = findOrCreate("[Z");
098      public static final TypeReference ByteArray = findOrCreate("[B");
099      public static final TypeReference CharArray = findOrCreate("[C");
100      public static final TypeReference ShortArray = findOrCreate("[S");
101      public static final TypeReference IntArray = findOrCreate("[I");
102      public static final TypeReference LongArray = findOrCreate("[J");
103      public static final TypeReference FloatArray = findOrCreate("[F");
104      public static final TypeReference DoubleArray = findOrCreate("[D");
105    
106      public static final TypeReference Word = findOrCreate(org.vmmagic.unboxed.Word.class);
107      public static final TypeReference Address = findOrCreate(org.vmmagic.unboxed.Address.class);
108      public static final TypeReference ObjectReference = findOrCreate(org.vmmagic.unboxed.ObjectReference.class);
109      public static final TypeReference Offset = findOrCreate(org.vmmagic.unboxed.Offset.class);
110      public static final TypeReference Extent = findOrCreate(org.vmmagic.unboxed.Extent.class);
111      public static final TypeReference Code =
112          findOrCreate(VM.BuildForIA32 ? "Lorg/jikesrvm/ia32/Code;" : "Lorg/jikesrvm/ppc/Code;");
113      public static final TypeReference WordArray = findOrCreate(org.vmmagic.unboxed.WordArray.class);
114      public static final TypeReference AddressArray = findOrCreate(org.vmmagic.unboxed.AddressArray.class);
115      public static final TypeReference ObjectReferenceArray =
116          findOrCreate(org.vmmagic.unboxed.ObjectReferenceArray.class);
117      public static final TypeReference OffsetArray = findOrCreate(org.vmmagic.unboxed.OffsetArray.class);
118      public static final TypeReference ExtentArray = findOrCreate(org.vmmagic.unboxed.ExtentArray.class);
119      public static final TypeReference CodeArray = findOrCreate(org.jikesrvm.ArchitectureSpecific.CodeArray.class);
120      public static final TypeReference Magic = findOrCreate(org.jikesrvm.runtime.Magic.class);
121      public static final TypeReference SysCall = findOrCreate(org.vmmagic.pragma.SysCallNative.class);
122      public static final TypeReference TIB = findOrCreate(org.jikesrvm.objectmodel.TIB.class);
123      public static final TypeReference ITableArray = findOrCreate(org.jikesrvm.objectmodel.ITableArray.class);
124      public static final TypeReference ITable = findOrCreate(org.jikesrvm.objectmodel.ITable.class);
125      public static final TypeReference IMT = findOrCreate(org.jikesrvm.objectmodel.IMT.class);
126      public static final TypeReference Thread = findOrCreate(org.jikesrvm.scheduler.RVMThread.class);
127      public static final TypeReference FunctionTable = findOrCreate(org.jikesrvm.jni.FunctionTable.class);
128      public static final TypeReference LinkageTripletTable = findOrCreate(org.jikesrvm.jni.LinkageTripletTable.class);
129    
130      public static final TypeReference JavaLangObject = findOrCreate(java.lang.Object.class);
131      public static final TypeReference JavaLangClass = findOrCreate(java.lang.Class.class);
132      public static final TypeReference JavaLangString = findOrCreate(java.lang.String.class);
133      public static final TypeReference JavaLangCloneable = findOrCreate(java.lang.Cloneable.class);
134      public static final TypeReference JavaIoSerializable = findOrCreate(java.io.Serializable.class);
135      public static final TypeReference JavaLangRefReference = findOrCreate(java.lang.ref.Reference.class);
136      public static final TypeReference JavaLangSystem = findOrCreate(java.lang.System.class);
137    
138      public static final TypeReference JavaLangObjectArray = findOrCreate(java.lang.Object[].class);
139    
140      public static final TypeReference JavaLangThrowable = findOrCreate(java.lang.Throwable.class);
141      public static final TypeReference JavaLangError = findOrCreate(java.lang.Error.class);
142      public static final TypeReference JavaLangNullPointerException =
143          findOrCreate(java.lang.NullPointerException.class);
144      public static final TypeReference JavaLangArrayIndexOutOfBoundsException =
145          findOrCreate(java.lang.ArrayIndexOutOfBoundsException.class);
146      public static final TypeReference JavaLangArithmeticException = findOrCreate(java.lang.ArithmeticException.class);
147      public static final TypeReference JavaLangArrayStoreException = findOrCreate(java.lang.ArrayStoreException.class);
148      public static final TypeReference JavaLangClassCastException = findOrCreate(java.lang.ClassCastException.class);
149      public static final TypeReference JavaLangNegativeArraySizeException =
150          findOrCreate(java.lang.NegativeArraySizeException.class);
151      public static final TypeReference JavaLangIllegalMonitorStateException =
152          findOrCreate(java.lang.IllegalMonitorStateException.class);
153    
154      public static final TypeReference Type = findOrCreate(org.jikesrvm.classloader.RVMType.class);
155      public static final TypeReference Class = findOrCreate(org.jikesrvm.classloader.RVMClass.class);
156    
157      public static final TypeReference NativeBridge = findOrCreate(org.vmmagic.pragma.NativeBridge.class);
158      public static final TypeReference DynamicBridge = findOrCreate(org.vmmagic.pragma.DynamicBridge.class);
159      public static final TypeReference SaveVolatile = findOrCreate(org.vmmagic.pragma.SaveVolatile.class);
160      public static final TypeReference Interruptible = findOrCreate(org.vmmagic.pragma.Interruptible.class);
161      public static final TypeReference LogicallyUninterruptible =
162          findOrCreate(org.vmmagic.pragma.LogicallyUninterruptible.class);
163      public static final TypeReference Preemptible = findOrCreate(org.vmmagic.pragma.Preemptible.class);
164      public static final TypeReference UninterruptibleNoWarn =
165          findOrCreate(org.vmmagic.pragma.UninterruptibleNoWarn.class);
166      public static final TypeReference UnpreemptibleNoWarn =
167          findOrCreate(org.vmmagic.pragma.UnpreemptibleNoWarn.class);
168      public static final TypeReference Uninterruptible = findOrCreate(org.vmmagic.pragma.Uninterruptible.class);
169      public static final TypeReference NoCheckStore = findOrCreate(org.vmmagic.pragma.NoCheckStore.class);
170      public static final TypeReference Unpreemptible = findOrCreate(org.vmmagic.pragma.Unpreemptible.class);
171      public static final TypeReference SpecializedMethodInvoke = findOrCreate(org.vmmagic.pragma.SpecializedMethodInvoke.class);
172      public static final TypeReference Untraced = findOrCreate(org.vmmagic.pragma.Untraced.class);
173      public static final TypeReference NonMoving = findOrCreate(org.vmmagic.pragma.NonMoving.class);
174      public static final TypeReference NonMovingAllocation = findOrCreate(org.vmmagic.pragma.NonMovingAllocation.class);
175      public static final TypeReference BaselineNoRegisters = findOrCreate(org.vmmagic.pragma.BaselineNoRegisters.class);
176      public static final TypeReference BaselineSaveLSRegisters = findOrCreate(org.vmmagic.pragma.BaselineSaveLSRegisters.class);
177      public static final TypeReference ReferenceFieldsVary = findOrCreate(org.vmmagic.pragma.ReferenceFieldsVary.class);
178    
179    
180      public static final TypeReference ReferenceMaps =
181          findOrCreate(org.jikesrvm.compilers.baseline.ReferenceMaps.class);
182      public static final TypeReference JNIFunctions = findOrCreate(org.jikesrvm.jni.JNIFunctions.class);
183    
184      public static final TypeReference RVMArray = findOrCreate(org.jikesrvm.classloader.RVMArray.class);
185      /** Abstract base of reflective method invoker classes */
186      static final TypeReference baseReflectionClass = TypeReference.findOrCreate(ReflectionBase.class);
187    
188      // Synthetic types used by the opt compiler
189      public static final TypeReference NULL_TYPE =
190          (VM.BuildForOptCompiler) ? findOrCreate("Lorg/jikesrvm/classloader/TypeReference$NULL;") : null;
191      public static final TypeReference VALIDATION_TYPE =
192          (VM.BuildForOptCompiler) ? findOrCreate("Lorg/jikesrvm/classloader/TypeReference$VALIDATION;") : null;
193    
194      public static final TypeReference ExceptionTable =
195          (VM.BuildForOptCompiler) ? findOrCreate(org.jikesrvm.compilers.common.ExceptionTable.class) : null;
196    
197      public static final TypeReference OptimizationPlanner =
198          (VM.BuildForAdaptiveSystem) ? findOrCreate(org.jikesrvm.compilers.opt.driver.OptimizationPlanner.class) : null;
199    
200      /**
201       * Hash value based on name, used for canonical type dictionary
202       */
203      @Override
204      public int hashCode() {
205        return name.hashCode();
206      }
207    
208      /**
209       * Are two keys equivalent? Used for canonical type dictionary.
210       * NB ignores id value
211       */
212      @Override
213      public boolean equals(Object other) {
214        if (other instanceof TypeReference) {
215          TypeReference that = (TypeReference) other;
216          return name == that.name && classloader.equals(that.classloader);
217        } else {
218          return false;
219        }
220      }
221    
222      /**
223       * Find or create the canonical TypeReference instance for
224       * the given pair.
225       *
226       * @param cl the classloader (defining/initiating depending on usage)
227       * @param tn the name of the type
228       *
229       * @throws IllegalArgumentException Needs to throw some kind of error in
230       *  the case of a Atom that does not represent a type name.
231       */
232      public static synchronized TypeReference findOrCreate(ClassLoader cl, Atom tn) throws IllegalArgumentException {
233        TypeDescriptorParsing.validateAsTypeDescriptor(tn);
234        // Primitives, arrays of primitives, system classes and arrays of system
235        // classes must use the bootstrap classloader.  Force that here so we don't
236        // have to worry about it anywhere else in the VM.
237        ClassLoader bootstrapCL = BootstrapClassLoader.getBootstrapClassLoader();
238        if (cl == null) {
239          cl = bootstrapCL;
240        } else if (cl != bootstrapCL) {
241          if (tn.isClassDescriptor()) {
242            if (tn.isBootstrapClassDescriptor()) {
243              cl = bootstrapCL;
244            }
245          } else if (tn.isArrayDescriptor()) {
246            Atom innermostElementType = tn.parseForInnermostArrayElementDescriptor();
247            if (innermostElementType.isClassDescriptor()) {
248              if (innermostElementType.isBootstrapClassDescriptor()) {
249                cl = bootstrapCL;
250              }
251            } else {
252              cl = bootstrapCL;
253            }
254          } else {
255            cl = bootstrapCL;
256          }
257        }
258        return findOrCreateInternal(cl, tn);
259      }
260    
261      /**
262       * Shorthand for doing a find or create for a type reference that should
263       * be created using the bootstrap classloader.
264       * @param tn type name
265       */
266      public static TypeReference findOrCreate(String tn) {
267        return findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), Atom.findOrCreateAsciiAtom(tn));
268      }
269    
270      /**
271       * Convert a java.lang.Class into a type reference the slow way. For
272       * use in boot image writing
273       * @param klass java.lang.Class to convert to type reference
274       */
275      public static TypeReference findOrCreate(Class<?> klass) {
276        if (VM.runningVM) {
277          return java.lang.JikesRVMSupport.getTypeForClass(klass).getTypeRef();
278        } else {
279          String className = klass.getName();
280          if (className.startsWith("[")) {
281            // an array
282            Atom classAtom = Atom.findOrCreateAsciiAtom(className.replace('.', '/'));
283            return findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), classAtom);
284          } else {
285            // a class
286            Atom classAtom;
287            if (className.equals("int")) {
288              return TypeReference.Int;
289            } else if (className.equals("boolean")) {
290              return TypeReference.Boolean;
291            } else if (className.equals("byte")) {
292              return TypeReference.Byte;
293            } else if (className.equals("char")) {
294              return TypeReference.Char;
295            } else if (className.equals("double")) {
296              return TypeReference.Double;
297            } else if (className.equals("float")) {
298              return TypeReference.Float;
299            } else if (className.equals("long")) {
300              return TypeReference.Long;
301            } else if (className.equals("short")) {
302              return TypeReference.Short;
303            } else if (className.equals("void")) {
304              return TypeReference.Void;
305            } else {
306              classAtom = Atom.findOrCreateAsciiAtom(className.replace('.', '/'));
307            }
308            Atom classDescriptor = classAtom.descriptorFromClassName();
309            return findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), classDescriptor);
310          }
311        }
312      }
313    
314      /**
315       * Find or create the canonical TypeReference instance for
316       * the given pair without type descriptor parsing.
317       *
318       * @param cl the classloader (defining/initiating depending on usage)
319       * @param tn the name of the type
320       */
321      public static synchronized TypeReference findOrCreateInternal(ClassLoader cl, Atom tn) {
322        // Next actually findOrCreate the type reference using the proper classloader.
323        TypeReference key = new TypeReference(cl, tn, nextId);
324        TypeReference val = dictionary.get(key);
325        if (val == null) {
326          // Create type reference
327          val = key;
328          nextId++; // id of val is the nextId, move it along
329          int column = val.id >> LOG_ROW_SIZE;
330          if (column == types.length) {
331            // Grow the array of types if necessary
332            TypeReference[][] tmp = new TypeReference[column+1][];
333            for (int i=0; i < column; i++) {
334              tmp[i] = types[i];
335            }
336            types = tmp;
337            types[column] = new TypeReference[1 << LOG_ROW_SIZE];
338          }
339          types[column][val.id & ROW_MASK] = val;
340          dictionary.add(val);
341        }
342        return val;
343      }
344      private static void canonicalizeCL(ClassLoader cl) {
345        clDict.add(cl);
346      }
347      public static ImmutableEntryHashSetRVM<ClassLoader> getCLDict() { return clDict; }
348    
349      /**
350       * Constructor
351       * @param cl the classloader
352       * @param tn the type name
353       * @param id the numeric identifier
354       */
355      private TypeReference(ClassLoader cl, Atom tn, int id) {
356        canonicalizeCL(cl);
357        classloader = cl;
358        name = tn;
359        this.id = id;
360      }
361    
362      /**
363       * Get the canonical type reference given its id. The unused id of 0 will return null.
364       * @param id the type references id
365       * @return the type reference
366       */
367      @Uninterruptible
368      public static TypeReference getTypeRef(int id) {
369        return types[id >> LOG_ROW_SIZE][id & ROW_MASK];
370      }
371    
372      /**
373       * @return the classloader component of this type reference
374       */
375      @Uninterruptible
376      public ClassLoader getClassLoader() {
377        return classloader;
378      }
379    
380      /**
381       * @return the type name component of this type reference
382       */
383      @Uninterruptible
384      public Atom getName() {
385        return name;
386      }
387    
388      /**
389       * Get the element type of for this array type
390       */
391      public TypeReference getArrayElementType() {
392        if (VM.VerifyAssertions) VM._assert(isArrayType());
393    
394        if (isUnboxedArrayType()) {
395          if (this == AddressArray) {
396            return Address;
397          } else if (this == ObjectReferenceArray) {
398            return ObjectReference;
399          } else if (this == WordArray) {
400            return Word;
401          } else if (this == OffsetArray) {
402            return Offset;
403          } else if (this == ExtentArray) {
404            return Extent;
405          } else if (this == CodeArray) {
406            return Code;
407          } else {
408            if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED, "Unexpected case of Magic arrays!");
409            return null;
410          }
411        } else {
412          return findOrCreate(classloader, name.parseForArrayElementDescriptor());
413        }
414      }
415    
416      /**
417       * Get array type corresponding to "this" array element type.
418       */
419      public TypeReference getArrayTypeForElementType() {
420        Atom arrayDescriptor = name.arrayDescriptorFromElementDescriptor();
421        return findOrCreate(classloader, arrayDescriptor);
422      }
423    
424      /**
425       * Return the dimensionality of the type.
426       * By convention, class types have dimensionality 0,
427       * primitives -1, and arrays the number of [ in their descriptor.
428       */
429      public int getDimensionality() {
430        if (isArrayType()) {
431          TypeReference elem = getArrayElementType();
432          if (elem.isArrayType()) {
433            // NOTE: we must recur instead of attempting to parse
434            //       the array descriptor for ['s so we correctly handle
435            //       [AddressArray etc. which actually has dimensionality 2!
436            return 1 + elem.getDimensionality();
437          } else {
438            return 1;
439          }
440        } else if (isUnboxedType()) {
441          return -1;
442        } else if (isClassType()) {
443          return 0;
444        } else {
445          return -1;
446        }
447      }
448    
449      /**
450       * Return the innermost element type reference for an array
451       */
452      public TypeReference getInnermostElementType() {
453        TypeReference elem = getArrayElementType();
454        if (elem.isArrayType()) {
455          // NOTE: we must recur instead of attempting to parse
456          //       the array descriptor for ['s so we correctly handle
457          //       [AddressArray and similar evil VMMagic
458          return elem.getInnermostElementType();
459        } else {
460          return elem;
461        }
462      }
463    
464      /**
465       * Does 'this' refer to a class?
466       */
467      @Uninterruptible
468      public boolean isClassType() {
469        return name.isClassDescriptor() && !(isUnboxedArrayType() || isUnboxedType());
470      }
471    
472      /**
473       * Does 'this' refer to an array?
474       */
475      @Uninterruptible
476      public boolean isArrayType() {
477        return name.isArrayDescriptor() || isUnboxedArrayType();
478      }
479    
480      /**
481       * Does 'this' refer to a primitive type
482       */
483      @Uninterruptible
484      public boolean isPrimitiveType() {
485        return !(isArrayType() || isClassType());
486      }
487    
488      /**
489       * Does 'this' refer to a reference type
490       */
491      @Uninterruptible
492      public boolean isReferenceType() {
493        return !isPrimitiveType();
494      }
495    
496      /**
497       * Does 'this' refer to Word, Address, Offset or Extent
498       */
499      @Uninterruptible
500      public boolean isWordLikeType() {
501        return this == Word || this == Offset || this == Address || this == Extent;
502      }
503    
504      /**
505       * Does 'this' refer to Word
506       */
507      @Uninterruptible
508      public boolean isWordType() {
509        return this == Word;
510      }
511    
512      /**
513       * Does 'this' refer to Address
514       */
515      @Uninterruptible
516      public boolean isAddressType() {
517        return this == Address;
518      }
519    
520      /**
521       * Does 'this' refer to Offset
522       */
523      @Uninterruptible
524      public boolean isOffsetType() {
525        return this == Offset;
526      }
527    
528      /**
529       * Does 'this' refer to Extent
530       */
531      @Uninterruptible
532      public boolean isExtentType() {
533        return this == Extent;
534      }
535    
536      /**
537       * Does 'this' refer to an unboxed type.
538       */
539      @Uninterruptible
540      public boolean isUnboxedType() {
541        return isWordLikeType() || isCodeType();
542      }
543    
544      /**
545       * Does 'this' refer to Code
546       */
547      @Uninterruptible
548      public boolean isCodeType() {
549        return this == Code;
550      }
551    
552      /**
553       * Does 'this' refer to WordArray, AddressArray, OffsetArray or ExtentArray
554       */
555      @Uninterruptible
556      public boolean isWordArrayType() {
557        return this == WordArray ||
558               this == OffsetArray ||
559               this == AddressArray ||
560               this == ExtentArray;
561      }
562    
563      /**
564       * Does 'this' refer to WordArray, AddressArray, OffsetArray or ExtentArray
565       */
566      @Uninterruptible
567      public boolean isUnboxedArrayType() {
568        return isWordArrayType() || isCodeArrayType() || this == ObjectReferenceArray;
569      }
570    
571      /**
572       * Does 'this' refer to a runtime table type?
573       */
574      @Uninterruptible
575      public boolean isRuntimeTable() {
576        return this == IMT || this == TIB || this == ITable || this == ITableArray ||
577               this == FunctionTable || this == LinkageTripletTable;
578      }
579    
580      /**
581       * Does 'this' refer to CodeArray
582       */
583      @Uninterruptible
584      public boolean isCodeArrayType() {
585        return this == CodeArray;
586      }
587    
588      /**
589       * Does 'this' refer to Magic?
590       */
591      @Uninterruptible
592      public boolean isMagicType() {
593        return this == Magic || isUnboxedType() || isUnboxedArrayType() || this == ObjectReference || isRuntimeTable();
594      }
595    
596      /**
597       * How many java stack/local words do value of this type take?
598       */
599      @Uninterruptible
600      public int getStackWords() {
601        if (isLoaded()) {
602          // all primitive and magic types are resolved immediately
603          return type.getStackWords();
604        } else {
605          // anything remaining must be a reference
606          return 1;
607        }
608      }
609    
610      /**
611       * How many bytes do values of this type take?
612       */
613      @Uninterruptible
614      public int getMemoryBytes() {
615        if (isLoaded()) {
616          // all primitive and magic types are resolved immediately
617          return type.getMemoryBytes();
618        } else {
619          // anything remaining must be a reference
620          return BYTES_IN_ADDRESS;
621        }
622      }
623    
624      /**
625       * @return the id to use for this type
626       */
627      @Uninterruptible
628      public int getId() {
629        return id;
630      }
631    
632      /**
633       * Is this the type reference for the void primitive type?
634       */
635      @Uninterruptible
636      public boolean isVoidType() {
637        return this == Void;
638      }
639    
640      /**
641       * Is this the type reference for the boolean primitive type?
642       */
643      @Uninterruptible
644      public boolean isBooleanType() {
645        return this == Boolean;
646      }
647    
648      /**
649       * Is this the type reference for the byte primitive type?
650       */
651      @Uninterruptible
652      public boolean isByteType() {
653        return this == Byte;
654      }
655    
656      /**
657       * Is this the type reference for the short primitive type?
658       */
659      @Uninterruptible
660      public boolean isShortType() {
661        return this == Short;
662      }
663    
664      /**
665       * Is this the type reference for the char primitive type?
666       */
667      @Uninterruptible
668      public boolean isCharType() {
669        return this == Char;
670      }
671    
672      /**
673       * Is this the type reference for the int primitive type?
674       */
675      @Uninterruptible
676      public boolean isIntType() {
677        return this == Int;
678      }
679    
680      /**
681       * Is this the type reference for the long primitive type?
682       */
683      @Uninterruptible
684      public boolean isLongType() {
685        return this == Long;
686      }
687    
688      /**
689       * Is this the type reference for the float primitive type?
690       */
691      @Uninterruptible
692      public boolean isFloatType() {
693        return this == Float;
694      }
695    
696      /**
697       * Is this the type reference for the double primitive type?
698       */
699      @Uninterruptible
700      public boolean isDoubleType() {
701        return this == Double;
702      }
703    
704      /**
705       * Is <code>this</code> the type reference for an
706       * int-like (1, 8, 16, or 32 bit integral) primitive type?
707       */
708      @Uninterruptible
709      public boolean isIntLikeType() {
710        return isBooleanType() || isByteType() || isCharType() || isShortType() || isIntType();
711      }
712    
713      /**
714       * Do this and that definitely refer to the different types?
715       */
716      public boolean definitelyDifferent(TypeReference that) {
717        if (this == that) return false;
718        if (name != that.name) return true;
719        RVMType mine = peekType();
720        RVMType theirs = that.peekType();
721        if (mine == null || theirs == null) return false;
722        return mine != theirs;
723      }
724    
725      /**
726       * Do {@code this} and that definitely refer to the same type?
727       */
728      public boolean definitelySame(TypeReference that) {
729        if (VM.VerifyAssertions) VM._assert(that != null);
730        if (this == that) return true;
731        if (name != that.name) return false;
732        RVMType mine = peekType();
733        RVMType theirs = that.peekType();
734        if (mine == null || theirs == null) return false;
735        return mine == theirs;
736      }
737    
738      /**
739       * Return true if the type for type reference has been loaded.
740       */
741      @Uninterruptible
742      public boolean isLoaded() {
743        return type != null;
744      }
745    
746      /**
747       * Return true if the type for type reference has been loaded and it is resolved.
748       */
749      @Uninterruptible
750      public boolean isResolved() {
751        return isLoaded() && type.isResolved();
752      }
753    
754      /**
755       * @return the current value of resolvedType -- null if not yet resolved.
756       */
757      @Uninterruptible
758      public RVMType peekType() {
759        return type;
760      }
761    
762      /*
763       * for use by RVMClassLoader.defineClassInternal
764       */
765      void setType(RVMType rt) {
766        type = rt;
767        if (type.isClassType()) {
768          type.asClass().setResolvedMembers();
769        }
770      }
771    
772      /**
773       * Force the resolution of the type reference. May cause class loading
774       * if a required class file hasn't been loaded before.
775       *
776       * @return the RVMType instance that this references resolves to.
777       *
778       * @throws NoClassDefFoundError When it cannot resolve a class.
779       *        we go to the trouble of converting the class loader's
780       *        <code>ClassNotFoundException</code> into this error,
781       *        since we need to be able to throw
782       *        <code>NoClassDefFoundError</code> for classes
783       *        that we're loading whose existence was compile-time checked.
784       *
785       * @throws IllegalArgumentException In case of a malformed class name
786       *        (should never happen, since the right thing to do is probably to
787       *        validate them as soon as we insert them into a TypeReference.
788       *        This stinks. XXX)
789       */
790      public RVMType resolve() throws NoClassDefFoundError, IllegalArgumentException {
791        /*
792        * Lock the classloader instead of this to avoid conflicting locking order.
793        * Suppose we locked this, then one thread could call resolve(), locking this,
794        * call classloader.loadClass(), trying to lock the classloader. Meanwhile,
795        * another thread could call loadClass(), locking the classloader, then
796        * try to resolve() the TypeReference, resulting in a deadlock
797        */
798        synchronized (classloader) {
799          return resolveInternal();
800        }
801      }
802    
803      private RVMType resolveInternal() throws NoClassDefFoundError, IllegalArgumentException {
804        if (type != null) return type;
805        if (isClassType()) {
806          RVMType ans;
807          if (VM.runningVM) {
808            Class<?> klass;
809            String myName = name.classNameFromDescriptor();
810            try {
811              klass = classloader.loadClass(myName);
812            } catch (ClassNotFoundException cnf) {
813              NoClassDefFoundError ncdfe =
814                  new NoClassDefFoundError("Could not find the class " + myName + ":\n\t" + cnf.getMessage());
815              ncdfe.initCause(cnf); // in dubious taste, but helps us debug Jikes RVM
816              throw ncdfe;
817            }
818    
819            ans = java.lang.JikesRVMSupport.getTypeForClass(klass);
820          } else {
821            // Use a special purpose backdoor to avoid creating java.lang.Class
822            // objects when not running the VM (we get host JDK Class objects
823            // and that just doesn't work).
824            ans = ((BootstrapClassLoader) classloader).loadVMClass(name.classNameFromDescriptor());
825          }
826          if (VM.VerifyAssertions) {
827            VM._assert(type == null || type == ans);
828          }
829          setType(ans);
830        } else if (isArrayType()) {
831          if (isUnboxedArrayType()) {
832            // Ensure that we only create one RVMArray object for each pair of
833            // names for this type.
834            // Do this by resolving AddressArray to [Address
835            setType(getArrayElementType().getArrayTypeForElementType().resolve());
836          } else {
837            RVMType elementType = getArrayElementType().resolve();
838            if (elementType.getClassLoader() != classloader) {
839              // We aren't the canonical type reference because the element type
840              // was loaded using a different classloader.
841              // Find the canonical type reference and ask it to resolve itself.
842              TypeReference canonical = TypeReference.findOrCreate(elementType.getClassLoader(), name);
843              setType(canonical.resolve());
844            } else {
845              setType(new RVMArray(this, elementType));
846            }
847          }
848        } else {
849          if (isUnboxedType()) {
850            setType(UnboxedType.createUnboxedType(this));
851          } else {
852            setType(Primitive.createPrimitive(this));
853          }
854        }
855        return type;
856      }
857    
858      @Override
859      public String toString() {
860        return "< " + classloader + ", " + name + " >";
861      }
862    }