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 java.lang.annotation.Annotation;
016    import java.lang.annotation.Inherited;
017    
018    import org.jikesrvm.Callbacks;
019    import org.jikesrvm.Constants;
020    import org.jikesrvm.VM;
021    import org.jikesrvm.compilers.common.CompiledMethod;
022    import org.jikesrvm.compilers.opt.inlining.ClassLoadingDependencyManager;
023    import org.jikesrvm.mm.mminterface.MemoryManager;
024    import org.jikesrvm.objectmodel.FieldLayoutContext;
025    import org.jikesrvm.objectmodel.IMT;
026    import org.jikesrvm.objectmodel.ObjectModel;
027    import org.jikesrvm.objectmodel.TIB;
028    import org.jikesrvm.runtime.Magic;
029    import org.jikesrvm.runtime.RuntimeEntrypoints;
030    import org.jikesrvm.runtime.StackBrowser;
031    import org.jikesrvm.runtime.Statics;
032    import org.vmmagic.pragma.NonMoving;
033    import org.vmmagic.pragma.Pure;
034    import org.vmmagic.pragma.Uninterruptible;
035    import org.vmmagic.unboxed.Offset;
036    
037    /**
038     * Description of a java "class" type.<br/>
039     *
040     * This description is read from a ".class" file as classes/field/methods
041     * referenced by the running program need to be bound in to the running image.
042     *
043     * @see RVMType
044     * @see RVMArray
045     * @see Primitive
046     * @see UnboxedType
047     */
048    @NonMoving
049    public final class RVMClass extends RVMType implements Constants, ClassLoaderConstants {
050    
051      /** Flag for closed world testing */
052      public static boolean classLoadingDisabled = false;
053    
054      /**
055       * The constant pool holds constants used by the class and the Java
056       * bytecodes in the methods associated with this class. This
057       * constant pool isn't that from the class file, instead it has been
058       * processed during class loading (see {@link ClassFileReader#readClass}). The loaded
059       * class' constant pool has 3 bits of type information (such as
060       * (see {@link ClassLoaderConstants#CP_INT})), the rest of the int holds data as follows:
061       *
062       * <ul>
063       * <li>utf: value is a UTF atom identifier</li>
064       * <li>int, long, float, double, string: value is an offset in the
065       *     JTOC</li>
066       * <li>member: value is a member reference identifier</li>
067       * <li>class: value is a type reference identifier. NB this means
068       *     that class literal bytecodes must first convert the identifier
069       *     in to a JTOC offset.</li>
070       * </ul>
071       */
072      private final int[] constantPool;
073      /** {@link ClassLoaderConstants} */
074      private final short modifiers;
075      /** Super class of this class */
076      private final RVMClass superClass;
077      /**
078       * Non-final list of sub-classes. Classes added as sub-classes are
079       * loaded.
080       */
081      private RVMClass[] subClasses;
082      /** Interfaces supported by this class */
083      private final RVMClass[] declaredInterfaces;
084      /** Fields of this class */
085      private final RVMField[] declaredFields;
086      /** Methods of this class */
087      private final RVMMethod[] declaredMethods;
088      /** Declared inner classes, may be null */
089      private final TypeReference[] declaredClasses;
090      /** The outer class, or null if this is not a inner/nested class */
091      private final TypeReference declaringClass;
092      /** The enclosing class if this is a local class */
093      private final TypeReference enclosingClass;
094      /** The enclosing method if this is a local class */
095      private final MethodReference enclosingMethod;
096      /** Name of file .class file was compiled from, may be null */
097      private final Atom sourceName;
098      /**
099       * The signature is a string representing the generic type for this
100       * class declaration, may be null
101       */
102      private final Atom signature;
103      /**
104       * Class initializer method, null if no method or if class is
105       * initialized (ie class initializer method has been run)
106       */
107      private RVMMethod classInitializerMethod;
108    
109      /**
110       * current class-loading stage (loaded, resolved, instantiated,
111       * initializing or initialized)
112       */
113      private byte state;
114    
115      //
116      // The following are valid only when "state >= CLASS_RESOLVED".
117      //
118    
119      // --- Field size and offset information --- //
120    
121      /** fields shared by all instances of class  */
122      private RVMField[] staticFields;
123    
124      /** fields distinct for each instance of class */
125      private RVMField[] instanceFields;
126    
127      /** offsets of reference-containing instance fields */
128      private int[] referenceOffsets;
129    
130      /** Total size of per-instance data, in bytes  */
131      private int instanceSize;
132    
133      /** The desired alignment for instances of this type. */
134      private int alignment;
135    
136      /**
137       * A field layout helper - used to keep context regarding field layouts.
138       * Managed by the field layout objects in the ObjectModel.
139       */
140      private FieldLayoutContext fieldLayoutContext = null;
141    
142      // --- Method-dispatching information --- //
143    
144      /** static methods of class */
145      private RVMMethod[] staticMethods;
146    
147      /** constructor methods of class  */
148      private RVMMethod[] constructorMethods;
149    
150      /** virtual methods of class */
151      private RVMMethod[] virtualMethods;
152    
153      /**
154       * Do objects of this class have a finalizer method?
155       */
156      private boolean hasFinalizer;
157    
158      /** type and virtual method dispatch table for class */
159      private TIB typeInformationBlock;
160    
161      // --- Memory manager support --- //
162    
163      /**
164       * Is this class type in the bootimage? Types in the boot image can
165       * be initialized prior to execution (therefore removing runtime
166       * resolution).
167       */
168      private boolean inBootImage;
169    
170      /**
171       * At what offset is the thin lock word to be found in instances of
172       * objects of this type?  A value of -1 indicates that the instances of
173       * this type do not have inline thin locks.
174       */
175      private Offset thinLockOffset;
176    
177      /** Reference Count GC: is this type acyclic?  */
178      private boolean acyclic;
179    
180      /** Cached set of inherited and declared annotations. */
181      private Annotation[] annotations;
182    
183      /** Set of objects that are cached here to ensure they are not collected by GC **/
184      private Object[] objectCache;
185    
186      /** The imt for this class **/
187      @SuppressWarnings("unused")
188      private IMT imt;
189    
190      // --- Assertion support --- //
191      /**
192       * Are assertions enabled on this class?
193       */
194      private final boolean desiredAssertionStatus;
195    
196      // --- General purpose functions --- //
197    
198      /**
199       * Name - something like "java.lang.String".
200       */
201      @Override
202      @Pure
203      public String toString() {
204        return getDescriptor().classNameFromDescriptor();
205      }
206    
207      /**
208       * Package name - something like "java.lang".
209       * Returns the empty string if the class is a member of the unnamed package.
210       */
211      public String getPackageName() {
212        String className = toString();
213        int lastDot = className.lastIndexOf(".");
214        return (lastDot >= 0) ? className.substring(0, lastDot) : "";
215      }
216    
217      /**
218       * Stack space requirement in words.
219       */
220      @Override
221      @Pure
222      @Uninterruptible
223      public int getStackWords() {
224        return 1;
225      }
226    
227      /**
228       * Space required in memory in bytes.
229       */
230      @Override
231      @Pure
232      @Uninterruptible
233      public int getMemoryBytes() {
234        return BYTES_IN_ADDRESS;
235      }
236    
237      /**
238       * An "interface" description rather than a "class" description?
239       */
240      @Uninterruptible
241      public boolean isInterface() {
242        return (modifiers & ACC_INTERFACE) != 0;
243      }
244    
245      /**
246       * Usable from other packages?
247       */
248      @Uninterruptible
249      public boolean isPublic() {
250        return (modifiers & ACC_PUBLIC) != 0;
251      }
252    
253      /**
254       * Non-subclassable?
255       */
256      @Uninterruptible
257      public boolean isFinal() {
258        return (modifiers & ACC_FINAL) != 0;
259      }
260    
261      /**
262       * Non-instantiable?
263       */
264      @Uninterruptible
265      public boolean isAbstract() {
266        return (modifiers & ACC_ABSTRACT) != 0;
267      }
268    
269      /**
270       * Use new-style "invokespecial" semantics for method calls in this class?
271       */
272      @Uninterruptible
273      public boolean isSpecial() {
274        return (modifiers & ACC_SUPER) != 0;
275      }
276    
277      /**
278       * Not present in source code file?
279       */
280      public boolean isSynthetic() {
281        return (modifiers & ACC_SYNTHETIC) != 0;
282      }
283    
284      /**
285       * Is enumeration?
286       */
287      public boolean isEnum() {
288        return (modifiers & ACC_ENUM) != 0;
289      }
290    
291      /**
292       * Annotation type
293       */
294      public boolean isAnnotation() {
295        return (modifiers & ACC_ANNOTATION) != 0;
296      }
297    
298      /**
299       * @return true if this is a representation of an anonymous class
300       */
301      public boolean isAnonymousClass() {
302        return (enclosingClass != null) && (enclosingMethod == null);
303      }
304    
305      /**
306       * @return true if this is a representation of a local class, ie
307       * local to a block of code.
308       */
309      public boolean isLocalClass() {
310        return enclosingMethod != null;
311      }
312    
313      /**
314       * @return true if this is a representation of a member class
315       */
316      public boolean isMemberClass() {
317        return ((declaringClass != null) && ((modifiers & ACC_STATIC) == 0));
318      }
319      /**
320       * @return true if this an object of this class could be assigned to Throwable
321       */
322      public boolean isThrowable() {
323        return (getTypeRef() == TypeReference.JavaLangThrowable) ||
324        RuntimeEntrypoints.isAssignableWith(TypeReference.JavaLangThrowable.resolve(), this);
325      }
326      /**
327       * Get the modifiers associated with this class {@link
328       * ClassLoaderConstants}.
329       */
330      public int getModifiers() {
331        return modifiers & APPLICABLE_TO_CLASSES;
332      }
333    
334      /**
335       * Generic type information for class
336       */
337      public Atom getSignature() {
338        return signature;
339      }
340    
341      /**
342       * Name of source file from which class was compiled -
343       * something like "c:\java\src\java\lang\Object.java".
344       * (null --> "unknown - wasn't recorded by compiler").
345       */
346      public Atom getSourceName() {
347        return sourceName;
348      }
349    
350      /**
351       * Superclass of this class (null means "no superclass",
352       * ie. class is "java/lang/Object").
353       */
354      @Uninterruptible
355      public RVMClass getSuperClass() {
356        return superClass;
357      }
358    
359      /**
360       * Currently loaded classes that "extend" this class.
361       */
362      @Uninterruptible
363      public RVMClass[] getSubClasses() {
364        return subClasses;
365      }
366    
367      /**
368       * Interfaces implemented directly by this class
369       * (ie. not including superclasses).
370       */
371      @Uninterruptible
372      public RVMClass[] getDeclaredInterfaces() {
373        return declaredInterfaces;
374      }
375    
376      /**
377       * Fields defined directly by this class (ie. not including superclasses).
378       */
379      @Uninterruptible
380      public RVMField[] getDeclaredFields() {
381        return declaredFields;
382      }
383    
384      /**
385       * Does this class directly define a final instance field (has implications for JMM).
386       */
387      public boolean declaresFinalInstanceField() {
388        for (RVMField f : declaredFields) {
389          if (f.isFinal() && !f.isStatic()) return true;
390        }
391        return false;
392      }
393    
394      /**
395       * Methods defined directly by this class (ie. not including superclasses).
396       */
397      @Uninterruptible
398      public RVMMethod[] getDeclaredMethods() {
399        return declaredMethods;
400      }
401    
402      /**
403       * Declared inner and static member classes.
404       */
405      public TypeReference[] getDeclaredClasses() {
406        return declaredClasses;
407      }
408    
409      /**
410       * Class that declared this class, or null if this is not an
411       * inner/nested class.
412       */
413      public TypeReference getDeclaringClass() {
414        return declaringClass;
415      }
416    
417      /**
418       * Class that immediately encloses this class, or null if this is not an
419       * inner/nested class.
420       */
421      public TypeReference getEnclosingClass() {
422        return enclosingClass;
423      }
424    
425      /**
426       * Set the resolvedMember in all declared members.
427       */
428      void setResolvedMembers() {
429        for(RVMField field: declaredFields) {
430          /* Make all declared fields appear resolved */
431          field.getMemberRef().asFieldReference().setResolvedMember(field);
432        }
433        for(RVMMethod method: declaredMethods) {
434          /* Make all declared methods appear resolved */
435          method.getMemberRef().asMethodReference().setResolvedMember(method);
436        }
437        if (virtualMethods != null) {
438          /* Possibly created Miranda methods */
439          for(RVMMethod method: virtualMethods) {
440            if (method.getDeclaringClass() == this) {
441              method.getMemberRef().asMethodReference().setResolvedMember(method);
442            }
443          }
444        }
445      }
446    
447      /**
448       * Static initializer method for this class (null -> no static initializer
449       *  or initializer already been run).
450       */
451      @Uninterruptible
452      public RVMMethod getClassInitializerMethod() {
453        return classInitializerMethod;
454      }
455    
456      @Override
457      Annotation[] getAnnotationsInternal() {
458        final RVMClass parent = getSuperClass();
459        if (parent == null) {
460          return super.getAnnotationsInternal();
461        }
462        if (annotations == null) {
463          final Annotation[] declared = getDeclaredAnnotations();
464          // Not synchronized as it does not matter if occasionally we create two cached copies
465          final Annotation[] parentAnnotations = parent.getAnnotations();
466          int rejected = 0;
467          for (int i = 0; i < parentAnnotations.length; i++) {
468            final Annotation pa = parentAnnotations[i];
469            final Class<? extends Annotation> paType = pa.annotationType();
470            if (!paType.isAnnotationPresent(Inherited.class)) {
471              parentAnnotations[i] = null;
472              rejected++;
473            } else {
474              for (final Annotation a : declared) {
475                if (a.annotationType().equals(paType)) {
476                  parentAnnotations[i] = null;
477                  rejected++;
478                  break;
479                }
480              }
481            }
482          }
483          final Annotation[] cache = new Annotation[declared.length + parentAnnotations.length - rejected];
484          System.arraycopy(declared, 0, cache, 0, declared.length);
485          int index = declared.length;
486          for (final Annotation pa : parentAnnotations) {
487            if (pa != null) cache[index++] = pa;
488          }
489          annotations = cache;
490        }
491        return annotations;
492      }
493    
494      /**
495       * Find description of a field of this class.
496       * @param fieldName field name - something like "foo"
497       * @param fieldDescriptor field descriptor - something like "I"
498       * @return description (null --> not found)
499       */
500      public RVMField findDeclaredField(Atom fieldName, Atom fieldDescriptor) {
501        for (RVMField field : declaredFields) {
502          if (field.getName() == fieldName && field.getDescriptor() == fieldDescriptor) {
503            return field;
504          }
505        }
506        return null;
507      }
508    
509      /**
510       * Find description of a field of this class. NB. ignores descriptor.
511       * @param fieldName field name - something like "foo"
512       * @return description (null --> not found)
513       */
514      public RVMField findDeclaredField(Atom fieldName) {
515        for (RVMField field : declaredFields) {
516          if (field.getName() == fieldName) {
517            return field;
518          }
519        }
520        return null;
521      }
522    
523      /**
524       * Find description of a method of this class.
525       * @param methodName method name - something like "foo"
526       * @param methodDescriptor method descriptor - something like "()I"
527       * @return description (null --> not found)
528       */
529      public RVMMethod findDeclaredMethod(Atom methodName, Atom methodDescriptor) {
530        for (RVMMethod method : declaredMethods) {
531          if (method.getName() == methodName && method.getDescriptor() == methodDescriptor) {
532            return method;
533          }
534        }
535        return null;
536      }
537    
538      /**
539       * Find the first description of a method of this class.
540       * @param methodName method name - something like "foo"
541       * @return description (null --> not found)
542       */
543      public RVMMethod findDeclaredMethod(Atom methodName) {
544        for (RVMMethod method : declaredMethods) {
545          if (method.getName() == methodName) {
546            return method;
547          }
548        }
549        return null;
550      }
551    
552      /**
553       * Find description of "public static void main(String[])"
554       * method of this class.
555       * @return description (null --> not found)
556       */
557      public RVMMethod findMainMethod() {
558        Atom mainName = Atom.findOrCreateAsciiAtom(("main"));
559        Atom mainDescriptor = Atom.findOrCreateAsciiAtom(("([Ljava/lang/String;)V"));
560        RVMMethod mainMethod = this.findDeclaredMethod(mainName, mainDescriptor);
561    
562        if (mainMethod == null || !mainMethod.isPublic() || !mainMethod.isStatic()) {
563          // no such method
564          return null;
565        }
566        return mainMethod;
567      }
568    
569      /**
570       * Add the given cached object.
571       */
572      public synchronized void addCachedObject(Object o) {
573        Object[] newObjectCache;
574        if (objectCache == null) {
575          newObjectCache = new Object[1];
576        } else {
577          newObjectCache = new Object[objectCache.length + 1];
578          for (int i=0; i < objectCache.length; i++) {
579            newObjectCache[i] = objectCache[i];
580          }
581        }
582        newObjectCache[newObjectCache.length - 1] = o;
583        objectCache = newObjectCache;
584      }
585    
586      /**
587       * Set the imt object.
588       */
589      public void setIMT(IMT imt) {
590        this.imt = imt;
591      }
592    
593      //
594      // Constant pool accessors.
595      //
596      // The constant pool holds literals and external references used by
597      // the bytecodes of this class's methods.
598      // Items are fetched by specifying their "constant pool index".
599      //
600    
601      /**
602       * Get offset of a literal constant, in bytes.
603       * Offset is with respect to virtual machine's "table of contents" (jtoc).
604       */
605      public Offset getLiteralOffset(int constantPoolIndex) {
606        return ClassFileReader.getLiteralOffset(this.constantPool, constantPoolIndex);
607      }
608    
609      /**
610       * Get description of a literal constant.
611       */
612      public byte getLiteralDescription(int constantPoolIndex) {
613        int cpValue = constantPool[constantPoolIndex];
614        byte type = ClassFileReader.unpackCPType(cpValue);
615        return type;
616      }
617    
618      /**
619       * Get contents of a "typeRef" constant pool entry.
620       * @return type that was referenced
621       */
622      @Uninterruptible
623      public TypeReference getTypeRef(int constantPoolIndex) {
624        return ClassFileReader.getTypeRef(constantPool, constantPoolIndex);
625      }
626    
627      /**
628       * Get contents of a "methodRef" constant pool entry.
629       */
630      @Uninterruptible
631      public MethodReference getMethodRef(int constantPoolIndex) {
632        return ClassFileReader.getMethodRef(constantPool, constantPoolIndex);
633      }
634    
635      /**
636       * Get contents of a "fieldRef" constant pool entry.
637       */
638      @Uninterruptible
639      public FieldReference getFieldRef(int constantPoolIndex) {
640        int cpValue = constantPool[constantPoolIndex];
641        if (VM.VerifyAssertions) VM._assert(ClassFileReader.unpackCPType(cpValue) == CP_MEMBER);
642        return (FieldReference) MemberReference.getMemberRef(ClassFileReader.unpackUnsignedCPValue(cpValue));
643      }
644    
645      /**
646       * Get contents of a "utf" constant pool entry.
647       */
648      @Uninterruptible
649      Atom getUtf(int constantPoolIndex) {
650        int cpValue = constantPool[constantPoolIndex];
651        if (VM.VerifyAssertions) VM._assert(ClassFileReader.unpackCPType(cpValue) == CP_UTF);
652        return Atom.getAtom(ClassFileReader.unpackUnsignedCPValue(cpValue));
653      }
654    
655      /**
656       * Should the methods of this class be compiled with special
657       * register save/restore logic?
658       * @see org.vmmagic.pragma.DynamicBridge
659       */
660      @Uninterruptible
661      public boolean hasDynamicBridgeAnnotation() {
662        return isAnnotationDeclared(TypeReference.DynamicBridge);
663      }
664    
665      /**
666       * The methods of this class are only called from native code,
667       * they are compiled with
668       * a special prolog to interface with the native stack frame.
669       */
670      @Uninterruptible
671      public boolean hasBridgeFromNativeAnnotation() {
672        return isAnnotationDeclared(TypeReference.NativeBridge);
673      }
674    
675      /**
676       * Should the methods of this class save incoming registers ?
677       * @see org.vmmagic.pragma.SaveVolatile
678       */
679      public boolean hasSaveVolatileAnnotation() {
680        return isAnnotationDeclared(TypeReference.SaveVolatile);
681      }
682    
683      //--------------------------------------------------------------------//
684      // The following are available after the class has been "resolved".   //
685      //--------------------------------------------------------------------//
686    
687      /**
688       * Does this class override java.lang.Object.finalize()?
689       */
690      @Override
691      @Pure
692      @Uninterruptible
693      public boolean hasFinalizer() {
694        if (VM.VerifyAssertions) VM._assert(isResolved());
695        return hasFinalizer;
696      }
697    
698      /**
699       * Static fields of this class.
700       * Values in these fields are shared by all class instances.
701       */
702      @Override
703      @Pure
704      public RVMField[] getStaticFields() {
705        if (VM.VerifyAssertions) VM._assert(isResolved());
706        return staticFields;
707      }
708    
709      /**
710       * Non-static fields of this class (composed with supertypes, if any).
711       * Values in these fields are distinct for each class instance.
712       */
713      @Override
714      @Pure
715      public RVMField[] getInstanceFields() {
716        if (VM.VerifyAssertions) VM._assert(isResolved());
717        return instanceFields;
718      }
719    
720      /**
721       * Statically dispatched methods of this class.
722       */
723      @Override
724      @Pure
725      public RVMMethod[] getStaticMethods() {
726        if (VM.VerifyAssertions) VM._assert(isResolved());
727        return staticMethods;
728      }
729    
730      /**
731       * Constructors (<init>) methods of this class.
732       */
733      @Pure
734      public RVMMethod[] getConstructorMethods() {
735        if (VM.VerifyAssertions) VM._assert(isResolved(), "Error class " + this + " is not resolved but " + state);
736        return constructorMethods;
737      }
738    
739      /**
740       * Virtually dispatched methods of this class
741       * (composed with supertypes, if any).
742       */
743      @Override
744      @Pure
745      public RVMMethod[] getVirtualMethods() {
746        if (VM.VerifyAssertions) VM._assert(isResolved());
747        return virtualMethods;
748      }
749    
750      /**
751       * @return All of the interfaces implemented by this class either
752       * directly or by inheritance from superclass and superinterfaces
753       * recursively.
754       */
755      @Pure
756      public RVMClass[] getAllImplementedInterfaces() {
757        if (VM.VerifyAssertions) VM._assert(isResolved());
758        int count = 0;
759        int[] doesImplement = getDoesImplement();
760        for (int mask : doesImplement) {
761          while (mask != 0) {
762            count++;
763            mask &= (mask - 1); // clear lsb 1 bit
764          }
765        }
766        if (count == 0) return emptyVMClass;
767        RVMClass[] ans = new RVMClass[count];
768        for (int i = 0, idx = 0; i < doesImplement.length; i++) {
769          int mask = doesImplement[i];
770          if (mask != 0) {
771            for (int j = 0; j < 32; j++) {
772              if ((mask & (1 << j)) != 0) {
773                int id = 32 * i + j;
774                ans[idx++] = RVMClass.getInterface(id);
775              }
776            }
777          }
778        }
779        return ans;
780      }
781    
782      /**
783       * Total size, in bytes, of an instance of this class
784       * (including object header).
785       */
786      @Uninterruptible
787      public int getInstanceSize() {
788        if (VM.VerifyAssertions) VM._assert(isResolved());
789        return instanceSize;
790      }
791    
792      /**
793       * Total size, in bytes, of an instance of this class (including
794       * object header). Doesn't perform any verification.
795       */
796      @Uninterruptible
797      public int getInstanceSizeInternal() {
798        return instanceSize;
799      }
800    
801      /**
802       * Set the size of the instance. Only meant to be called from
803       * ObjectModel et al. must be called when lock on class object
804       * is already held (ie from resolve).
805       */
806      @Uninterruptible
807      public void setInstanceSizeInternal(int size) {
808        instanceSize = size;
809      }
810    
811      /**
812       * Offsets of reference-containing instance fields of this class type.
813       * Offsets are with respect to object pointer -- see RVMField.getOffset().
814       */
815      @Uninterruptible
816      public int[] getReferenceOffsets() {
817        if (VM.VerifyAssertions) VM._assert(isResolved());
818        return referenceOffsets;
819      }
820    
821      /**
822       * @return number of fields that are non-final
823       */
824      public int getNumberOfNonFinalReferences() {
825        int count = 0;
826        for(RVMField field: declaredFields) {
827          if (!field.isFinal()) {
828            count++;
829          }
830        }
831        return count;
832      }
833    
834      /**
835       * Set object representing available holes in the field layout
836       */
837      public FieldLayoutContext getFieldLayoutContext() {
838        return fieldLayoutContext;
839      }
840    
841      /**
842       * Set object representing available holes in the field layout
843       */
844      public void setFieldLayoutContext(FieldLayoutContext newLayout) {
845        fieldLayoutContext = isFinal() ? null : newLayout;
846      }
847    
848      /**
849       * @return alignment for instances of this class type
850       */
851      @Uninterruptible
852      public int getAlignment() {
853        if (BYTES_IN_ADDRESS == BYTES_IN_DOUBLE) {
854          return BYTES_IN_ADDRESS;
855        } else {
856          return alignment;
857        }
858      }
859    
860      /**
861       * Set the alignment for instances of this class type
862       */
863      public void setAlignment(int align) {
864        if (BYTES_IN_ADDRESS != BYTES_IN_DOUBLE) {
865          if (VM.VerifyAssertions) VM._assert(align >= alignment);
866          alignment = align;
867        }
868      }
869    
870      /**
871       * Find specified static method description.
872       * @param memberName method name - something like "foo"
873       * @param memberDescriptor method descriptor - something like "I" or "()I"
874       * @return method description (null --> not found)
875       */
876      @Pure
877      public RVMMethod findStaticMethod(Atom memberName, Atom memberDescriptor) {
878        if (VM.VerifyAssertions) VM._assert(isResolved());
879        for (RVMMethod method : getStaticMethods()) {
880          if (method.getName() == memberName && method.getDescriptor() == memberDescriptor) {
881            return method;
882          }
883        }
884        return null;
885      }
886    
887      /**
888       * Find specified initializer method description.
889       * @param  memberDescriptor  init method descriptor - something like "(I)V"
890       * @return method description (null --> not found)
891       */
892      @Pure
893      public RVMMethod findInitializerMethod(Atom memberDescriptor) {
894        if (VM.VerifyAssertions) VM._assert(isResolved());
895        for (RVMMethod method : getConstructorMethods()) {
896          if (method.getDescriptor() == memberDescriptor) {
897            return method;
898          }
899        }
900        return null;
901      }
902    
903      /**
904       * Runtime type information for this class type.
905       */
906      @Override
907      @Uninterruptible
908      public TIB getTypeInformationBlock() {
909        if (VM.VerifyAssertions) VM._assert(isResolved());
910        return typeInformationBlock;
911      }
912    
913      //--------------------------------------------------------------------//
914      //                     Miscellaneous queries.                         //
915      //---------------------------------------------------------------------//
916    
917      /**
918       * Support for user-written class loaders:
919       * It's required to find the classloader of the class
920       * whose method requires another class to be loaded;
921       * the initiating loader of the required class is the
922       * defining loader of the requiring class.
923       *
924       *
925       * @param skip specifies the number of frames back from the
926       *             caller to the method whose class's loader is required
927       */
928      public static ClassLoader getClassLoaderFromStackFrame(int skip) {
929        skip++; // account for stack frame of this function
930        StackBrowser browser = new StackBrowser();
931        VM.disableGC();
932        browser.init();
933        while (skip-- > 0) browser.up();
934        VM.enableGC();
935        return browser.getClassLoader();
936      }
937    
938      /**
939       * Used for accessibility checks in reflection code.
940       * Find the class of the method that corresponds to the requested frame.
941       *
942       * @param skip   Specifies the number of frames back from the
943       *               caller to the method whose class is required
944       */
945      public static RVMClass getClassFromStackFrame(int skip) {
946        skip++; // account for stack frame of this function
947        StackBrowser browser = new StackBrowser();
948        VM.disableGC();
949        browser.init();
950        while (skip-- > 0) browser.up();
951        VM.enableGC();
952        return browser.getCurrentClass();
953      }
954    
955      /**
956       * Should assertions be enabled on this type?
957       */
958      @Override
959      @Pure
960      public boolean getDesiredAssertionStatus() {
961        return desiredAssertionStatus;
962      }
963    
964      //--------------------------------------------------------------------//
965      //      Load, Resolve, Instantiate, and Initialize                    //
966      //--------------------------------------------------------------------//
967    
968      /**
969       * Construct a class from its constituent loaded parts
970       *
971       * @param typeRef the type reference that was resolved to this class
972       * @param constantPool array of ints encoding constant value
973       * @param modifiers {@link org.jikesrvm.classloader.ClassLoaderConstants}
974       * @param superClass parent of this class
975       * @param declaredInterfaces array of interfaces this class implements
976       * @param declaredFields fields of the class
977       * @param declaredMethods methods of the class
978       * @param declaredClasses declared inner classes
979       * @param declaringClass outer class if an inner class
980       * @param sourceName source file name
981       * @param classInitializerMethod handle to class initializer method
982       * @param signature the generic type name for this class
983       * @param annotations array of runtime visible annotations
984       */
985      RVMClass(TypeReference typeRef, int[] constantPool, short modifiers, RVMClass superClass,
986               RVMClass[] declaredInterfaces, RVMField[] declaredFields, RVMMethod[] declaredMethods,
987               TypeReference[] declaredClasses, TypeReference declaringClass, TypeReference enclosingClass,
988               MethodReference enclosingMethod, Atom sourceName, RVMMethod classInitializerMethod,
989               Atom signature, RVMAnnotation[] annotations) {
990        super(typeRef, 0, annotations);
991        if (VM.VerifyAssertions) VM._assert(!getTypeRef().isUnboxedType());
992        if (VM.VerifyAssertions && null != superClass) VM._assert(!superClass.getTypeRef().isUnboxedType());
993    
994        // final fields
995        this.constantPool = constantPool;
996        this.modifiers = modifiers;
997        this.superClass = superClass;
998        this.declaredInterfaces = declaredInterfaces;
999        this.declaredFields = declaredFields;
1000        this.declaredMethods = declaredMethods;
1001        this.declaredClasses = declaredClasses;
1002        this.declaringClass = declaringClass;
1003        this.enclosingClass = enclosingClass;
1004        this.enclosingMethod = enclosingMethod;
1005        this.sourceName = sourceName;
1006        this.classInitializerMethod = classInitializerMethod;
1007        this.signature = signature;
1008    
1009        // non-final fields
1010        this.subClasses = emptyVMClass;
1011        state = CLASS_LOADED;
1012    
1013        // we're about to leak a reference to 'this' force memory to be
1014        // consistent
1015        Magic.sync();
1016    
1017        if (superClass != null) {
1018          // MUST wait until end of constructor to 'publish' the subclass link.
1019          // If we do this earlier, then people can see an incomplete RVMClass object
1020          // by traversing the subclasses of our superclass!
1021          superClass.addSubClass(this);
1022        }
1023    
1024        this.desiredAssertionStatus = RVMClassLoader.getDesiredAssertionStatus(this);
1025    
1026        Callbacks.notifyClassLoaded(this);
1027    
1028        if (VM.TraceClassLoading && VM.runningVM) {
1029          VM.sysWriteln("RVMClass: (end)   load file " + typeRef.getName());
1030        }
1031        if (VM.verboseClassLoading) VM.sysWrite("[Loaded " + toString() + "]\n");
1032      }
1033    
1034      /**
1035       * Generate size and offset information for members of this class and
1036       * allocate space in jtoc for static fields, static methods, and virtual
1037       * method table.
1038       * Side effects: superclasses and superinterfaces are resolved.
1039       */
1040      @Override
1041      public synchronized void resolve() {
1042        if (isResolved()) return;
1043        if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (begin) resolve " + this);
1044        if (VM.VerifyAssertions) VM._assert(state == CLASS_LOADED);
1045    
1046        // Resolve superclass and super interfaces
1047        //
1048        if (superClass != null) {
1049          superClass.resolve();
1050        }
1051        for (RVMClass declaredInterface : declaredInterfaces) {
1052          declaredInterface.resolve();
1053        }
1054    
1055        if (isInterface()) {
1056          if (VM.VerifyAssertions) VM._assert(superClass == null);
1057          depth = 1;
1058          thinLockOffset = Offset.max();
1059        } else if (superClass == null) {
1060          if (VM.VerifyAssertions) VM._assert(isJavaLangObjectType());
1061          instanceSize = ObjectModel.computeScalarHeaderSize(this);
1062          alignment = BYTES_IN_ADDRESS;
1063          thinLockOffset = ObjectModel.defaultThinLockOffset();
1064          depth=0;
1065        } else {
1066          depth = superClass.depth + 1;
1067          thinLockOffset = superClass.thinLockOffset;
1068          instanceSize = superClass.instanceSize;
1069          fieldLayoutContext = superClass.fieldLayoutContext;
1070          alignment = superClass.alignment;
1071        }
1072    
1073        if (this == RVMType.JavaLangClassType) {
1074          ObjectModel.allocateThinLock(this);
1075        }
1076    
1077        if (superClass != null && superClass.isNonMoving() && !isNonMoving()) {
1078          VM.sysWriteln("WARNING: movable " + this + " extends non-moving " + superClass);
1079        }
1080    
1081        if (VM.verboseClassLoading) VM.sysWrite("[Preparing " + this + "]\n");
1082    
1083        // build field and method lists for this class
1084        //
1085        {
1086          FieldVector staticFields = new FieldVector();
1087          FieldVector instanceFields = new FieldVector();
1088          MethodVector staticMethods = new MethodVector();
1089          MethodVector constructorMethods = new MethodVector();
1090          MethodVector virtualMethods = new MethodVector();
1091    
1092          // start with fields and methods of superclass
1093          //
1094          if (superClass != null) {
1095            for (RVMField field : superClass.getInstanceFields()) {
1096              instanceFields.addElement(field);
1097            }
1098    
1099            for (RVMMethod method : superClass.getVirtualMethods()) {
1100              virtualMethods.addElement(method);
1101            }
1102          }
1103    
1104          // append fields defined by this class
1105          //
1106          for (RVMField field : getDeclaredFields()) {
1107            if (field.isStatic()) {
1108              staticFields.addElement(field);
1109            } else {
1110              instanceFields.addElement(field);
1111            }
1112          }
1113    
1114          // append/overlay methods defined by this class
1115          //
1116          for (RVMMethod method : getDeclaredMethods()) {
1117            if (VM.VerifyUnint) {
1118              if (method.isSynchronized() && method.isUninterruptible()) {
1119                if (VM.ParanoidVerifyUnint || !method.hasLogicallyUninterruptibleAnnotation()) {
1120                  VM.sysWriteln("WARNING: " + method + " cannot be both uninterruptible and synchronized");
1121                }
1122              }
1123            }
1124    
1125            if (method.isObjectInitializer()) {
1126              Callbacks.notifyMethodOverride(method, null);
1127              constructorMethods.addElement(method);
1128            } else if (method.isStatic()) {
1129              if (!method.isClassInitializer()) {
1130                Callbacks.notifyMethodOverride(method, null);
1131                staticMethods.addElement(method);
1132              }
1133            } else { // Virtual method
1134    
1135              if (method.isSynchronized()) {
1136                ObjectModel.allocateThinLock(this);
1137              }
1138    
1139              // method could override something in superclass - check for it
1140              //
1141              int superclassMethodIndex = -1;
1142              for (int j = 0, m = virtualMethods.size(); j < m; ++j) {
1143                RVMMethod alreadyDefinedMethod = virtualMethods.elementAt(j);
1144                if (alreadyDefinedMethod.getName() == method.getName() &&
1145                    alreadyDefinedMethod.getDescriptor() == method.getDescriptor()) {
1146                  // method already defined in superclass
1147                  superclassMethodIndex = j;
1148                  break;
1149                }
1150              }
1151    
1152              if (superclassMethodIndex == -1) {
1153                Callbacks.notifyMethodOverride(method, null);
1154                virtualMethods.addElement(method);                          // append
1155              } else {
1156                RVMMethod superc = virtualMethods.elementAt(superclassMethodIndex);
1157                if (VM.VerifyUnint) {
1158                  if (!superc.isInterruptible() && method.isInterruptible()) {
1159                    VM.sysWriteln("WARNING: interruptible " + method + " overrides uninterruptible " + superc);
1160                  }
1161                }
1162                Callbacks.notifyMethodOverride(method, superc);
1163                virtualMethods.setElementAt(method, superclassMethodIndex); // override
1164              }
1165            }
1166          }
1167    
1168          // Deal with Miranda methods.
1169          // If this is an abstract class, then for each
1170          // interface that this class implements, ensure that a corresponding virtual
1171          // method is declared.  If one is not, then create an abstract method to fill the void.
1172          if (!isInterface() && isAbstract()) {
1173            for (RVMClass I : declaredInterfaces) {
1174              RVMMethod[] iMeths = I.getVirtualMethods();
1175              outer:
1176              for (RVMMethod iMeth : iMeths) {
1177                Atom iName = iMeth.getName();
1178                Atom iDesc = iMeth.getDescriptor();
1179                for (int k = 0; k < virtualMethods.size(); k++) {
1180                  RVMMethod vMeth = virtualMethods.elementAt(k);
1181                  if (vMeth.getName() == iName && vMeth.getDescriptor() == iDesc) continue outer;
1182                }
1183                MemberReference mRef = MemberReference.findOrCreate(typeRef, iName, iDesc);
1184                virtualMethods.addElement(new AbstractMethod(getTypeRef(),
1185                                                                mRef,
1186                                                                (short) (ACC_ABSTRACT | ACC_PUBLIC),
1187                                                                iMeth.getExceptionTypes(),
1188                                                                null,
1189                                                                null,
1190                                                                null,
1191                                                                null));
1192              }
1193            }
1194          }
1195    
1196          // If this is an interface, inherit methods from its superinterfaces
1197          if (isInterface()) {
1198            for (RVMClass declaredInterface : declaredInterfaces) {
1199              RVMMethod[] meths = declaredInterface.getVirtualMethods();
1200              for (RVMMethod meth : meths) {
1201                virtualMethods.addUniqueElement(meth);
1202              }
1203            }
1204          }
1205    
1206          this.staticFields = staticFields.finish();
1207          this.instanceFields = instanceFields.finish();
1208          this.staticMethods = staticMethods.finish();
1209          this.constructorMethods = constructorMethods.finish();
1210          this.virtualMethods = virtualMethods.finish();
1211        }
1212    
1213        // allocate space for class fields
1214        //
1215        for (RVMField field : staticFields) {
1216          if (field.isReferenceType()) {
1217            field.setOffset(Statics.allocateReferenceSlot(true));
1218          } else if (field.getSize() <= BYTES_IN_INT) {
1219            field.setOffset(Statics.allocateNumericSlot(BYTES_IN_INT, true));
1220          } else {
1221            field.setOffset(Statics.allocateNumericSlot(BYTES_IN_LONG, true));
1222          }
1223    
1224          // (SJF): Serialization nastily accesses even final private static
1225          //           fields via pseudo-reflection! So, we must shove the
1226          //           values of final static fields into the JTOC.  Now
1227          //           seems to be a good time.
1228          if (field.isFinal()) {
1229            setFinalStaticJTOCEntry(field, field.getOffset());
1230          }
1231        }
1232    
1233        // lay out instance fields
1234        //
1235        ObjectModel.layoutInstanceFields(this);
1236    
1237        // count reference fields
1238        int referenceFieldCount = 0;
1239        for (RVMField field : instanceFields) {
1240          if (field.isTraced()) {
1241            referenceFieldCount += 1;
1242          }
1243        }
1244    
1245        // record offsets of those instance fields that contain references
1246        //
1247        if (typeRef.isRuntimeTable()) {
1248          referenceOffsets = MemoryManager.newNonMovingIntArray(0);
1249        } else {
1250          referenceOffsets = MemoryManager.newNonMovingIntArray(referenceFieldCount);
1251          int j = 0;
1252          for (RVMField field : instanceFields) {
1253            if (field.isTraced()) {
1254              referenceOffsets[j++] = field.getOffset().toInt();
1255            }
1256          }
1257        }
1258    
1259        // Allocate space for <init> method pointers
1260        //
1261        for (RVMMethod method : constructorMethods) {
1262          method.setOffset(Statics.allocateReferenceSlot(true));
1263        }
1264    
1265        // Allocate space for static method pointers
1266        //
1267        for (RVMMethod method : staticMethods) {
1268          if (method.isClassInitializer()) {
1269            method.setOffset(Offset.fromIntZeroExtend(0xebad0ff5)); // should never be used.
1270          } else {
1271            method.setOffset(Statics.allocateReferenceSlot(true));
1272          }
1273        }
1274    
1275        if (!isInterface()) {
1276          // lay out virtual method section of type information block
1277          // (to be filled in by instantiate)
1278          for (int i = 0, n = virtualMethods.length; i < n; ++i) {
1279            RVMMethod method = virtualMethods[i];
1280            method.setOffset(TIB.getVirtualMethodOffset(i));
1281          }
1282        }
1283    
1284        // RCGC: Determine if class is inherently acyclic
1285        acyclic = false;    // must initially be false for recursive types
1286        boolean foundCyclic = false;
1287        for (RVMField instanceField : instanceFields) {
1288          TypeReference ft = instanceField.getType();
1289          if (!ft.isResolved() || !ft.peekType().isAcyclicReference()) {
1290            foundCyclic = true;
1291            break;
1292          }
1293        }
1294        if (!foundCyclic) {
1295          acyclic = true;
1296        }
1297    
1298        // allocate "type information block"
1299        TIB allocatedTib;
1300        if (isInterface()) {
1301          allocatedTib = MemoryManager.newTIB(0);
1302        } else {
1303          allocatedTib = MemoryManager.newTIB(virtualMethods.length);
1304        }
1305    
1306        superclassIds = DynamicTypeCheck.buildSuperclassIds(this);
1307        doesImplement = DynamicTypeCheck.buildDoesImplement(this);
1308    
1309        // can't move this beyond "finalize" code block as findVirtualMethod
1310        // assumes state >= RESOLVED, no allocation occurs until
1311        // state >= CLASS_INITIALIZING
1312        publishResolved(allocatedTib, superclassIds, doesImplement);
1313    
1314        // TODO: Make this into a more general listener interface
1315        if (VM.BuildForOptCompiler && VM.writingBootImage) {
1316          classLoadListener.classInitialized(this, true);
1317        }
1318    
1319        Callbacks.notifyClassResolved(this);
1320        MemoryManager.notifyClassResolved(this);
1321    
1322        // check for a "finalize" method that overrides the one in java.lang.Object
1323        //
1324        if (!isInterface()) {
1325          final RVMMethod method =
1326              findVirtualMethod(RVMClassLoader.StandardObjectFinalizerMethodName,
1327                                RVMClassLoader.StandardObjectFinalizerMethodDescriptor);
1328          if (!method.getDeclaringClass().isJavaLangObjectType()) {
1329            hasFinalizer = true;
1330          }
1331        }
1332    
1333        if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (end)   resolve " + this);
1334      }
1335    
1336      /**
1337       * Atomically initialize the important parts of the TIB and let the world know this type is
1338       * resolved.
1339       *
1340       * @param allocatedTib The TIB that has been allocated for this type
1341       * @param superclassIds The calculated superclass ids array
1342       * @param doesImplement The calculated does implement array
1343       */
1344      @Uninterruptible
1345      private void publishResolved(TIB allocatedTib, short[] superclassIds, int[] doesImplement) {
1346        Statics.setSlotContents(getTibOffset(), allocatedTib);
1347        allocatedTib.setType(this);
1348        allocatedTib.setSuperclassIds(superclassIds);
1349        allocatedTib.setDoesImplement(doesImplement);
1350        typeInformationBlock = allocatedTib;
1351        state = CLASS_RESOLVED;
1352      }
1353    
1354      @Override
1355      public void allBootImageTypesResolved() {
1356        for (RVMMethod method : declaredMethods) {
1357          if (method instanceof NormalMethod) {
1358            ((NormalMethod)method).recomputeSummary(constantPool);
1359          }
1360        }
1361      }
1362    
1363    
1364      // RCGC: A reference to class is acyclic if the class is acyclic and
1365      // final (otherwise the reference could be to a subsequently loaded
1366      // cyclic subclass).
1367      //
1368      @Override
1369      @Uninterruptible
1370      public boolean isAcyclicReference() {
1371        return acyclic && isFinal();
1372      }
1373    
1374      /**
1375       * Insert the value of a final static field into the JTOC
1376       */
1377      private void setFinalStaticJTOCEntry(RVMField field, Offset fieldOffset) {
1378        if (!field.isFinal()) return;
1379    
1380        // value Index: index into the classes constant pool.
1381        int valueIndex = field.getConstantValueIndex();
1382    
1383        // if there's no value in the constant pool, bail out
1384        if (valueIndex <= 0) return;
1385    
1386        Offset literalOffset = field.getDeclaringClass().getLiteralOffset(valueIndex);
1387    
1388        if (Statics.isReference(Statics.offsetAsSlot(fieldOffset))) {
1389          Object obj = Statics.getSlotContentsAsObject(literalOffset);
1390          Statics.setSlotContents(fieldOffset, obj);
1391        } else if (field.getSize() <= BYTES_IN_INT) {
1392          // copy one word from constant pool to JTOC
1393          int value = Statics.getSlotContentsAsInt(literalOffset);
1394          Statics.setSlotContents(fieldOffset, value);
1395        } else {
1396          // copy two words from constant pool to JTOC
1397          long value = Statics.getSlotContentsAsLong(literalOffset);
1398          Statics.setSlotContents(fieldOffset, value);
1399        }
1400      }
1401    
1402      /**
1403       * Compile this class's methods, build type information block, populate jtoc.
1404       * Side effects: superclasses are instantiated.
1405       */
1406      @Override
1407      public synchronized void instantiate() {
1408        if (isInstantiated()) {
1409          return;
1410        }
1411    
1412        if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (begin) instantiate " + this);
1413        if (VM.VerifyAssertions) VM._assert(state == CLASS_RESOLVED);
1414    
1415        // instantiate superclass
1416        //
1417        if (superClass != null) {
1418          superClass.instantiate();
1419        }
1420        if (VM.runningVM) {
1421          // can't instantiate if building bootimage, since this can cause
1422          // class initializer to be lost (when interface is not included in bootimage).
1423          // since we don't need to instantiate/initialize for the purposes of
1424          // dynamic type checking and interface invocation, defer it until runtime
1425          // and the class actually refers to a static field of the interface.
1426          for (RVMClass declaredInterface : declaredInterfaces) {
1427            declaredInterface.instantiate();
1428          }
1429        }
1430    
1431        if (!isInterface()) {
1432          // Create the internal lazy method invoker trampoline
1433          typeInformationBlock.initializeInternalLazyCompilationTrampoline();
1434    
1435          // Initialize slots in the TIB for virtual methods
1436          for(int i=0; i < virtualMethods.length; i++) {
1437            RVMMethod method = virtualMethods[i];
1438            if (method.isPrivate() && method.getDeclaringClass() != this) {
1439              typeInformationBlock.setVirtualMethod(i, null); // an inherited private method....will never be invoked via this TIB
1440            } else {
1441              typeInformationBlock.setVirtualMethod(i, method.getCurrentEntryCodeArray());
1442            }
1443          }
1444    
1445          // compile <init> methods and put their addresses into jtoc
1446          for (RVMMethod method : constructorMethods) {
1447            Statics.setSlotContents(method.getOffset(), method.getCurrentEntryCodeArray());
1448          }
1449    
1450          // compile static methods and put their addresses into jtoc
1451          for (RVMMethod method : staticMethods) {
1452            // don't bother compiling <clinit> here;
1453            // compile it right before we invoke it in initialize.
1454            // This also avoids putting <clinit>s in the bootimage.
1455            if (!method.isClassInitializer()) {
1456              Statics.setSlotContents(method.getOffset(), method.getCurrentEntryCodeArray());
1457            }
1458          }
1459        }
1460    
1461        InterfaceInvocation.initializeDispatchStructures(this);
1462        SpecializedMethodManager.notifyTypeInstantiated(this);
1463    
1464        if (VM.writingBootImage) {
1465          state = CLASS_INITIALIZED;
1466          // Mark final fields as literals as class initializer won't have been called
1467          markFinalFieldsAsLiterals();
1468        } else {
1469          state = CLASS_INSTANTIATED;
1470        }
1471    
1472        Callbacks.notifyClassInstantiated(this);
1473        if (VM.writingBootImage) {
1474          Callbacks.notifyClassInitialized(this);
1475        }
1476    
1477        if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (end)   instantiate " + this);
1478      }
1479    
1480      /**
1481       * Make the passed field a traced field by garbage collection. Also affects all
1482       * subclasses.
1483       */
1484      public synchronized void makeFieldTraced(RVMField field) {
1485        int[] oldOffsets = referenceOffsets;
1486        int fieldOffset = field.getOffset().toInt();
1487        referenceOffsets = MemoryManager.newNonMovingIntArray(oldOffsets.length + 1);
1488        int i;
1489        for(i=0; i < oldOffsets.length && oldOffsets[i] < fieldOffset; i++) {
1490          referenceOffsets[i] = oldOffsets[i];
1491        }
1492        if (VM.VerifyAssertions) VM._assert(oldOffsets[i] != fieldOffset, "Field is already traced!");
1493        referenceOffsets[i++] = fieldOffset;
1494        while(i < referenceOffsets.length) {
1495          referenceOffsets[i] = oldOffsets[i-1];
1496          i++;
1497        }
1498        SpecializedMethodManager.refreshSpecializedMethods(this);
1499    
1500        for(RVMClass klass: subClasses) {
1501          klass.makeFieldTraced(field);
1502        }
1503      }
1504    
1505      /**
1506       * Execute this class's static initializer, <clinit>.
1507       * Side effects: superclasses are initialized, static fields receive
1508       * initial values.
1509       */
1510      @Override
1511      public synchronized void initialize() throws ExceptionInInitializerError {
1512        if (isInitialized()) {
1513          return;
1514        }
1515    
1516        if (state == CLASS_INITIALIZING) {
1517          return;
1518        }
1519    
1520        if (state == CLASS_INITIALIZER_FAILED) {
1521          throw new NoClassDefFoundError(this+" (initialization failure)");
1522        }
1523    
1524        if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (begin) initialize " + this);
1525        if (VM.VerifyAssertions) VM._assert(state == CLASS_INSTANTIATED);
1526        state = CLASS_INITIALIZING;
1527        if (VM.verboseClassLoading) VM.sysWrite("[Initializing " + this + "]\n");
1528    
1529        // run super <clinit>
1530        //
1531        if (superClass != null) {
1532          superClass.initialize();
1533        }
1534    
1535        // run <clinit>
1536        //
1537        if (classInitializerMethod != null) {
1538          CompiledMethod cm = classInitializerMethod.getCurrentCompiledMethod();
1539          while (cm == null) {
1540            classInitializerMethod.compile();
1541            cm = classInitializerMethod.getCurrentCompiledMethod();
1542          }
1543    
1544          if (VM.verboseClassLoading) VM.sysWrite("[Running static initializer for " + this + "]\n");
1545    
1546          try {
1547            Magic.invokeClassInitializer(cm.getEntryCodeArray());
1548          } catch (Error e) {
1549            state = CLASS_INITIALIZER_FAILED;
1550            throw e;
1551          } catch (Throwable t) {
1552            ExceptionInInitializerError eieio = new ExceptionInInitializerError("While initializing " + this);
1553            eieio.initCause(t);
1554            state = CLASS_INITIALIZER_FAILED;
1555            if (VM.verboseClassLoading) {
1556              VM.sysWriteln("[Exception in initializer error caused by:");
1557              t.printStackTrace();
1558              VM.sysWriteln("]");
1559            }
1560            throw eieio;
1561          }
1562    
1563          // <clinit> is no longer needed: reclaim space by removing references to it
1564          classInitializerMethod.invalidateCompiledMethod(cm);
1565          classInitializerMethod = null;
1566        }
1567    
1568        if (VM.BuildForOptCompiler) {
1569          // report that a class is about to be marked initialized to
1570          // the opt compiler so it can invalidate speculative CHA optimizations
1571          // before an instance of this class could actually be created.
1572          classLoadListener.classInitialized(this, false);
1573        }
1574    
1575        state = CLASS_INITIALIZED;
1576    
1577        Callbacks.notifyClassInitialized(this);
1578    
1579        markFinalFieldsAsLiterals();
1580    
1581        if (VM.verboseClassLoading) VM.sysWrite("[Initialized " + this + "]\n");
1582        if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (end)   initialize " + this);
1583      }
1584    
1585      /**
1586       * Mark final fields as being available as literals
1587       */
1588      private void markFinalFieldsAsLiterals() {
1589        for (RVMField f : getStaticFields()) {
1590          if (f.isFinal()) {
1591            Offset fieldOffset = f.getOffset();
1592            if (Statics.isReference(Statics.offsetAsSlot(fieldOffset))) {
1593              Statics.markAsReferenceLiteral(fieldOffset);
1594            } else {
1595              Statics.markAsNumericLiteral(f.getSize(), fieldOffset);
1596            }
1597          }
1598        }
1599      }
1600    
1601      /**
1602       * Copy the values of all static final fields into
1603       * the JTOC.  Note: This method should only be run AFTER
1604       * the class initializer has run.
1605       */
1606      public void setAllFinalStaticJTOCEntries() {
1607        if (VM.VerifyAssertions) VM._assert(isInitialized());
1608        for (RVMField f : getStaticFields()) {
1609          if (f.isFinal()) {
1610            setFinalStaticJTOCEntry(f, f.getOffset());
1611          }
1612        }
1613      }
1614    
1615      void resolveNativeMethods() {
1616        if (VM.VerifyAssertions) VM._assert(isInitialized());
1617        resolveNativeMethodsInternal(getStaticMethods());
1618        resolveNativeMethodsInternal(getVirtualMethods());
1619      }
1620    
1621      private void resolveNativeMethodsInternal(RVMMethod[] methods) {
1622        for (RVMMethod m : methods) {
1623          if (m.isNative()) {
1624            m.replaceCompiledMethod(null);
1625          }
1626        }
1627      }
1628    
1629      /**
1630       * Unregisters all native methods
1631       */
1632      public void unregisterNativeMethods() {
1633        if (VM.VerifyAssertions) VM._assert(isInitialized());
1634        for (RVMMethod m : declaredMethods) {
1635          if (m.isNative()) {
1636            NativeMethod nm = (NativeMethod) m;
1637            nm.unregisterNativeSymbol();
1638            m.replaceCompiledMethod(null);
1639          }
1640        }
1641      }
1642    
1643      /**
1644       * Add to list of classes that derive from this one.
1645       */
1646      private void addSubClass(RVMClass sub) {
1647        int n = subClasses.length;
1648        RVMClass[] tmp = new RVMClass[n + 1];
1649    
1650        for (int i = 0; i < n; ++i) {
1651          tmp[i] = subClasses[i];
1652        }
1653        tmp[n] = sub;
1654    
1655        subClasses = tmp;
1656      }
1657    
1658      //------------------------------------------------------------//
1659      // Support for speculative optimizations that may need to
1660      // invalidate compiled code when new classes are loaded.
1661      //
1662      // TODO: Make this into a more general listener API
1663      //------------------------------------------------------------//
1664      public static final ClassLoadingListener classLoadListener =
1665          VM.BuildForOptCompiler ? new ClassLoadingDependencyManager() : null;
1666    
1667      /**
1668       * Given a method declared by this class, update all
1669       * dispatching tables to refer to the current compiled
1670       * code for the method.
1671       */
1672      public void updateMethod(RVMMethod m) {
1673        if (VM.VerifyAssertions) VM._assert(isResolved());
1674        if (VM.VerifyAssertions) VM._assert(m.getDeclaringClass() == this);
1675        if (m.isClassInitializer()) return; // we never put this method in the jtoc anyways!
1676    
1677        if (m.isStatic() || m.isObjectInitializer()) {
1678          updateJTOCEntry(m);
1679        } else {
1680          updateVirtualMethod(m);
1681        }
1682      }
1683    
1684      /**
1685       * Update the JTOC slot for the given static method to point to
1686       * the current compiled code for the given method.
1687       * NOTE: This method is intentionally not synchronized to avoid deadlocks.
1688       *       We instead rely on the fact that we are always updating the JTOC with
1689       *       the most recent instructions for the method.
1690       */
1691      public void updateJTOCEntry(RVMMethod m) {
1692        if (VM.VerifyAssertions) VM._assert(m.getDeclaringClass() == this);
1693        if (VM.VerifyAssertions) VM._assert(isResolved());
1694        if (VM.VerifyAssertions) VM._assert(m.isStatic() || m.isObjectInitializer());
1695        Statics.setSlotContents(m.getOffset(), m.getCurrentEntryCodeArray());
1696      }
1697    
1698      /**
1699       * Update this class's TIB entry for the given method to point to
1700       * the current compiled code for the given method.
1701       * NOTE: This method is intentionally not synchronized to avoid deadlocks.
1702       *       We instead rely on the fact that we are always updating the JTOC with
1703       *       the most recent instructions for the method.
1704       */
1705      public void updateTIBEntry(RVMMethod m) {
1706        if (VM.VerifyAssertions) {
1707          RVMMethod vm = findVirtualMethod(m.getName(), m.getDescriptor());
1708          VM._assert(vm == m);
1709        }
1710        typeInformationBlock.setVirtualMethod(m.getOffset(), m.getCurrentEntryCodeArray());
1711        InterfaceInvocation.updateTIBEntry(this, m);
1712      }
1713    
1714      /**
1715       * Update the TIB entry's for all classes that inherit the given method
1716       * to point to the current compiled code for the given method.
1717       * NOTE: This method is intentionally not synchronized to avoid deadlocks.
1718       *       We instead rely on the fact that we are always updating the JTOC with
1719       *       the most recent instructions for the method.
1720       */
1721      public void updateVirtualMethod(RVMMethod m) {
1722        RVMMethod dm = findDeclaredMethod(m.getName(), m.getDescriptor());
1723        if (dm != null && dm != m) return;  // this method got overridden
1724        updateTIBEntry(m);
1725        if (m.isPrivate()) return; // can't override
1726        for (RVMClass sc : getSubClasses()) {
1727          if (sc.isResolved()) {
1728            sc.updateVirtualMethod(m);
1729          }
1730        }
1731      }
1732    
1733      //------------------------------------------------------------//
1734      // Additional fields and methods for Interfaces               //
1735      //------------------------------------------------------------//
1736    
1737      private static final Object interfaceCountLock = new Object();
1738      private static int interfaceCount = 0;
1739      private static RVMClass[] interfaces;
1740      private int interfaceId = -1;
1741      RVMMethod[] noIMTConflictMap; // used by InterfaceInvocation to support resetTIB
1742    
1743      /**
1744       * Classes used as Interfaces get assigned an interface id.
1745       *   If the class is not an interface, attempting to use this
1746       *   id will cause an IncompatibleClassChangeError to be thrown
1747       */
1748      public int getInterfaceId() {
1749        if (interfaceId == -1) {
1750          assignInterfaceId();
1751        }
1752        return interfaceId;
1753      }
1754    
1755      public int getDoesImplementIndex() {
1756        return getInterfaceId() >>> 5;
1757      }
1758    
1759      public int getDoesImplementBitMask() {
1760        return 1 << (getInterfaceId() & 31);
1761      }
1762    
1763      public static RVMClass getInterface(int id) {
1764        return interfaces[id];
1765      }
1766    
1767      private synchronized void assignInterfaceId() {
1768        if (interfaceId == -1) {
1769          if (interfaceCountLock != null && interfaces != null) {
1770            synchronized (interfaceCountLock) {
1771              interfaceId = interfaceCount++;
1772              if (interfaceId == interfaces.length) {
1773                RVMClass[] tmp = new RVMClass[interfaces.length * 2];
1774                System.arraycopy(interfaces, 0, tmp, 0, interfaces.length);
1775                interfaces = tmp;
1776              }
1777              interfaces[interfaceId] = this;
1778            }
1779          } else {
1780            interfaceId = interfaceCount++;
1781            if (interfaces == null) {
1782              interfaces = new RVMClass[200];
1783            }
1784            interfaces[interfaceId] = this;
1785          }
1786        }
1787      }
1788    
1789      /**
1790       * Number of [ in descriptor for arrays; -1 for primitives; 0 for
1791       * classes
1792       * @return 0
1793       */
1794      @Override
1795      @Pure
1796      @Uninterruptible
1797      public int getDimensionality() {
1798        return 0;
1799      }
1800    
1801      /**
1802       * Resolution status.
1803       */
1804      @Override
1805      @Uninterruptible
1806      public boolean isResolved() {
1807        return state >= CLASS_RESOLVED;
1808      }
1809    
1810      /**
1811       * Instantiation status.
1812       */
1813      @Override
1814      @Uninterruptible
1815      public boolean isInstantiated() {
1816        return state >= CLASS_INSTANTIATED;
1817      }
1818    
1819      /**
1820       * Initialization status.
1821       */
1822      @Override
1823      @Uninterruptible
1824      public boolean isInitialized() {
1825        return state == CLASS_INITIALIZED;
1826      }
1827    
1828      /**
1829       * Only intended to be used by the BootImageWriter
1830       */
1831      @Override
1832      public void markAsBootImageClass() {
1833        inBootImage = true;
1834      }
1835    
1836      /**
1837       * Is this class part of the virtual machine's boot image?
1838       */
1839      @Override
1840      @Uninterruptible
1841      public boolean isInBootImage() {
1842        return inBootImage;
1843      }
1844    
1845      /**
1846       * Get the offset in instances of this type assigned to the thin lock word.
1847       * Offset.max() if instances of this type do not have thin lock words.
1848       * Is only known after class has been resolved.
1849       */
1850      @Override
1851      @Uninterruptible
1852      public Offset getThinLockOffset() {
1853        if (VM.VerifyAssertions) VM._assert(isResolved());
1854        return thinLockOffset;
1855      }
1856    
1857     /**
1858       * Set the thin lock offset for instances of this type. Can be called at most once.
1859       * and is invoked from ObjectModel.allocateThinLock (in object models which
1860       * do not allocate thin locks for all scalar object types).
1861       */
1862      public void setThinLockOffset(Offset offset) {
1863        if (VM.VerifyAssertions) VM._assert(thinLockOffset.isMax());
1864        if (VM.VerifyAssertions) VM._assert(!offset.isMax());
1865        thinLockOffset = offset;
1866      }
1867    
1868      /**
1869       * get number of superclasses to Object
1870       */
1871      @Override
1872      @Pure
1873      @Uninterruptible
1874      public int getTypeDepth() {
1875        return depth;
1876      }
1877    
1878      /**
1879       * Whether or not this is an instance of RVMClass?
1880       * @return false
1881       */
1882      @Override
1883      @Pure
1884      @Uninterruptible
1885      public boolean isClassType() {
1886        return true;
1887      }
1888    
1889      /**
1890       * Whether or not this is an instance of RVMArray?
1891       * @return true
1892       */
1893      @Override
1894      @Pure
1895      @Uninterruptible
1896      public boolean isArrayType() {
1897        return false;
1898      }
1899    
1900      /**
1901       * Whether or not this is a primitive type
1902       * @return false
1903       */
1904      @Override
1905      @Pure
1906      @Uninterruptible
1907      public boolean isPrimitiveType() {
1908        return false;
1909      }
1910    
1911      /**
1912       * @return whether or not this is a reference (ie non-primitive) type.
1913       */
1914      @Override
1915      @Pure
1916      @Uninterruptible
1917      public boolean isReferenceType() {
1918        return true;
1919      }
1920    
1921      /**
1922       * @return whether or not this is an unboxed type
1923       */
1924      @Override
1925      @Pure
1926      @Uninterruptible
1927      public boolean isUnboxedType() {
1928        return false;
1929      }
1930    
1931      /**
1932       * Create a synthetic class that extends ReflectionBase and invokes the given method
1933       * @param methodToCall the method we wish to call reflectively
1934       * @return the synthetic class
1935       */
1936      static Class<?> createReflectionClass(RVMMethod methodToCall) {
1937        if (VM.VerifyAssertions) VM._assert(VM.runningVM);
1938        if (DynamicTypeCheck.instanceOfResolved(TypeReference.baseReflectionClass.resolve(), methodToCall.getDeclaringClass())) {
1939          // Avoid reflection on reflection base class
1940          return null;
1941        }
1942        int[] constantPool = new int[methodToCall.getParameterTypes().length+3];
1943        String reflectionClassName = "Lorg/jikesrvm/classloader/ReflectionBase$$Reflect"+methodToCall.getMemberRef().getId()+";";
1944        TypeReference reflectionClass = TypeReference.findOrCreate(reflectionClassName);
1945        RVMType klass = reflectionClass.peekType();
1946        if (klass == null) {
1947          MethodReference reflectionMethodRef = MethodReference.findOrCreate(reflectionClass,
1948              Atom.findOrCreateUnicodeAtom("invokeInternal"),
1949              Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")
1950          ).asMethodReference();
1951          MethodReference constructorMethodRef = MethodReference.findOrCreate(reflectionClass,
1952              Atom.findOrCreateUnicodeAtom("<init>"),
1953              Atom.findOrCreateUnicodeAtom("()V")
1954          ).asMethodReference();
1955    
1956          RVMMethod[] reflectionMethods = new RVMMethod[]{
1957              methodToCall.createReflectionMethod(reflectionClass, constantPool, reflectionMethodRef),
1958              RVMMethod.createDefaultConstructor(reflectionClass, constructorMethodRef)};
1959          klass =
1960            new RVMClass(reflectionClass, constantPool, (short) (ACC_SYNTHETIC | ACC_PUBLIC | ACC_FINAL), // modifiers
1961                TypeReference.baseReflectionClass.resolve().asClass(), // superClass
1962                emptyVMClass, // declaredInterfaces
1963                emptyVMField, reflectionMethods,
1964                null, null, null, null, null, null, null, null);
1965          reflectionClass.setType(klass);
1966          RuntimeEntrypoints.initializeClassForDynamicLink(klass.asClass());
1967        }
1968        return klass.getClassForType();
1969      }
1970    }