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 }