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.HandInlinedScanning;
024 import org.jikesrvm.mm.mminterface.AlignmentEncoding;
025 import org.jikesrvm.mm.mminterface.MemoryManager;
026 import org.jikesrvm.objectmodel.FieldLayoutContext;
027 import org.jikesrvm.objectmodel.IMT;
028 import org.jikesrvm.objectmodel.ObjectModel;
029 import org.jikesrvm.objectmodel.TIB;
030 import org.jikesrvm.runtime.Magic;
031 import org.jikesrvm.runtime.RuntimeEntrypoints;
032 import org.jikesrvm.runtime.StackBrowser;
033 import org.jikesrvm.runtime.Statics;
034 import org.vmmagic.pragma.NonMoving;
035 import org.vmmagic.pragma.Pure;
036 import org.vmmagic.pragma.Uninterruptible;
037 import org.vmmagic.unboxed.Offset;
038
039 /**
040 * Description of a java "class" type.<p>
041 *
042 * This description is read from a ".class" file as classes/field/methods
043 * referenced by the running program need to be bound in to the running image.
044 *
045 * @see RVMType
046 * @see RVMArray
047 * @see Primitive
048 * @see UnboxedType
049 */
050 @NonMoving
051 public final class RVMClass extends RVMType implements Constants, ClassLoaderConstants {
052
053 /** Flag for closed world testing */
054 public static boolean classLoadingDisabled = false;
055
056 /**
057 * The constant pool holds constants used by the class and the Java
058 * bytecodes in the methods associated with this class. This
059 * constant pool isn't that from the class file, instead it has been
060 * processed during class loading (see {@link ClassFileReader#readClass}). The loaded
061 * class' constant pool has 3 bits of type information (such as
062 * (see {@link ClassLoaderConstants#CP_INT})), the rest of the int holds data as follows:
063 *
064 * <ul>
065 * <li>utf: value is a UTF atom identifier</li>
066 * <li>int, long, float, double, string: value is an offset in the
067 * JTOC</li>
068 * <li>member: value is a member reference identifier</li>
069 * <li>class: value is a type reference identifier. NB this means
070 * that class literal bytecodes must first convert the identifier
071 * in to a JTOC offset.</li>
072 * </ul>
073 */
074 private final int[] constantPool;
075 /** {@link ClassLoaderConstants} */
076 private final short modifiers;
077 /** Super class of this class */
078 private final RVMClass superClass;
079 /**
080 * Non-final list of sub-classes. Classes added as sub-classes are
081 * loaded.
082 */
083 private RVMClass[] subClasses;
084 /** Interfaces supported by this class */
085 private final RVMClass[] declaredInterfaces;
086 /** Fields of this class */
087 private final RVMField[] declaredFields;
088 /** Methods of this class */
089 private final RVMMethod[] declaredMethods;
090 /** Declared inner classes, may be null */
091 private final TypeReference[] declaredClasses;
092 /** The outer class, or null if this is not a inner/nested class */
093 private final TypeReference declaringClass;
094 /** The enclosing class if this is a local class */
095 private final TypeReference enclosingClass;
096 /** The enclosing method if this is a local class */
097 private final MethodReference enclosingMethod;
098 /** Name of file .class file was compiled from, may be null */
099 private final Atom sourceName;
100 /**
101 * The signature is a string representing the generic type for this
102 * class declaration, may be null
103 */
104 private final Atom signature;
105 /**
106 * Class initializer method, null if no method or if class is
107 * initialized (ie class initializer method has been run)
108 */
109 private RVMMethod classInitializerMethod;
110
111 /**
112 * current class-loading stage (loaded, resolved, instantiated,
113 * initializing or initialized)
114 */
115 private byte state;
116
117 //
118 // The following are valid only when "state >= CLASS_RESOLVED".
119 //
120
121 // --- Field size and offset information --- //
122
123 /** fields shared by all instances of class */
124 private RVMField[] staticFields;
125
126 /** fields distinct for each instance of class */
127 private RVMField[] instanceFields;
128
129 /** Total size of per-instance data, in bytes */
130 private int instanceSize;
131
132 /** The desired alignment for instances of this type. */
133 private int alignment;
134
135 /**
136 * A field layout helper - used to keep context regarding field layouts.
137 * Managed by the field layout objects in the ObjectModel.
138 */
139 private FieldLayoutContext fieldLayoutContext = null;
140
141 // --- Method-dispatching information --- //
142
143 /** static methods of class */
144 private RVMMethod[] staticMethods;
145
146 /** constructor methods of class */
147 private RVMMethod[] constructorMethods;
148
149 /** virtual methods of class */
150 private RVMMethod[] virtualMethods;
151
152 /**
153 * Do objects of this class have a finalizer method?
154 */
155 private boolean hasFinalizer;
156
157 /** type and virtual method dispatch table for class */
158 private TIB typeInformationBlock;
159
160 // --- Memory manager support --- //
161
162 /**
163 * Is this class type in the bootimage? Types in the boot image can
164 * be initialized prior to execution (therefore removing runtime
165 * resolution).
166 */
167 private boolean inBootImage;
168
169 /**
170 * At what offset is the thin lock word to be found in instances of
171 * objects of this type? A value of -1 indicates that the instances of
172 * this type do not have inline thin locks.
173 */
174 private Offset thinLockOffset;
175
176 /** Reference Count GC: is this type acyclic? */
177 private boolean acyclic;
178
179 /** Cached set of inherited and declared annotations. */
180 private Annotation[] annotations;
181
182 /** Set of objects that are cached here to ensure they are not collected by GC **/
183 private Object[] objectCache;
184
185 /** The imt for this class **/
186 @SuppressWarnings("unused")
187 private IMT imt;
188
189 // --- Assertion support --- //
190 /**
191 * Are assertions enabled on this class?
192 */
193 private final boolean desiredAssertionStatus;
194
195 // --- General purpose functions --- //
196
197 /**
198 * Name - something like "java.lang.String".
199 */
200 @Override
201 @Pure
202 public String toString() {
203 return getDescriptor().classNameFromDescriptor();
204 }
205
206 /**
207 * Package name - something like "java.lang".
208 * @return package name or the empty string if the class is a member of the unnamed package
209 */
210 public String getPackageName() {
211 String className = toString();
212 int lastDot = className.lastIndexOf(".");
213 return (lastDot >= 0) ? className.substring(0, lastDot) : "";
214 }
215
216 /**
217 * @return 1
218 */
219 @Override
220 @Pure
221 @Uninterruptible
222 public int getStackWords() {
223 return 1;
224 }
225
226 @Override
227 @Pure
228 @Uninterruptible
229 public int getMemoryBytes() {
230 return BYTES_IN_ADDRESS;
231 }
232
233 /**
234 * An "interface" description rather than a "class" description?
235 */
236 @Uninterruptible
237 public boolean isInterface() {
238 return (modifiers & ACC_INTERFACE) != 0;
239 }
240
241 /**
242 * Usable from other packages?
243 */
244 @Uninterruptible
245 public boolean isPublic() {
246 return (modifiers & ACC_PUBLIC) != 0;
247 }
248
249 /**
250 * Non-subclassable?
251 */
252 @Uninterruptible
253 public boolean isFinal() {
254 return (modifiers & ACC_FINAL) != 0;
255 }
256
257 /**
258 * Non-instantiable?
259 */
260 @Uninterruptible
261 public boolean isAbstract() {
262 return (modifiers & ACC_ABSTRACT) != 0;
263 }
264
265 /**
266 * Use new-style "invokespecial" semantics for method calls in this class?
267 */
268 @Uninterruptible
269 public boolean isSpecial() {
270 return (modifiers & ACC_SUPER) != 0;
271 }
272
273 /**
274 * Not present in source code file?
275 */
276 public boolean isSynthetic() {
277 return (modifiers & ACC_SYNTHETIC) != 0;
278 }
279
280 /**
281 * Is enumeration?
282 */
283 public boolean isEnum() {
284 return (modifiers & ACC_ENUM) != 0;
285 }
286
287 /**
288 * Annotation type
289 */
290 public boolean isAnnotation() {
291 return (modifiers & ACC_ANNOTATION) != 0;
292 }
293
294 /**
295 * @return true if this is a representation of an anonymous class
296 */
297 public boolean isAnonymousClass() {
298 if (enclosingClass == null || enclosingClass.peekType() == null) return false;
299 for(TypeReference t: enclosingClass.peekType().asClass().getDeclaredClasses()) {
300 if (t == typeRef) return false;
301 }
302 return true;
303 }
304
305 /**
306 * @return {@code 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 {@code 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 {@code 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 * ({@code null} --> "unknown - wasn't recorded by compiler").
345 */
346 public Atom getSourceName() {
347 return sourceName;
348 }
349
350 /**
351 * Superclass of this class ({@code null} means "no superclass",
352 * i.e. 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 (i.e. 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 (i.e. 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 ({@code 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 ({@code 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 ({@code 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 ({@code 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" (HTOC).
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 * @return number of fields that are non-final
813 */
814 public int getNumberOfNonFinalReferences() {
815 int count = 0;
816 for(RVMField field: declaredFields) {
817 if (!field.isFinal()) {
818 count++;
819 }
820 }
821 return count;
822 }
823
824 /**
825 * Set object representing available holes in the field layout
826 */
827 public FieldLayoutContext getFieldLayoutContext() {
828 return fieldLayoutContext;
829 }
830
831 /**
832 * Set object representing available holes in the field layout
833 */
834 public void setFieldLayoutContext(FieldLayoutContext newLayout) {
835 fieldLayoutContext = isFinal() ? null : newLayout;
836 }
837
838 /**
839 * @return alignment for instances of this class type
840 */
841 @Uninterruptible
842 public int getAlignment() {
843 if (BYTES_IN_ADDRESS == BYTES_IN_DOUBLE) {
844 return BYTES_IN_ADDRESS;
845 } else {
846 return alignment;
847 }
848 }
849
850 /**
851 * Set the alignment for instances of this class type
852 */
853 public void setAlignment(int align) {
854 if (BYTES_IN_ADDRESS != BYTES_IN_DOUBLE) {
855 if (VM.VerifyAssertions) VM._assert(align >= alignment);
856 alignment = align;
857 }
858 }
859
860 /**
861 * Find specified static method description.
862 * @param memberName method name - something like "foo"
863 * @param memberDescriptor method descriptor - something like "I" or "()I"
864 * @return method description (null --> not found)
865 */
866 @Pure
867 public RVMMethod findStaticMethod(Atom memberName, Atom memberDescriptor) {
868 if (VM.VerifyAssertions) VM._assert(isResolved());
869 for (RVMMethod method : getStaticMethods()) {
870 if (method.getName() == memberName && method.getDescriptor() == memberDescriptor) {
871 return method;
872 }
873 }
874 return null;
875 }
876
877 /**
878 * Find specified initializer method description.
879 * @param memberDescriptor init method descriptor - something like "(I)V"
880 * @return method description (null --> not found)
881 */
882 @Pure
883 public RVMMethod findInitializerMethod(Atom memberDescriptor) {
884 if (VM.VerifyAssertions) VM._assert(isResolved());
885 for (RVMMethod method : getConstructorMethods()) {
886 if (method.getDescriptor() == memberDescriptor) {
887 return method;
888 }
889 }
890 return null;
891 }
892
893 /**
894 * Runtime type information for this class type.
895 */
896 @Override
897 @Uninterruptible
898 public TIB getTypeInformationBlock() {
899 if (VM.VerifyAssertions) VM._assert(isResolved());
900 return typeInformationBlock;
901 }
902
903 //--------------------------------------------------------------------//
904 // Miscellaneous queries. //
905 //---------------------------------------------------------------------//
906
907 /**
908 * Support for user-written class loaders:
909 * It's required to find the classloader of the class
910 * whose method requires another class to be loaded;
911 * the initiating loader of the required class is the
912 * defining loader of the requiring class.
913 *
914 *
915 * @param skip specifies the number of frames back from the
916 * caller to the method whose class's loader is required
917 */
918 public static ClassLoader getClassLoaderFromStackFrame(int skip) {
919 skip++; // account for stack frame of this function
920 StackBrowser browser = new StackBrowser();
921 VM.disableGC();
922 browser.init();
923 while (skip-- > 0) browser.up();
924 VM.enableGC();
925 return browser.getClassLoader();
926 }
927
928 /**
929 * Used for accessibility checks in reflection code.
930 * Find the class of the method that corresponds to the requested frame.
931 *
932 * @param skip Specifies the number of frames back from the
933 * caller to the method whose class is required
934 */
935 public static RVMClass getClassFromStackFrame(int skip) {
936 skip++; // account for stack frame of this function
937 StackBrowser browser = new StackBrowser();
938 VM.disableGC();
939 browser.init();
940 while (skip-- > 0) browser.up();
941 VM.enableGC();
942 return browser.getCurrentClass();
943 }
944
945 /**
946 * @return whether or not assertions should be enabled
947 */
948 @Override
949 @Pure
950 public boolean getDesiredAssertionStatus() {
951 return desiredAssertionStatus;
952 }
953
954 //--------------------------------------------------------------------//
955 // Load, Resolve, Instantiate, and Initialize //
956 //--------------------------------------------------------------------//
957
958 /**
959 * Construct a class from its constituent loaded parts
960 *
961 * @param typeRef the type reference that was resolved to this class
962 * @param constantPool array of ints encoding constant value
963 * @param modifiers {@link org.jikesrvm.classloader.ClassLoaderConstants}
964 * @param superClass parent of this class
965 * @param declaredInterfaces array of interfaces this class implements
966 * @param declaredFields fields of the class
967 * @param declaredMethods methods of the class
968 * @param declaredClasses declared inner classes
969 * @param declaringClass outer class if an inner class
970 * @param sourceName source file name
971 * @param classInitializerMethod handle to class initializer method
972 * @param signature the generic type name for this class
973 * @param annotations array of runtime visible annotations
974 */
975 RVMClass(TypeReference typeRef, int[] constantPool, short modifiers, RVMClass superClass,
976 RVMClass[] declaredInterfaces, RVMField[] declaredFields, RVMMethod[] declaredMethods,
977 TypeReference[] declaredClasses, TypeReference declaringClass, TypeReference enclosingClass,
978 MethodReference enclosingMethod, Atom sourceName, RVMMethod classInitializerMethod,
979 Atom signature, RVMAnnotation[] annotations) {
980 super(typeRef, 0, annotations);
981 if (VM.VerifyAssertions) VM._assert(!getTypeRef().isUnboxedType());
982 if (VM.VerifyAssertions && null != superClass) VM._assert(!superClass.getTypeRef().isUnboxedType());
983
984 // final fields
985 this.constantPool = constantPool;
986 this.modifiers = modifiers;
987 this.superClass = superClass;
988 this.declaredInterfaces = declaredInterfaces;
989 this.declaredFields = declaredFields;
990 this.declaredMethods = declaredMethods;
991 this.declaredClasses = declaredClasses;
992 this.declaringClass = declaringClass;
993 this.enclosingClass = enclosingClass;
994 this.enclosingMethod = enclosingMethod;
995 this.sourceName = sourceName;
996 this.classInitializerMethod = classInitializerMethod;
997 this.signature = signature;
998
999 // non-final fields
1000 this.subClasses = emptyVMClass;
1001 state = CLASS_LOADED;
1002
1003 // we're about to leak a reference to 'this' force memory to be
1004 // consistent
1005 Magic.sync();
1006
1007 if (superClass != null) {
1008 // MUST wait until end of constructor to 'publish' the subclass link.
1009 // If we do this earlier, then people can see an incomplete RVMClass object
1010 // by traversing the subclasses of our superclass!
1011 superClass.addSubClass(this);
1012 }
1013
1014 this.desiredAssertionStatus = RVMClassLoader.getDesiredAssertionStatus(this);
1015
1016 Callbacks.notifyClassLoaded(this);
1017
1018 if (VM.TraceClassLoading && VM.runningVM) {
1019 VM.sysWriteln("RVMClass: (end) load file " + typeRef.getName());
1020 }
1021 if (VM.verboseClassLoading) VM.sysWrite("[Loaded " + toString() + "]\n");
1022 }
1023
1024 /**
1025 * {@inheritDoc} Space in the JTOC is allocated for static fields,
1026 * static methods and constructors. Moreover, this method generates size
1027 * and offset information for members of this class.<p>
1028 *
1029 * Side effects: superclasses and superinterfaces are resolved.
1030 */
1031 @Override
1032 public synchronized void resolve() {
1033 if (isResolved()) return;
1034 if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (begin) resolve " + this);
1035 if (VM.VerifyAssertions) VM._assert(state == CLASS_LOADED);
1036
1037 // Resolve superclass and super interfaces
1038 //
1039 if (superClass != null) {
1040 superClass.resolve();
1041 }
1042 for (RVMClass declaredInterface : declaredInterfaces) {
1043 declaredInterface.resolve();
1044 }
1045
1046 if (isInterface()) {
1047 if (VM.VerifyAssertions) VM._assert(superClass == null);
1048 depth = 1;
1049 thinLockOffset = Offset.max();
1050 } else if (superClass == null) {
1051 if (VM.VerifyAssertions) VM._assert(isJavaLangObjectType());
1052 instanceSize = ObjectModel.computeScalarHeaderSize(this);
1053 alignment = BYTES_IN_ADDRESS;
1054 thinLockOffset = ObjectModel.defaultThinLockOffset();
1055 depth=0;
1056 } else {
1057 depth = superClass.depth + 1;
1058 thinLockOffset = superClass.thinLockOffset;
1059 instanceSize = superClass.instanceSize;
1060 fieldLayoutContext = superClass.fieldLayoutContext;
1061 alignment = superClass.alignment;
1062 }
1063
1064 if (this == RVMType.JavaLangClassType) {
1065 ObjectModel.allocateThinLock(this);
1066 }
1067
1068 if (superClass != null && superClass.isNonMoving() && !isNonMoving()) {
1069 VM.sysWriteln("WARNING: movable " + this + " extends non-moving " + superClass);
1070 }
1071
1072 if (VM.verboseClassLoading) VM.sysWrite("[Preparing " + this + "]\n");
1073
1074 // build field and method lists for this class
1075 //
1076 {
1077 FieldVector staticFields = new FieldVector();
1078 FieldVector instanceFields = new FieldVector();
1079 MethodVector staticMethods = new MethodVector();
1080 MethodVector constructorMethods = new MethodVector();
1081 MethodVector virtualMethods = new MethodVector();
1082
1083 // start with fields and methods of superclass
1084 //
1085 if (superClass != null) {
1086 for (RVMField field : superClass.getInstanceFields()) {
1087 instanceFields.addElement(field);
1088 }
1089
1090 for (RVMMethod method : superClass.getVirtualMethods()) {
1091 virtualMethods.addElement(method);
1092 }
1093 }
1094
1095 // append fields defined by this class
1096 //
1097 for (RVMField field : getDeclaredFields()) {
1098 if (field.isStatic()) {
1099 staticFields.addElement(field);
1100 } else {
1101 instanceFields.addElement(field);
1102 }
1103 }
1104
1105 // append/overlay methods defined by this class
1106 //
1107 for (RVMMethod method : getDeclaredMethods()) {
1108 if (VM.VerifyUnint) {
1109 if (method.isSynchronized() && method.isUninterruptible()) {
1110 if (VM.ParanoidVerifyUnint || !method.hasLogicallyUninterruptibleAnnotation()) {
1111 VM.sysWriteln("WARNING: " + method + " cannot be both uninterruptible and synchronized");
1112 }
1113 }
1114 }
1115
1116 if (method.isObjectInitializer()) {
1117 Callbacks.notifyMethodOverride(method, null);
1118 constructorMethods.addElement(method);
1119 } else if (method.isStatic()) {
1120 if (!method.isClassInitializer()) {
1121 Callbacks.notifyMethodOverride(method, null);
1122 staticMethods.addElement(method);
1123 }
1124 } else { // Virtual method
1125
1126 if (method.isSynchronized()) {
1127 ObjectModel.allocateThinLock(this);
1128 }
1129
1130 // method could override something in superclass - check for it
1131 //
1132 int superclassMethodIndex = -1;
1133 for (int j = 0, m = virtualMethods.size(); j < m; ++j) {
1134 RVMMethod alreadyDefinedMethod = virtualMethods.elementAt(j);
1135 if (alreadyDefinedMethod.getName() == method.getName() &&
1136 alreadyDefinedMethod.getDescriptor() == method.getDescriptor()) {
1137 // method already defined in superclass
1138 superclassMethodIndex = j;
1139 break;
1140 }
1141 }
1142
1143 if (superclassMethodIndex == -1) {
1144 Callbacks.notifyMethodOverride(method, null);
1145 virtualMethods.addElement(method); // append
1146 } else {
1147 RVMMethod superc = virtualMethods.elementAt(superclassMethodIndex);
1148 if (VM.VerifyUnint) {
1149 if (!superc.isInterruptible() && method.isInterruptible()) {
1150 VM.sysWriteln("WARNING: interruptible " + method + " overrides uninterruptible " + superc);
1151 }
1152 }
1153 Callbacks.notifyMethodOverride(method, superc);
1154 virtualMethods.setElementAt(method, superclassMethodIndex); // override
1155 }
1156 }
1157 }
1158
1159 // Deal with Miranda methods.
1160 // If this is an abstract class, then for each
1161 // interface that this class implements, ensure that a corresponding virtual
1162 // method is declared. If one is not, then create an abstract method to fill the void.
1163 if (!isInterface() && isAbstract()) {
1164 for (RVMClass I : declaredInterfaces) {
1165 RVMMethod[] iMeths = I.getVirtualMethods();
1166 outer:
1167 for (RVMMethod iMeth : iMeths) {
1168 Atom iName = iMeth.getName();
1169 Atom iDesc = iMeth.getDescriptor();
1170 for (int k = 0; k < virtualMethods.size(); k++) {
1171 RVMMethod vMeth = virtualMethods.elementAt(k);
1172 if (vMeth.getName() == iName && vMeth.getDescriptor() == iDesc) continue outer;
1173 }
1174 MemberReference mRef = MemberReference.findOrCreate(typeRef, iName, iDesc);
1175 virtualMethods.addElement(new AbstractMethod(getTypeRef(),
1176 mRef,
1177 (short) (ACC_ABSTRACT | ACC_PUBLIC),
1178 iMeth.getExceptionTypes(),
1179 null,
1180 null,
1181 null,
1182 null));
1183 }
1184 }
1185 }
1186
1187 // If this is an interface, inherit methods from its superinterfaces
1188 if (isInterface()) {
1189 for (RVMClass declaredInterface : declaredInterfaces) {
1190 RVMMethod[] meths = declaredInterface.getVirtualMethods();
1191 for (RVMMethod meth : meths) {
1192 virtualMethods.addUniqueElement(meth);
1193 }
1194 }
1195 }
1196
1197 this.staticFields = staticFields.finish();
1198 this.instanceFields = instanceFields.finish();
1199 this.staticMethods = staticMethods.finish();
1200 this.constructorMethods = constructorMethods.finish();
1201 this.virtualMethods = virtualMethods.finish();
1202 }
1203
1204 // allocate space for class fields
1205 //
1206 for (RVMField field : staticFields) {
1207 if (field.isReferenceType()) {
1208 field.setOffset(Statics.allocateReferenceSlot(true));
1209 } else if (field.getSize() <= BYTES_IN_INT) {
1210 field.setOffset(Statics.allocateNumericSlot(BYTES_IN_INT, true));
1211 } else {
1212 field.setOffset(Statics.allocateNumericSlot(BYTES_IN_LONG, true));
1213 }
1214
1215 // (SJF): Serialization nastily accesses even final private static
1216 // fields via pseudo-reflection! So, we must shove the
1217 // values of final static fields into the JTOC. Now
1218 // seems to be a good time.
1219 if (field.isFinal()) {
1220 setFinalStaticJTOCEntry(field, field.getOffset());
1221 }
1222 }
1223
1224 // lay out instance fields
1225 //
1226 ObjectModel.layoutInstanceFields(this);
1227
1228 // count reference fields
1229 int referenceFieldCount = 0;
1230 for (RVMField field : instanceFields) {
1231 if (field.isTraced()) {
1232 referenceFieldCount += 1;
1233 }
1234 }
1235
1236 // record offsets of those instance fields that contain references
1237 //
1238 if (typeRef.isRuntimeTable()) {
1239 referenceOffsets = MemoryManager.newNonMovingIntArray(0);
1240 } else {
1241 referenceOffsets = MemoryManager.newNonMovingIntArray(referenceFieldCount);
1242 int j = 0;
1243 for (RVMField field : instanceFields) {
1244 if (field.isTraced()) {
1245 referenceOffsets[j++] = field.getOffset().toInt();
1246 }
1247 }
1248 }
1249
1250 // Allocate space for <init> method pointers
1251 //
1252 for (RVMMethod method : constructorMethods) {
1253 method.setOffset(Statics.allocateReferenceSlot(true));
1254 }
1255
1256 // Allocate space for static method pointers
1257 //
1258 for (RVMMethod method : staticMethods) {
1259 if (method.isClassInitializer()) {
1260 method.setOffset(Offset.fromIntZeroExtend(0xebad0ff5)); // should never be used.
1261 } else {
1262 method.setOffset(Statics.allocateReferenceSlot(true));
1263 }
1264 }
1265
1266 if (!isInterface()) {
1267 // lay out virtual method section of type information block
1268 // (to be filled in by instantiate)
1269 for (int i = 0, n = virtualMethods.length; i < n; ++i) {
1270 RVMMethod method = virtualMethods[i];
1271 method.setOffset(TIB.getVirtualMethodOffset(i));
1272 }
1273 }
1274
1275 // RCGC: Determine if class is inherently acyclic
1276 acyclic = false; // must initially be false for recursive types
1277 boolean foundCyclic = false;
1278 for (RVMField instanceField : instanceFields) {
1279 TypeReference ft = instanceField.getType();
1280 if (!ft.isResolved() || !ft.peekType().isAcyclicReference()) {
1281 foundCyclic = true;
1282 break;
1283 }
1284 }
1285 if (!foundCyclic) {
1286 acyclic = true;
1287 }
1288
1289 // allocate "type information block"
1290 TIB allocatedTib;
1291 if (isInterface()) {
1292 allocatedTib = MemoryManager.newTIB(0, AlignmentEncoding.ALIGN_CODE_NONE);
1293 } else if (isAnnotationDeclared(TypeReference.ReferenceFieldsVary)) {
1294 allocatedTib = MemoryManager.newTIB(virtualMethods.length, HandInlinedScanning.fallback());
1295 } else {
1296 allocatedTib = MemoryManager.newTIB(virtualMethods.length, HandInlinedScanning.scalar(referenceOffsets));
1297 }
1298
1299 superclassIds = DynamicTypeCheck.buildSuperclassIds(this);
1300 doesImplement = DynamicTypeCheck.buildDoesImplement(this);
1301
1302 // can't move this beyond "finalize" code block as findVirtualMethod
1303 // assumes state >= RESOLVED, no allocation occurs until
1304 // state >= CLASS_INITIALIZING
1305 publishResolved(allocatedTib, superclassIds, doesImplement);
1306
1307 // TODO: Make this into a more general listener interface
1308 if (VM.BuildForOptCompiler && VM.writingBootImage) {
1309 classLoadListener.classInitialized(this, true);
1310 }
1311
1312 Callbacks.notifyClassResolved(this);
1313 MemoryManager.notifyClassResolved(this);
1314
1315 // check for a "finalize" method that overrides the one in java.lang.Object
1316 //
1317 if (!isInterface()) {
1318 final RVMMethod method =
1319 findVirtualMethod(RVMClassLoader.StandardObjectFinalizerMethodName,
1320 RVMClassLoader.StandardObjectFinalizerMethodDescriptor);
1321 if (!method.getDeclaringClass().isJavaLangObjectType()) {
1322 hasFinalizer = true;
1323 }
1324 }
1325
1326 if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (end) resolve " + this);
1327 }
1328
1329 /**
1330 * Atomically initialize the important parts of the TIB and let the world know this type is
1331 * resolved.
1332 *
1333 * @param allocatedTib The TIB that has been allocated for this type
1334 * @param superclassIds The calculated superclass ids array
1335 * @param doesImplement The calculated does implement array
1336 */
1337 @Uninterruptible
1338 private void publishResolved(TIB allocatedTib, short[] superclassIds, int[] doesImplement) {
1339 Statics.setSlotContents(getTibOffset(), allocatedTib);
1340 allocatedTib.setType(this);
1341 allocatedTib.setSuperclassIds(superclassIds);
1342 allocatedTib.setDoesImplement(doesImplement);
1343 typeInformationBlock = allocatedTib;
1344 state = CLASS_RESOLVED;
1345 }
1346
1347 @Override
1348 public void allBootImageTypesResolved() {
1349 for (RVMMethod method : declaredMethods) {
1350 if (method instanceof NormalMethod) {
1351 ((NormalMethod)method).recomputeSummary(constantPool);
1352 }
1353 }
1354 }
1355
1356
1357 /**
1358 * @return <code>true</code> if the class is acyclic and
1359 * final (otherwise the reference could be to a subsequently loaded
1360 * cyclic subclass)
1361 */
1362 @Override
1363 @Uninterruptible
1364 public boolean isAcyclicReference() {
1365 return acyclic && isFinal();
1366 }
1367
1368 /**
1369 * Insert the value of a final static field into the JTOC
1370 */
1371 private void setFinalStaticJTOCEntry(RVMField field, Offset fieldOffset) {
1372 if (!field.isFinal()) return;
1373
1374 // value Index: index into the classes constant pool.
1375 int valueIndex = field.getConstantValueIndex();
1376
1377 // if there's no value in the constant pool, bail out
1378 if (valueIndex <= 0) return;
1379
1380 Offset literalOffset = field.getDeclaringClass().getLiteralOffset(valueIndex);
1381
1382 if (Statics.isReference(Statics.offsetAsSlot(fieldOffset))) {
1383 Object obj = Statics.getSlotContentsAsObject(literalOffset);
1384 Statics.setSlotContents(fieldOffset, obj);
1385 } else if (field.getSize() <= BYTES_IN_INT) {
1386 // copy one word from constant pool to JTOC
1387 int value = Statics.getSlotContentsAsInt(literalOffset);
1388 Statics.setSlotContents(fieldOffset, value);
1389 } else {
1390 // copy two words from constant pool to JTOC
1391 long value = Statics.getSlotContentsAsLong(literalOffset);
1392 Statics.setSlotContents(fieldOffset, value);
1393 }
1394 }
1395
1396 /**
1397 * {@inheritDoc} The TIB will also be built.<p>
1398 *
1399 * Side effects: superclasses are instantiated.
1400 */
1401 @Override
1402 public synchronized void instantiate() {
1403 if (isInstantiated()) {
1404 return;
1405 }
1406
1407 if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (begin) instantiate " + this);
1408 if (VM.VerifyAssertions) VM._assert(state == CLASS_RESOLVED);
1409
1410 // instantiate superclass
1411 //
1412 if (superClass != null) {
1413 superClass.instantiate();
1414 }
1415 if (VM.runningVM) {
1416 // can't instantiate if building bootimage, since this can cause
1417 // class initializer to be lost (when interface is not included in bootimage).
1418 // since we don't need to instantiate/initialize for the purposes of
1419 // dynamic type checking and interface invocation, defer it until runtime
1420 // and the class actually refers to a static field of the interface.
1421 for (RVMClass declaredInterface : declaredInterfaces) {
1422 declaredInterface.instantiate();
1423 }
1424 }
1425
1426 if (!isInterface()) {
1427 // Create the internal lazy method invoker trampoline
1428 typeInformationBlock.initializeInternalLazyCompilationTrampoline();
1429
1430 // Initialize slots in the TIB for virtual methods
1431 for(int i=0; i < virtualMethods.length; i++) {
1432 RVMMethod method = virtualMethods[i];
1433 if (method.isPrivate() && method.getDeclaringClass() != this) {
1434 typeInformationBlock.setVirtualMethod(i, null); // an inherited private method....will never be invoked via this TIB
1435 } else {
1436 typeInformationBlock.setVirtualMethod(i, method.getCurrentEntryCodeArray());
1437 }
1438 }
1439
1440 // compile <init> methods and put their addresses into jtoc
1441 for (RVMMethod method : constructorMethods) {
1442 Statics.setSlotContents(method.getOffset(), method.getCurrentEntryCodeArray());
1443 }
1444
1445 // compile static methods and put their addresses into jtoc
1446 for (RVMMethod method : staticMethods) {
1447 // don't bother compiling <clinit> here;
1448 // compile it right before we invoke it in initialize.
1449 // This also avoids putting <clinit>s in the bootimage.
1450 if (!method.isClassInitializer()) {
1451 Statics.setSlotContents(method.getOffset(), method.getCurrentEntryCodeArray());
1452 }
1453 }
1454 }
1455
1456 InterfaceInvocation.initializeDispatchStructures(this);
1457 SpecializedMethodManager.notifyTypeInstantiated(this);
1458
1459 if (VM.writingBootImage) {
1460 state = CLASS_INITIALIZED;
1461 // Mark final fields as literals as class initializer won't have been called
1462 markFinalFieldsAsLiterals();
1463 } else {
1464 state = CLASS_INSTANTIATED;
1465 }
1466
1467 Callbacks.notifyClassInstantiated(this);
1468 if (VM.writingBootImage) {
1469 Callbacks.notifyClassInitialized(this);
1470 }
1471
1472 if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (end) instantiate " + this);
1473 }
1474
1475 /**
1476 * Make the passed field a traced field by garbage collection. Also affects all
1477 * subclasses.
1478 */
1479 public void makeFieldTraced(RVMField field) {
1480 int[] oldOffsets = referenceOffsets;
1481 int fieldOffset = field.getOffset().toInt();
1482 referenceOffsets = MemoryManager.newNonMovingIntArray(oldOffsets.length + 1);
1483 int i;
1484 for(i=0; i < oldOffsets.length && oldOffsets[i] < fieldOffset; i++) {
1485 referenceOffsets[i] = oldOffsets[i];
1486 }
1487 referenceOffsets[i++] = fieldOffset;
1488 while(i < referenceOffsets.length) {
1489 referenceOffsets[i] = oldOffsets[i-1];
1490 i++;
1491 }
1492 SpecializedMethodManager.refreshSpecializedMethods(this);
1493
1494 for(RVMClass klass: subClasses) {
1495 klass.makeFieldTraced(field);
1496 }
1497 }
1498
1499 /**
1500 * {@inheritDoc}<p>
1501 *
1502 * Side effects: superclasses are initialized, static fields receive
1503 * initial values.
1504 */
1505 @Override
1506 public synchronized void initialize() throws ExceptionInInitializerError {
1507 if (isInitialized()) {
1508 return;
1509 }
1510
1511 if (state == CLASS_INITIALIZING) {
1512 return;
1513 }
1514
1515 if (state == CLASS_INITIALIZER_FAILED) {
1516 throw new NoClassDefFoundError(this+" (initialization failure)");
1517 }
1518
1519 if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (begin) initialize " + this);
1520 if (VM.VerifyAssertions) VM._assert(state == CLASS_INSTANTIATED);
1521 state = CLASS_INITIALIZING;
1522 if (VM.verboseClassLoading) VM.sysWrite("[Initializing " + this + "]\n");
1523
1524 // run super <clinit>
1525 //
1526 if (superClass != null) {
1527 superClass.initialize();
1528 }
1529
1530 // run <clinit>
1531 //
1532 if (classInitializerMethod != null) {
1533 CompiledMethod cm = classInitializerMethod.getCurrentCompiledMethod();
1534 while (cm == null) {
1535 classInitializerMethod.compile();
1536 cm = classInitializerMethod.getCurrentCompiledMethod();
1537 }
1538
1539 if (VM.verboseClassLoading) VM.sysWrite("[Running static initializer for " + this + "]\n");
1540
1541 try {
1542 Magic.invokeClassInitializer(cm.getEntryCodeArray());
1543 } catch (Error e) {
1544 state = CLASS_INITIALIZER_FAILED;
1545 throw e;
1546 } catch (Throwable t) {
1547 ExceptionInInitializerError eieio = new ExceptionInInitializerError("While initializing " + this);
1548 eieio.initCause(t);
1549 state = CLASS_INITIALIZER_FAILED;
1550 if (VM.verboseClassLoading) {
1551 VM.sysWriteln("[Exception in initializer error caused by:");
1552 t.printStackTrace();
1553 VM.sysWriteln("]");
1554 }
1555 throw eieio;
1556 }
1557
1558 // <clinit> is no longer needed: reclaim space by removing references to it
1559 classInitializerMethod.invalidateCompiledMethod(cm);
1560 classInitializerMethod = null;
1561 }
1562
1563 if (VM.BuildForOptCompiler) {
1564 // report that a class is about to be marked initialized to
1565 // the opt compiler so it can invalidate speculative CHA optimizations
1566 // before an instance of this class could actually be created.
1567 classLoadListener.classInitialized(this, false);
1568 }
1569
1570 state = CLASS_INITIALIZED;
1571
1572 Callbacks.notifyClassInitialized(this);
1573
1574 markFinalFieldsAsLiterals();
1575
1576 if (VM.verboseClassLoading) VM.sysWrite("[Initialized " + this + "]\n");
1577 if (VM.TraceClassLoading && VM.runningVM) VM.sysWriteln("RVMClass: (end) initialize " + this);
1578 }
1579
1580 /**
1581 * Mark final fields as being available as literals
1582 */
1583 private void markFinalFieldsAsLiterals() {
1584 for (RVMField f : getStaticFields()) {
1585 if (f.isFinal()) {
1586 Offset fieldOffset = f.getOffset();
1587 if (Statics.isReference(Statics.offsetAsSlot(fieldOffset))) {
1588 Statics.markAsReferenceLiteral(fieldOffset);
1589 } else {
1590 Statics.markAsNumericLiteral(f.getSize(), fieldOffset);
1591 }
1592 }
1593 }
1594 }
1595
1596 /**
1597 * Copy the values of all static final fields into
1598 * the JTOC. Note: This method should only be run AFTER
1599 * the class initializer has run.
1600 */
1601 public void setAllFinalStaticJTOCEntries() {
1602 if (VM.VerifyAssertions) VM._assert(isInitialized());
1603 for (RVMField f : getStaticFields()) {
1604 if (f.isFinal()) {
1605 setFinalStaticJTOCEntry(f, f.getOffset());
1606 }
1607 }
1608 }
1609
1610 void resolveNativeMethods() {
1611 if (VM.VerifyAssertions) VM._assert(isInitialized());
1612 resolveNativeMethodsInternal(getStaticMethods());
1613 resolveNativeMethodsInternal(getVirtualMethods());
1614 }
1615
1616 private void resolveNativeMethodsInternal(RVMMethod[] methods) {
1617 for (RVMMethod m : methods) {
1618 if (m.isNative()) {
1619 m.replaceCompiledMethod(null);
1620 }
1621 }
1622 }
1623
1624 /**
1625 * Unregisters all native methods
1626 */
1627 public void unregisterNativeMethods() {
1628 if (VM.VerifyAssertions) VM._assert(isInitialized());
1629 for (RVMMethod m : declaredMethods) {
1630 if (m.isNative()) {
1631 NativeMethod nm = (NativeMethod) m;
1632 nm.unregisterNativeSymbol();
1633 m.replaceCompiledMethod(null);
1634 }
1635 }
1636 }
1637
1638 /**
1639 * Add to list of classes that derive from this one.
1640 */
1641 private void addSubClass(RVMClass sub) {
1642 int n = subClasses.length;
1643 RVMClass[] tmp = new RVMClass[n + 1];
1644
1645 for (int i = 0; i < n; ++i) {
1646 tmp[i] = subClasses[i];
1647 }
1648 tmp[n] = sub;
1649
1650 subClasses = tmp;
1651 }
1652
1653 //------------------------------------------------------------//
1654 // Support for speculative optimizations that may need to
1655 // invalidate compiled code when new classes are loaded.
1656 //
1657 // TODO: Make this into a more general listener API
1658 //------------------------------------------------------------//
1659 public static final ClassLoadingListener classLoadListener =
1660 VM.BuildForOptCompiler ? new ClassLoadingDependencyManager() : null;
1661
1662 /**
1663 * Given a method declared by this class, update all
1664 * dispatching tables to refer to the current compiled
1665 * code for the method.
1666 */
1667 public void updateMethod(RVMMethod m) {
1668 if (VM.VerifyAssertions) VM._assert(isResolved());
1669 if (VM.VerifyAssertions) VM._assert(m.getDeclaringClass() == this);
1670 if (m.isClassInitializer()) return; // we never put this method in the jtoc anyways!
1671
1672 if (m.isStatic() || m.isObjectInitializer()) {
1673 updateJTOCEntry(m);
1674 } else {
1675 updateVirtualMethod(m);
1676 }
1677 }
1678
1679 /**
1680 * Update the JTOC slot for the given static method to point to
1681 * the current compiled code for the given method.
1682 * NOTE: This method is intentionally not synchronized to avoid deadlocks.
1683 * We instead rely on the fact that we are always updating the JTOC with
1684 * the most recent instructions for the method.
1685 */
1686 public void updateJTOCEntry(RVMMethod m) {
1687 if (VM.VerifyAssertions) VM._assert(m.getDeclaringClass() == this);
1688 if (VM.VerifyAssertions) VM._assert(isResolved());
1689 if (VM.VerifyAssertions) VM._assert(m.isStatic() || m.isObjectInitializer());
1690 Statics.setSlotContents(m.getOffset(), m.getCurrentEntryCodeArray());
1691 }
1692
1693 /**
1694 * Update this class's TIB entry for the given method to point to
1695 * the current compiled code for the given method.<p>
1696 * NOTE: This method is intentionally not synchronized to avoid deadlocks.
1697 * We instead rely on the fact that we are always updating the JTOC with
1698 * the most recent instructions for the method.
1699 */
1700 public void updateTIBEntry(RVMMethod m) {
1701 if (VM.VerifyAssertions) {
1702 RVMMethod vm = findVirtualMethod(m.getName(), m.getDescriptor());
1703 VM._assert(vm == m);
1704 }
1705 typeInformationBlock.setVirtualMethod(m.getOffset(), m.getCurrentEntryCodeArray());
1706 InterfaceInvocation.updateTIBEntry(this, m);
1707 }
1708
1709 /**
1710 * Update the TIB entry's for all classes that inherit the given method
1711 * to point to the current compiled code for the given method.<p>
1712 * NOTE: This method is intentionally not synchronized to avoid deadlocks.
1713 * We instead rely on the fact that we are always updating the JTOC with
1714 * the most recent instructions for the method.
1715 */
1716 public void updateVirtualMethod(RVMMethod m) {
1717 RVMMethod dm = findDeclaredMethod(m.getName(), m.getDescriptor());
1718 if (dm != null && dm != m) return; // this method got overridden
1719 updateTIBEntry(m);
1720 if (m.isPrivate()) return; // can't override
1721 for (RVMClass sc : getSubClasses()) {
1722 if (sc.isResolved()) {
1723 sc.updateVirtualMethod(m);
1724 }
1725 }
1726 }
1727
1728 //------------------------------------------------------------//
1729 // Additional fields and methods for Interfaces //
1730 //------------------------------------------------------------//
1731
1732 private static final Object interfaceCountLock = new Object();
1733 private static int interfaceCount = 0;
1734 private static RVMClass[] interfaces;
1735 private int interfaceId = -1;
1736 RVMMethod[] noIMTConflictMap; // used by InterfaceInvocation to support resetTIB
1737
1738 /**
1739 * Classes used as Interfaces get assigned an interface id.
1740 * If the class is not an interface, attempting to use this
1741 * id will cause an IncompatibleClassChangeError to be thrown
1742 */
1743 public int getInterfaceId() {
1744 if (interfaceId == -1) {
1745 assignInterfaceId();
1746 }
1747 return interfaceId;
1748 }
1749
1750 public int getDoesImplementIndex() {
1751 return getInterfaceId() >>> 5;
1752 }
1753
1754 public int getDoesImplementBitMask() {
1755 return 1 << (getInterfaceId() & 31);
1756 }
1757
1758 public static RVMClass getInterface(int id) {
1759 return interfaces[id];
1760 }
1761
1762 private synchronized void assignInterfaceId() {
1763 if (interfaceId == -1) {
1764 if (interfaceCountLock != null && interfaces != null) {
1765 synchronized (interfaceCountLock) {
1766 interfaceId = interfaceCount++;
1767 if (interfaceId == interfaces.length) {
1768 RVMClass[] tmp = new RVMClass[interfaces.length * 2];
1769 System.arraycopy(interfaces, 0, tmp, 0, interfaces.length);
1770 interfaces = tmp;
1771 }
1772 interfaces[interfaceId] = this;
1773 }
1774 } else {
1775 interfaceId = interfaceCount++;
1776 if (interfaces == null) {
1777 interfaces = new RVMClass[200];
1778 }
1779 interfaces[interfaceId] = this;
1780 }
1781 }
1782 }
1783
1784 /**
1785 * Number of [ in descriptor for arrays; -1 for primitives; 0 for
1786 * classes
1787 * @return 0
1788 */
1789 @Override
1790 @Pure
1791 @Uninterruptible
1792 public int getDimensionality() {
1793 return 0;
1794 }
1795
1796 @Override
1797 @Uninterruptible
1798 public boolean isResolved() {
1799 return state >= CLASS_RESOLVED;
1800 }
1801
1802 @Override
1803 @Uninterruptible
1804 public boolean isInstantiated() {
1805 return state >= CLASS_INSTANTIATED;
1806 }
1807
1808 @Override
1809 @Uninterruptible
1810 public boolean isInitialized() {
1811 return state == CLASS_INITIALIZED;
1812 }
1813
1814 @Override
1815 public void markAsBootImageClass() {
1816 inBootImage = true;
1817 }
1818
1819 @Override
1820 @Uninterruptible
1821 public boolean isInBootImage() {
1822 return inBootImage;
1823 }
1824
1825 /**
1826 * Get the offset in instances of this type assigned to the thin lock word.
1827 * Is only known after class has been resolved.
1828 */
1829 @Override
1830 @Uninterruptible
1831 public Offset getThinLockOffset() {
1832 if (VM.VerifyAssertions) VM._assert(isResolved());
1833 return thinLockOffset;
1834 }
1835
1836 /**
1837 * Set the thin lock offset for instances of this type. Can be called at most once.
1838 * and is invoked from ObjectModel.allocateThinLock (in object models which
1839 * do not allocate thin locks for all scalar object types).
1840 */
1841 public void setThinLockOffset(Offset offset) {
1842 if (VM.VerifyAssertions) VM._assert(thinLockOffset.isMax());
1843 if (VM.VerifyAssertions) VM._assert(!offset.isMax());
1844 thinLockOffset = offset;
1845 }
1846
1847 /**
1848 * Get number of superclasses to Object.
1849 */
1850 @Override
1851 @Pure
1852 @Uninterruptible
1853 public int getTypeDepth() {
1854 return depth;
1855 }
1856
1857 /**
1858 * @return <code>true</code>
1859 */
1860 @Override
1861 @Pure
1862 @Uninterruptible
1863 public boolean isClassType() {
1864 return true;
1865 }
1866
1867 /**
1868 * @return <code>false</code>
1869 */
1870 @Override
1871 @Pure
1872 @Uninterruptible
1873 public boolean isArrayType() {
1874 return false;
1875 }
1876
1877 /**
1878 * @return <code>false</code>
1879 */
1880 @Override
1881 @Pure
1882 @Uninterruptible
1883 public boolean isPrimitiveType() {
1884 return false;
1885 }
1886
1887 /**
1888 * @return <code>true</code>
1889 */
1890 @Override
1891 @Pure
1892 @Uninterruptible
1893 public boolean isReferenceType() {
1894 return true;
1895 }
1896
1897 /**
1898 * @return <code>false</code>
1899 */
1900 @Override
1901 @Pure
1902 @Uninterruptible
1903 public boolean isUnboxedType() {
1904 return false;
1905 }
1906
1907 /**
1908 * Create a synthetic class that extends ReflectionBase and invokes the given method
1909 * @param methodToCall the method we wish to call reflectively
1910 * @return the synthetic class
1911 */
1912 static Class<?> createReflectionClass(RVMMethod methodToCall) {
1913 if (VM.VerifyAssertions) VM._assert(VM.runningVM);
1914 if (DynamicTypeCheck.instanceOfResolved(TypeReference.baseReflectionClass.resolve(), methodToCall.getDeclaringClass())) {
1915 // Avoid reflection on reflection base class
1916 return null;
1917 }
1918 int[] constantPool = new int[methodToCall.getParameterTypes().length+3];
1919 String reflectionClassName = "Lorg/jikesrvm/classloader/ReflectionBase$$Reflect"+methodToCall.getMemberRef().getId()+";";
1920 TypeReference reflectionClass = TypeReference.findOrCreate(reflectionClassName);
1921 RVMType klass = reflectionClass.peekType();
1922 if (klass == null) {
1923 MethodReference reflectionMethodRef = MethodReference.findOrCreate(reflectionClass,
1924 Atom.findOrCreateUnicodeAtom("invokeInternal"),
1925 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")
1926 ).asMethodReference();
1927 MethodReference constructorMethodRef = MethodReference.findOrCreate(reflectionClass,
1928 Atom.findOrCreateUnicodeAtom("<init>"),
1929 Atom.findOrCreateUnicodeAtom("()V")
1930 ).asMethodReference();
1931
1932 RVMMethod[] reflectionMethods = new RVMMethod[]{
1933 methodToCall.createReflectionMethod(reflectionClass, constantPool, reflectionMethodRef),
1934 RVMMethod.createDefaultConstructor(reflectionClass, constructorMethodRef)};
1935 klass =
1936 new RVMClass(reflectionClass, constantPool, (short) (ACC_SYNTHETIC | ACC_PUBLIC | ACC_FINAL), // modifiers
1937 TypeReference.baseReflectionClass.resolve().asClass(), // superClass
1938 emptyVMClass, // declaredInterfaces
1939 emptyVMField, reflectionMethods,
1940 null, null, null, null, null, null, null, null);
1941 reflectionClass.setType(klass);
1942 RuntimeEntrypoints.initializeClassForDynamicLink(klass.asClass());
1943 }
1944 return klass.getClassForType();
1945 }
1946 }