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