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 */
013package org.jikesrvm.classloader;
014
015import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.runtime.ReflectionBase;
019import org.jikesrvm.util.ImmutableEntryHashSetRVM;
020
021import org.vmmagic.pragma.Uninterruptible;
022
023/**
024 * A class to represent the reference in a class file to some
025 * type (class, primitive or array).
026 * A type reference is uniquely defined by
027 * <ul>
028 * <li> an initiating class loader
029 * <li> a type name
030 * </ul>
031 * Resolving a TypeReference to a RVMType can
032 * be an expensive operation.  Therefore we canonicalize
033 * TypeReference instances and cache the result of resolution.
034 */
035public final class TypeReference {
036  /**
037   * The initiating class loader
038   */
039  final ClassLoader classloader;
040
041  /**
042   * The type name. For example, the primitive type int is "I", the
043   * class java.lang.String is "Ljava/lang/String;"
044   */
045  final Atom name;
046
047  /**
048   * The id of this type reference.
049   */
050  final int id;
051
052  /**
053   * The RVMType instance that this type reference resolves to.
054   * Null if the reference has not yet been resolved.
055   */
056  private RVMType type;
057
058  /**
059   * Used to canonicalize TypeReferences
060   */
061  private static final ImmutableEntryHashSetRVM<TypeReference> dictionary =
062    new ImmutableEntryHashSetRVM<TypeReference>();
063
064  private static final ImmutableEntryHashSetRVM<ClassLoader> clDict = new ImmutableEntryHashSetRVM<ClassLoader>();
065  /**
066   * 2^LOG_ROW_SIZE is the number of elements per row
067   */
068  private static final int LOG_ROW_SIZE = 10;
069  /**
070   * Mask to ascertain row from id number
071   */
072  private static final int ROW_MASK = (1 << LOG_ROW_SIZE) - 1;
073  /**
074   * Dictionary of all TypeReference instances.
075   */
076  private static TypeReference[][] types = new TypeReference[3][1 << LOG_ROW_SIZE];
077
078  /**
079   * Used to assign Ids.  Id 0 is not used. Ids are compressed and
080   * stored in the constant pool (See {@link RVMClass}).
081   */
082  private static int nextId = 1;
083
084  public static final TypeReference Void = findOrCreate("V");
085  public static final TypeReference Boolean = findOrCreate("Z");
086  public static final TypeReference Byte = findOrCreate("B");
087  public static final TypeReference Char = findOrCreate("C");
088  public static final TypeReference Short = findOrCreate("S");
089  public static final TypeReference Int = findOrCreate("I");
090  public static final TypeReference Long = findOrCreate("J");
091  public static final TypeReference Float = findOrCreate("F");
092  public static final TypeReference Double = findOrCreate("D");
093
094  public static final TypeReference BooleanArray = findOrCreate("[Z");
095  public static final TypeReference ByteArray = findOrCreate("[B");
096  public static final TypeReference CharArray = findOrCreate("[C");
097  public static final TypeReference ShortArray = findOrCreate("[S");
098  public static final TypeReference IntArray = findOrCreate("[I");
099  public static final TypeReference LongArray = findOrCreate("[J");
100  public static final TypeReference FloatArray = findOrCreate("[F");
101  public static final TypeReference DoubleArray = findOrCreate("[D");
102
103  public static final TypeReference Word = findOrCreate(org.vmmagic.unboxed.Word.class);
104  public static final TypeReference Address = findOrCreate(org.vmmagic.unboxed.Address.class);
105  public static final TypeReference ObjectReference = findOrCreate(org.vmmagic.unboxed.ObjectReference.class);
106  public static final TypeReference Offset = findOrCreate(org.vmmagic.unboxed.Offset.class);
107  public static final TypeReference Extent = findOrCreate(org.vmmagic.unboxed.Extent.class);
108  public static final TypeReference Code = findOrCreate(org.jikesrvm.compilers.common.Code.class);
109  public static final TypeReference WordArray = findOrCreate(org.vmmagic.unboxed.WordArray.class);
110  public static final TypeReference AddressArray = findOrCreate(org.vmmagic.unboxed.AddressArray.class);
111  public static final TypeReference ObjectReferenceArray =
112      findOrCreate(org.vmmagic.unboxed.ObjectReferenceArray.class);
113  public static final TypeReference OffsetArray = findOrCreate(org.vmmagic.unboxed.OffsetArray.class);
114  public static final TypeReference ExtentArray = findOrCreate(org.vmmagic.unboxed.ExtentArray.class);
115  public static final TypeReference CodeArray = findOrCreate(org.jikesrvm.compilers.common.CodeArray.class);
116  public static final TypeReference Magic = findOrCreate(org.jikesrvm.runtime.Magic.class);
117  public static final TypeReference SysCall = findOrCreate(org.vmmagic.pragma.SysCallNative.class);
118  public static final TypeReference TIB = findOrCreate(org.jikesrvm.objectmodel.TIB.class);
119  public static final TypeReference ITableArray = findOrCreate(org.jikesrvm.objectmodel.ITableArray.class);
120  public static final TypeReference ITable = findOrCreate(org.jikesrvm.objectmodel.ITable.class);
121  public static final TypeReference IMT = findOrCreate(org.jikesrvm.objectmodel.IMT.class);
122  public static final TypeReference Thread = findOrCreate(org.jikesrvm.scheduler.RVMThread.class);
123  public static final TypeReference FunctionTable = findOrCreate(org.jikesrvm.jni.FunctionTable.class);
124  public static final TypeReference LinkageTripletTable = findOrCreate(org.jikesrvm.jni.LinkageTripletTable.class);
125
126  public static final TypeReference JavaLangObject = findOrCreate(java.lang.Object.class);
127  public static final TypeReference JavaLangClass = findOrCreate(java.lang.Class.class);
128  public static final TypeReference JavaLangString = findOrCreate(java.lang.String.class);
129  public static final TypeReference JavaLangCloneable = findOrCreate(java.lang.Cloneable.class);
130  public static final TypeReference JavaIoSerializable = findOrCreate(java.io.Serializable.class);
131  public static final TypeReference JavaLangRefReference = findOrCreate(java.lang.ref.Reference.class);
132  public static final TypeReference JavaLangSystem = findOrCreate(java.lang.System.class);
133
134  public static final TypeReference JavaLangObjectArray = findOrCreate(java.lang.Object[].class);
135
136  public static final TypeReference JavaLangThrowable = findOrCreate(java.lang.Throwable.class);
137  public static final TypeReference JavaLangError = findOrCreate(java.lang.Error.class);
138  public static final TypeReference JavaLangNullPointerException =
139      findOrCreate(java.lang.NullPointerException.class);
140  public static final TypeReference JavaLangArrayIndexOutOfBoundsException =
141      findOrCreate(java.lang.ArrayIndexOutOfBoundsException.class);
142  public static final TypeReference JavaLangArithmeticException = findOrCreate(java.lang.ArithmeticException.class);
143  public static final TypeReference JavaLangArrayStoreException = findOrCreate(java.lang.ArrayStoreException.class);
144  public static final TypeReference JavaLangClassCastException = findOrCreate(java.lang.ClassCastException.class);
145  public static final TypeReference JavaLangNegativeArraySizeException =
146      findOrCreate(java.lang.NegativeArraySizeException.class);
147  public static final TypeReference JavaLangIllegalMonitorStateException =
148      findOrCreate(java.lang.IllegalMonitorStateException.class);
149
150  public static final TypeReference Type = findOrCreate(org.jikesrvm.classloader.RVMType.class);
151  public static final TypeReference Class = findOrCreate(org.jikesrvm.classloader.RVMClass.class);
152
153  public static final TypeReference NativeBridge = findOrCreate(org.vmmagic.pragma.NativeBridge.class);
154  public static final TypeReference DynamicBridge = findOrCreate(org.vmmagic.pragma.DynamicBridge.class);
155  public static final TypeReference SaveVolatile = findOrCreate(org.vmmagic.pragma.SaveVolatile.class);
156  public static final TypeReference Interruptible = findOrCreate(org.vmmagic.pragma.Interruptible.class);
157  public static final TypeReference LogicallyUninterruptible =
158      findOrCreate(org.vmmagic.pragma.LogicallyUninterruptible.class);
159  public static final TypeReference Preemptible = findOrCreate(org.vmmagic.pragma.Preemptible.class);
160  public static final TypeReference UninterruptibleNoWarn =
161      findOrCreate(org.vmmagic.pragma.UninterruptibleNoWarn.class);
162  public static final TypeReference UnpreemptibleNoWarn =
163      findOrCreate(org.vmmagic.pragma.UnpreemptibleNoWarn.class);
164  public static final TypeReference Uninterruptible = findOrCreate(org.vmmagic.pragma.Uninterruptible.class);
165  public static final TypeReference NoCheckStore = findOrCreate(org.vmmagic.pragma.NoCheckStore.class);
166  public static final TypeReference Unpreemptible = findOrCreate(org.vmmagic.pragma.Unpreemptible.class);
167  public static final TypeReference SpecializedMethodInvoke = findOrCreate(org.vmmagic.pragma.SpecializedMethodInvoke.class);
168  public static final TypeReference Untraced = findOrCreate(org.vmmagic.pragma.Untraced.class);
169  public static final TypeReference NonMoving = findOrCreate(org.vmmagic.pragma.NonMoving.class);
170  public static final TypeReference NonMovingAllocation = findOrCreate(org.vmmagic.pragma.NonMovingAllocation.class);
171  public static final TypeReference BaselineNoRegisters = findOrCreate(org.vmmagic.pragma.BaselineNoRegisters.class);
172  public static final TypeReference BaselineSaveLSRegisters = findOrCreate(org.vmmagic.pragma.BaselineSaveLSRegisters.class);
173  public static final TypeReference ReferenceFieldsVary = findOrCreate(org.vmmagic.pragma.ReferenceFieldsVary.class);
174
175
176  public static final TypeReference ReferenceMaps =
177      findOrCreate(org.jikesrvm.compilers.baseline.ReferenceMaps.class);
178  public static final TypeReference JNIFunctions = findOrCreate(org.jikesrvm.jni.JNIFunctions.class);
179
180  public static final TypeReference RVMArray = findOrCreate(org.jikesrvm.classloader.RVMArray.class);
181  /** Abstract base of reflective method invoker classes */
182  static final TypeReference baseReflectionClass = TypeReference.findOrCreate(ReflectionBase.class);
183
184  // Synthetic types used by the opt compiler
185  public static final TypeReference NULL_TYPE =
186      (VM.BuildForOptCompiler) ? findOrCreate("Lorg/jikesrvm/classloader/TypeReference$NULL;") : null;
187  public static final TypeReference VALIDATION_TYPE =
188      (VM.BuildForOptCompiler) ? findOrCreate("Lorg/jikesrvm/classloader/TypeReference$VALIDATION;") : null;
189
190  public static final TypeReference ExceptionTable =
191      (VM.BuildForOptCompiler) ? findOrCreate(org.jikesrvm.compilers.common.ExceptionTable.class) : null;
192
193  public static final TypeReference OptimizationPlanner =
194      (VM.BuildForAdaptiveSystem) ? findOrCreate(org.jikesrvm.compilers.opt.driver.OptimizationPlanner.class) : null;
195
196  /**
197   * Hash value based on name, used for canonical type dictionary
198   */
199  @Override
200  public int hashCode() {
201    return name.hashCode();
202  }
203
204  /**
205   * Are two keys equivalent? Used for canonical type dictionary.
206   * NB ignores id value
207   */
208  @Override
209  public boolean equals(Object other) {
210    if (other instanceof TypeReference) {
211      TypeReference that = (TypeReference) other;
212      return name == that.name && classloader.equals(that.classloader);
213    } else {
214      return false;
215    }
216  }
217
218  /**
219   * Find or create the canonical TypeReference instance for
220   * the given pair.
221   *
222   * @param cl the classloader (defining/initiating depending on usage)
223   * @param tn the name of the type
224   * @return the canonical type reference
225   * @throws IllegalArgumentException Needs to throw some kind of error in
226   *  the case of a Atom that does not represent a type name.
227   */
228  public static synchronized TypeReference findOrCreate(ClassLoader cl, Atom tn) throws IllegalArgumentException {
229    TypeDescriptorParsing.validateAsTypeDescriptor(tn);
230    // Primitives, arrays of primitives, system classes and arrays of system
231    // classes must use the bootstrap classloader.  Force that here so we don't
232    // have to worry about it anywhere else in the VM.
233    ClassLoader bootstrapCL = BootstrapClassLoader.getBootstrapClassLoader();
234    if (cl == null) {
235      cl = bootstrapCL;
236    } else if (cl != bootstrapCL) {
237      if (tn.isClassDescriptor()) {
238        if (tn.isBootstrapClassDescriptor()) {
239          cl = bootstrapCL;
240        }
241      } else if (tn.isArrayDescriptor()) {
242        Atom innermostElementType = tn.parseForInnermostArrayElementDescriptor();
243        if (innermostElementType.isClassDescriptor()) {
244          if (innermostElementType.isBootstrapClassDescriptor()) {
245            cl = bootstrapCL;
246          }
247        } else {
248          cl = bootstrapCL;
249        }
250      } else {
251        cl = bootstrapCL;
252      }
253    }
254    return findOrCreateInternal(cl, tn);
255  }
256
257  /**
258   * Shorthand for doing a find or create for a type reference that should
259   * be created using the bootstrap classloader.
260   * @return the canonical type reference
261   * @param tn type name
262   */
263  public static TypeReference findOrCreate(String tn) {
264    return findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), Atom.findOrCreateAsciiAtom(tn));
265  }
266
267  /**
268   * Convert a java.lang.Class into a type reference the slow way. For
269   * use in boot image writing
270   * @param klass java.lang.Class to convert to type reference
271   * @return the canonical type reference
272   */
273  public static TypeReference findOrCreate(Class<?> klass) {
274    if (VM.runningVM) {
275      return java.lang.JikesRVMSupport.getTypeForClass(klass).getTypeRef();
276    } else {
277      String className = klass.getName();
278      if (className.startsWith("[")) {
279        // an array
280        Atom classAtom = Atom.findOrCreateAsciiAtom(className.replace('.', '/'));
281        return findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), classAtom);
282      } else {
283        // a class
284        Atom classAtom;
285        if (className.equals("int")) {
286          return TypeReference.Int;
287        } else if (className.equals("boolean")) {
288          return TypeReference.Boolean;
289        } else if (className.equals("byte")) {
290          return TypeReference.Byte;
291        } else if (className.equals("char")) {
292          return TypeReference.Char;
293        } else if (className.equals("double")) {
294          return TypeReference.Double;
295        } else if (className.equals("float")) {
296          return TypeReference.Float;
297        } else if (className.equals("long")) {
298          return TypeReference.Long;
299        } else if (className.equals("short")) {
300          return TypeReference.Short;
301        } else if (className.equals("void")) {
302          return TypeReference.Void;
303        } else {
304          classAtom = Atom.findOrCreateAsciiAtom(className.replace('.', '/'));
305        }
306        Atom classDescriptor = classAtom.descriptorFromClassName();
307        return findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), classDescriptor);
308      }
309    }
310  }
311
312  /**
313   * Find or create the canonical TypeReference instance for
314   * the given pair without type descriptor parsing.
315   *
316   * @param cl the classloader (defining/initiating depending on usage)
317   * @param tn the name of the type
318   * @return the canonical type reference
319   */
320  public static synchronized TypeReference findOrCreateInternal(ClassLoader cl, Atom tn) {
321    // Next actually findOrCreate the type reference using the proper classloader.
322    TypeReference key = new TypeReference(cl, tn, nextId);
323    TypeReference val = dictionary.get(key);
324    if (val == null) {
325      // Create type reference
326      val = key;
327      nextId++; // id of val is the nextId, move it along
328      int column = val.id >> LOG_ROW_SIZE;
329      if (column == types.length) {
330        // Grow the array of types if necessary
331        TypeReference[][] tmp = new TypeReference[column + 1][];
332        for (int i = 0; i < column; i++) {
333          tmp[i] = types[i];
334        }
335        types = tmp;
336        types[column] = new TypeReference[1 << LOG_ROW_SIZE];
337      }
338      types[column][val.id & ROW_MASK] = val;
339      dictionary.add(val);
340    }
341    return val;
342  }
343  private static void canonicalizeCL(ClassLoader cl) {
344    clDict.add(cl);
345  }
346  public static ImmutableEntryHashSetRVM<ClassLoader> getCLDict() {
347    return clDict;
348  }
349
350  /**
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   * @return 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   * @return 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   * @return {@code true} if 'this' refers to a class
466   */
467  @Uninterruptible
468  public boolean isClassType() {
469    return name.isClassDescriptor() && !(isUnboxedArrayType() || isUnboxedType());
470  }
471
472  /**
473   * @return {@code true} if 'this' refers to an array
474   */
475  @Uninterruptible
476  public boolean isArrayType() {
477    return name.isArrayDescriptor() || isUnboxedArrayType();
478  }
479
480  /**
481   * @return {@code true} if 'this' refers to a primitive type
482   */
483  @Uninterruptible
484  public boolean isPrimitiveType() {
485    return !(isArrayType() || isClassType());
486  }
487
488  /**
489   * @return {@code true} if 'this' refers to a reference type
490   */
491  @Uninterruptible
492  public boolean isReferenceType() {
493    return !isPrimitiveType();
494  }
495
496  /**
497   * @return {@code true} if 'this' refers 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   * @return {@code true} if 'this' refers to Word
506   */
507  @Uninterruptible
508  public boolean isWordType() {
509    return this == Word;
510  }
511
512  /**
513   * @return {@code true} if 'this' refers to Address
514   */
515  @Uninterruptible
516  public boolean isAddressType() {
517    return this == Address;
518  }
519
520  /**
521   * @return {@code true} if 'this' refers to Offset
522   */
523  @Uninterruptible
524  public boolean isOffsetType() {
525    return this == Offset;
526  }
527
528  /**
529   * @return {@code true} if 'this' refers to Extent
530   */
531  @Uninterruptible
532  public boolean isExtentType() {
533    return this == Extent;
534  }
535
536  /**
537   * @return {@code true} if 'this' refers to an unboxed type.
538   */
539  @Uninterruptible
540  public boolean isUnboxedType() {
541    return isWordLikeType() || isCodeType();
542  }
543
544  /**
545   * @return {@code true} if 'this' refers to Code
546   */
547  @Uninterruptible
548  public boolean isCodeType() {
549    return this == Code;
550  }
551
552  /**
553   * @return {@code true} if  'this' refers 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   * @return {@code true} if 'this' refers to WordArray, AddressArray, OffsetArray or ExtentArray
565   */
566  @Uninterruptible
567  public boolean isUnboxedArrayType() {
568    return isWordArrayType() || isCodeArrayType() || this == ObjectReferenceArray;
569  }
570
571  /**
572   * @return {@code true} if 'this' refers 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   * @return {@code true} if 'this' refers to CodeArray
582   */
583  @Uninterruptible
584  public boolean isCodeArrayType() {
585    return this == CodeArray;
586  }
587
588  /**
589   * @return {@code true} if 'this' refers to Magic
590   */
591  @Uninterruptible
592  public boolean isMagicType() {
593    return this == Magic || isUnboxedType() || isUnboxedArrayType() || this == ObjectReference || isRuntimeTable();
594  }
595
596  /**
597   * @return number of java stack/local words that values 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   * @return number of bytes that 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   * @return {@code true} if this is the type reference for the void primitive type
634   */
635  @Uninterruptible
636  public boolean isVoidType() {
637    return this == Void;
638  }
639
640  /**
641   * @return {@code true} if this is the type reference for the boolean primitive type
642   */
643  @Uninterruptible
644  public boolean isBooleanType() {
645    return this == Boolean;
646  }
647
648  /**
649   * @return {@code true} if this is the type reference for the byte primitive type
650   */
651  @Uninterruptible
652  public boolean isByteType() {
653    return this == Byte;
654  }
655
656  /**
657   * @return {@code true} if this is the type reference for the short primitive type
658   */
659  @Uninterruptible
660  public boolean isShortType() {
661    return this == Short;
662  }
663
664  /**
665   * @return {@code true} if this is the type reference for the char primitive type
666   */
667  @Uninterruptible
668  public boolean isCharType() {
669    return this == Char;
670  }
671
672  /**
673   * @return {@code true} if this is the type reference for the int primitive type
674   */
675  @Uninterruptible
676  public boolean isIntType() {
677    return this == Int;
678  }
679
680  /**
681   * @return {@code true} if this is the type reference for the long primitive type
682   */
683  @Uninterruptible
684  public boolean isLongType() {
685    return this == Long;
686  }
687
688  /**
689   * @return {@code true} if this is the type reference for the float primitive type
690   */
691  @Uninterruptible
692  public boolean isFloatType() {
693    return this == Float;
694  }
695
696  /**
697   * @return {@code true} if this is the type reference for the double primitive type
698   */
699  @Uninterruptible
700  public boolean isDoubleType() {
701    return this == Double;
702  }
703
704  /**
705   * @return {@code true} if {@code this} is 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   * @param that other type
717   * @return {@code true} if this and the other type are definitely
718   *  different, {@code false} if it's not known (e.g. because a
719   *  type reference is not yet resolved)
720   */
721  public boolean definitelyDifferent(TypeReference that) {
722    if (this == that) return false;
723    if (name != that.name) return true;
724    RVMType mine = peekType();
725    RVMType theirs = that.peekType();
726    if (mine == null || theirs == null) return false;
727    return mine != theirs;
728  }
729
730  /**
731   * Do {@code this} and that definitely refer to the same type?
732   *
733   * @param that other type
734   * @return {@code true} if this and the other type are definitely
735   *  the same, {@code false} if it's not known (e.g. because a
736   *  type reference is not yet resolved)
737   */
738  public boolean definitelySame(TypeReference that) {
739    if (VM.VerifyAssertions) VM._assert(that != null);
740    if (this == that) return true;
741    if (name != that.name) return false;
742    RVMType mine = peekType();
743    RVMType theirs = that.peekType();
744    if (mine == null || theirs == null) return false;
745    return mine == theirs;
746  }
747
748  /**
749   * @return {@code true} if the type for type reference has been loaded.
750   */
751  @Uninterruptible
752  public boolean isLoaded() {
753    return type != null;
754  }
755
756  /**
757   * @return {@code true} if the type for type reference has been loaded and
758   *  it is resolved.
759   */
760  @Uninterruptible
761  public boolean isResolved() {
762    return isLoaded() && type.isResolved();
763  }
764
765  /**
766   * @return the current value of resolvedType -- null if not yet resolved.
767   */
768  @Uninterruptible
769  public RVMType peekType() {
770    return type;
771  }
772
773  void setType(RVMType rt) {
774    type = rt;
775    if (type.isClassType()) {
776      type.asClass().setResolvedMembers();
777    }
778  }
779
780  /**
781   * Force the resolution of the type reference. May cause class loading
782   * if a required class file hasn't been loaded before.
783   *
784   * @return the RVMType instance that this references resolves to.
785   *
786   * @throws NoClassDefFoundError When it cannot resolve a class.
787   *        we go to the trouble of converting the class loader's
788   *        <code>ClassNotFoundException</code> into this error,
789   *        since we need to be able to throw
790   *        <code>NoClassDefFoundError</code> for classes
791   *        that we're loading whose existence was compile-time checked.
792   *
793   * @throws IllegalArgumentException In case of a malformed class name
794   *        (should never happen, since the right thing to do is probably to
795   *        validate them as soon as we insert them into a TypeReference.
796   *        This stinks. XXX)
797   */
798  public RVMType resolve() throws NoClassDefFoundError, IllegalArgumentException {
799    /*
800    * Lock the classloader instead of this to avoid conflicting locking order.
801    * Suppose we locked this, then one thread could call resolve(), locking this,
802    * call classloader.loadClass(), trying to lock the classloader. Meanwhile,
803    * another thread could call loadClass(), locking the classloader, then
804    * try to resolve() the TypeReference, resulting in a deadlock
805    */
806    synchronized (classloader) {
807      return resolveInternal();
808    }
809  }
810
811  private RVMType resolveInternal() throws NoClassDefFoundError, IllegalArgumentException {
812    if (type != null) return type;
813    if (isClassType()) {
814      RVMType ans;
815      if (VM.runningVM) {
816        Class<?> klass;
817        String myName = name.classNameFromDescriptor();
818        try {
819          klass = classloader.loadClass(myName);
820        } catch (ClassNotFoundException cnf) {
821          NoClassDefFoundError ncdfe =
822              new NoClassDefFoundError("Could not find the class " + myName + ":\n\t" + cnf.getMessage());
823          ncdfe.initCause(cnf); // in dubious taste, but helps us debug Jikes RVM
824          throw ncdfe;
825        }
826
827        ans = java.lang.JikesRVMSupport.getTypeForClass(klass);
828      } else {
829        // Use a special purpose backdoor to avoid creating java.lang.Class
830        // objects when not running the VM (we get host JDK Class objects
831        // and that just doesn't work).
832        ans = ((BootstrapClassLoader) classloader).loadVMClass(name.classNameFromDescriptor());
833      }
834      if (VM.VerifyAssertions) {
835        VM._assert(type == null || type == ans);
836      }
837      setType(ans);
838    } else if (isArrayType()) {
839      if (isUnboxedArrayType()) {
840        // Ensure that we only create one RVMArray object for each pair of
841        // names for this type.
842        // Do this by resolving AddressArray to [Address
843        setType(getArrayElementType().getArrayTypeForElementType().resolve());
844      } else {
845        RVMType elementType = getArrayElementType().resolve();
846        if (elementType.getClassLoader() != classloader) {
847          // We aren't the canonical type reference because the element type
848          // was loaded using a different classloader.
849          // Find the canonical type reference and ask it to resolve itself.
850          TypeReference canonical = TypeReference.findOrCreate(elementType.getClassLoader(), name);
851          setType(canonical.resolve());
852        } else {
853          setType(new RVMArray(this, elementType));
854        }
855      }
856    } else {
857      if (isUnboxedType()) {
858        setType(UnboxedType.createUnboxedType(this));
859      } else {
860        setType(Primitive.createPrimitive(this));
861      }
862    }
863    return type;
864  }
865
866  @Override
867  public String toString() {
868    return "< " + classloader + ", " + name + " >";
869  }
870}