/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.objectmodel; import org.jikesrvm.VM; import org.jikesrvm.VM_SizeConstants; import org.jikesrvm.annotations.NoSubArchCompile; import org.jikesrvm.annotations.SubArchEntrypoint; import org.jikesrvm.classloader.VM_Array; import org.jikesrvm.classloader.VM_Class; import org.jikesrvm.classloader.VM_Type; import org.jikesrvm.compilers.common.assembler.VM_AbstractAssembler; import org.jikesrvm.memorymanagers.mminterface.MM_Interface; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.scheduler.VM_Lock; import org.jikesrvm.scheduler.VM_Thread; import org.vmmagic.pragma.Entrypoint; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Interruptible; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; /** * The interface to the object model definition accessible to the * virtual machine. <p> * * Conceptually each Java object is composed of the following pieces: * <ul> * <li> The JavaHeader defined by {@link VM_JavaHeader}. This portion of the * object supports language-level functions such as locking, hashcodes, * dynamic type checking, virtual function invocation, and array length. * <li> The GCHeader defined by {@link MM_Interface}. This portion * of the object supports allocator-specific requirements such as * mark/barrier bits, reference counts, etc. * <li> The MiscHeader defined by {@link VM_MiscHeader}. This portion supports * various other clients that want to add bits/words to all objects. * Typical uses are profiling and instrumentation (basically this is a * way to add an instance field to java.lang.Object). * <li> The instance fields. Currently defined by various classloader classes. * Factoring this code out and making it possible to lay out the instance * fields in different ways is a todo item. * </ul> * * Every object's header contains the three portions outlined above. * * <pre> * |<- lo memory hi memory ->| * * SCALAR LAYOUT: * |<---------- scalar header --------->| * +----------+------------+------------+------+------+------+--------+ * | GCHeader | MiscHeader | JavaHeader | fldO | fld1 | fldx | fldN-1 | * +----------+------------+------------+------+------+------+--------+ * ^ JHOFF ^objref * . * ARRAY LAYOUT: . * |<---------- array header ----------------->| * +----------+------------+------------+------+------+------+------+------+ * | GCHeader | MiscHeader | JavaHeader | len | elt0 | elt1 | ... |eltN-1| * +----------+------------+------------+------+------+------+------+------+ * ^ JHOFF ^objref * </pre> * * Assumptions: * <ul> * <li> Each portion of the header (JavaHeader, GCHeader, MiscHeader) * is some multiple of 4 bytes (possibly 0). This simplifies access, since we * can access each portion independently without having to worry about word tearing. * <li> The JavaHeader exports k (>=0) unused contiguous bits that can be used * by the GCHeader and MiscHeader. The GCHeader gets first dibs on these bits. * The GCHeader should use buts 0..i, MiscHeader should use bits i..k. * <li> JHOFF is a constant for a given configuration. * </ul> * * This model allows efficient array access: the array pointer can be * used directly in the base+offset subscript calculation, with no * additional constant required.<p> * * This model allows free null pointer checking for most reads: a * small offset from that reference will wrap around to either very * high or very low unmapped memory in the case of a null pointer. As * long as these segments of memory are not mapped to the current * process, loads/stores through such a pointer will cause a trap that * we can catch with a unix signal handler.<p> * * Note that on AIX we are forced to perform explicit null checks on * scalar field accesses as we are unable to protect low memory. * * Note the key invariant that all elements of the header are * available at the same offset from an objref for both arrays and * scalar objects. * * Note that this model allows for arbitrary growth of the GC header * to the left of the object. A possible TODO item is to modify the * necessary interfaces within this class and JavaHeader to allow * moveObject, bytesUsed, bytesRequiredWhenCopied, etc. to tell this * class how many GC header bytes have been allocated. As these calls * would be constant within the constant of the call the optimising * compiler should be able to allow this at minimal cost. * * Another possible TODO item is to include support for linear * scanning, where it is possible to move from one object to the next * under contiguous allocation. At the moment this is in conflict with * object alignment code for objects with long/double fields. We could * possibly include the code anyway but require that the alignment * code is switched off, or that all objects are aligned. Linear * scanning is used in several GC algorithms including card-marking * and compaction. * * @see VM_JavaHeader * @see VM_MiscHeader * @see MM_Interface */ @Uninterruptible public class VM_ObjectModel implements VM_JavaHeaderConstants, VM_SizeConstants { /** Should we gather stats on hash code state transitions for address-based hashing? */ public static final boolean HASH_STATS = false; /** count number of Object.hashCode() operations */ public static int hashRequests = 0; /** count transitions from UNHASHED to HASHED */ public static int hashTransition1 = 0; /** count transitions from HASHED to HASHED_AND_MOVED */ public static int hashTransition2 = 0; /** Whether to pack bytes and shorts into 32bit fields*/ private static final boolean PACKED = true; /** Layout widget */ private static final VM_FieldLayout layout; static { if (PACKED) { layout = new VM_FieldLayoutPacked(true, false); } else { layout = new VM_FieldLayoutUnpacked(true, false); } } /** * Layout the instance fields declared in this class. * @param klass the class to layout */ @Interruptible @NoSubArchCompile public static void layoutInstanceFields(VM_Class klass) { layout.layoutInstanceFields(klass); } /** * Given a reference, return an address which is guaranteed to be inside * the memory region allocated to the object. */ public static Address getPointerInMemoryRegion(ObjectReference ref) { return VM_JavaHeader.getPointerInMemoryRegion(ref); } /** * Return the offset of the array length field from an object reference * (in bytes) */ public static Offset getArrayLengthOffset() { return ARRAY_LENGTH_OFFSET; } /** * Get the TIB for an object. */ public static Object[] getTIB(ObjectReference ptr) { return getTIB(ptr.toObject()); } /** * Get the TIB for an object. */ public static Object[] getTIB(Object o) { return VM_JavaHeader.getTIB(o); } /** * Set the TIB for an object. */ public static void setTIB(ObjectReference ptr, Object[] tib) { setTIB(ptr.toObject(), tib); } /** * Set the TIB for an object. */ public static void setTIB(Object ref, Object[] tib) { VM_JavaHeader.setTIB(ref, tib); } /** * Set the TIB for an object. */ @Interruptible public static void setTIB(BootImageInterface bootImage, Address refAddress, Address tibAddr, VM_Type type) { VM_JavaHeader.setTIB(bootImage, refAddress, tibAddr, type); } /** * Get the pointer just past an object */ public static Address getObjectEndAddress(Object obj) { Object[] tib = getTIB(obj); VM_Type type = VM_Magic.objectAsType(tib[VM_TIBLayoutConstants.TIB_TYPE_INDEX]); if (type.isClassType()) { return getObjectEndAddress(obj, type.asClass()); } else { int numElements = VM_Magic.getArrayLength(obj); return getObjectEndAddress(obj, type.asArray(), numElements); } } /** * Get the pointer just past an object */ public static Address getObjectEndAddress(Object object, VM_Class type) { return VM_JavaHeader.getObjectEndAddress(object, type); } /** * Get the pointer just past an object */ public static Address getObjectEndAddress(Object object, VM_Array type, int elements) { return VM_JavaHeader.getObjectEndAddress(object, type, elements); } /** * Get an object reference from the address the lowest word of the object was allocated. */ public static ObjectReference getObjectFromStartAddress(Address start) { return VM_JavaHeader.getObjectFromStartAddress(start); } /** * Get an object reference from the address the lowest word of the object was allocated. */ public static ObjectReference getScalarFromStartAddress(Address start) { return VM_JavaHeader.getScalarFromStartAddress(start); } /** * Get an object reference from the address the lowest word of the object was allocated. */ public static ObjectReference getArrayFromStartAddress(Address start) { return VM_JavaHeader.getArrayFromStartAddress(start); } /** * Get the next object in the heap under contiguous allocation. */ public static ObjectReference getNextObject(ObjectReference obj) { Object[] tib = getTIB(obj); VM_Type type = VM_Magic.objectAsType(tib[VM_TIBLayoutConstants.TIB_TYPE_INDEX]); if (type.isClassType()) { return getNextObject(obj, type.asClass()); } else { int numElements = VM_Magic.getArrayLength(obj); return getNextObject(obj, type.asArray(), numElements); } } /** * Get the next object after this scalar under contiguous allocation. */ public static ObjectReference getNextObject(ObjectReference obj, VM_Class type) { return VM_JavaHeader.getNextObject(obj, type); } /** * Get the next object after this array under contiguous allocation. */ public static ObjectReference getNextObject(ObjectReference obj, VM_Array type, int numElements) { return VM_JavaHeader.getNextObject(obj, type, numElements); } /** * how many bytes are used by the object? */ public static Object getReferenceWhenCopiedTo(Object obj, Address to) { Object[] tib = getTIB(obj); VM_Type type = VM_Magic.objectAsType(tib[VM_TIBLayoutConstants.TIB_TYPE_INDEX]); if (type.isClassType()) { return getReferenceWhenCopiedTo(obj, to, type.asClass()); } else { return getReferenceWhenCopiedTo(obj, to, type.asArray()); } } /** * how many bytes are used by the object? */ public static int bytesUsed(Object obj) { Object[] tib = getTIB(obj); VM_Type type = VM_Magic.objectAsType(tib[VM_TIBLayoutConstants.TIB_TYPE_INDEX]); if (type.isClassType()) { return bytesUsed(obj, type.asClass()); } else { int numElements = VM_Magic.getArrayLength(obj); return bytesUsed(obj, type.asArray(), numElements); } } /** * how many bytes are used by the scalar? */ public static int bytesUsed(Object obj, VM_Class type) { return VM_JavaHeader.bytesUsed(obj, type); } /** * how many bytes are used by the array? */ public static int bytesUsed(Object obj, VM_Array type, int numElements) { return VM_JavaHeader.bytesUsed(obj, type, numElements); } /** * how many bytes are required when the object is copied by GC? */ public static int bytesRequiredWhenCopied(Object obj) { Object[] tib = getTIB(obj); VM_Type type = VM_Magic.objectAsType(tib[VM_TIBLayoutConstants.TIB_TYPE_INDEX]); if (type.isClassType()) { return bytesRequiredWhenCopied(obj, type.asClass()); } else { int numElements = VM_Magic.getArrayLength(obj); return bytesRequiredWhenCopied(obj, type.asArray(), numElements); } } /** * how many bytes are needed when the scalar object is copied by GC? */ public static int bytesRequiredWhenCopied(Object fromObj, VM_Class type) { return VM_JavaHeader.bytesRequiredWhenCopied(fromObj, type); } /** * how many bytes are needed when the array object is copied by GC? */ public static int bytesRequiredWhenCopied(Object fromObj, VM_Array type, int numElements) { return VM_JavaHeader.bytesRequiredWhenCopied(fromObj, type, numElements); } /** * Map from the object ref to the lowest address of the storage * associated with the object */ @Inline public static Address objectStartRef(ObjectReference obj) { return VM_JavaHeader.objectStartRef(obj); } /** * Get the reference of an object after copying to a specified region. */ public static Object getReferenceWhenCopiedTo(Object obj, Address region, VM_Class type) { return VM_JavaHeader.getReferenceWhenCopiedTo(obj, region, type); } /** * Get the reference of an object after copying to a specified region. */ public static Object getReferenceWhenCopiedTo(Object obj, Address region, VM_Array type) { return VM_JavaHeader.getReferenceWhenCopiedTo(obj, region, type); } /** * Copy a scalar object to the given raw storage address */ public static Object moveObject(Object fromObj, Object toObj, int numBytes, boolean noGCHeader, VM_Class type) { return VM_JavaHeader.moveObject(fromObj, toObj, numBytes, noGCHeader, type); } /** * Copy an array object to the given raw storage address */ public static Object moveObject(Object fromObj, Object toObj, int numBytes, boolean noGCHeader, VM_Array type) { return VM_JavaHeader.moveObject(fromObj, toObj, numBytes, noGCHeader, type); } /** * Copy a scalar object to the given raw storage address */ public static Object moveObject(Address toAddress, Object fromObj, int numBytes, boolean noGCHeader, VM_Class type) { return VM_JavaHeader.moveObject(toAddress, fromObj, numBytes, noGCHeader, type); } /** * Copy an array object to the given raw storage address */ public static Object moveObject(Address toAddress, Object fromObj, int numBytes, boolean noGCHeader, VM_Array type) { return VM_JavaHeader.moveObject(toAddress, fromObj, numBytes, noGCHeader, type); } /** * Get the type of an object. */ public static VM_Type getObjectType(Object o) { return VM_Magic.getObjectType(o); } /** * Get the length of an array */ @NoSubArchCompile public static int getArrayLength(Object o) { return VM_Magic.getIntAtOffset(o, getArrayLengthOffset()); } /** * Set the length of an array */ @NoSubArchCompile public static void setArrayLength(Object o, int len) { VM_Magic.setIntAtOffset(o, getArrayLengthOffset(), len); } /** * Get the hash code of an object. */ public static int getObjectHashCode(Object o) { if (HASH_STATS) hashRequests++; return VM_JavaHeader.getObjectHashCode(o); } /** * Get the offset of the thin lock word in this object */ public static Offset getThinLockOffset(Object o) { return VM_JavaHeader.getThinLockOffset(o); } /** * what is the default offset for a thin lock? */ public static Offset defaultThinLockOffset() { return VM_JavaHeader.defaultThinLockOffset(); } /** * Allocate a thin lock word for instances of the type * (if they already have one, then has no effect). */ public static void allocateThinLock(VM_Type t) { VM_JavaHeader.allocateThinLock(t); } /** * Generic lock */ @Entrypoint @SubArchEntrypoint public static void genericLock(Object o) { VM_JavaHeader.genericLock(o); } /** * Generic unlock */ @Entrypoint @SubArchEntrypoint public static void genericUnlock(Object o) { VM_JavaHeader.genericUnlock(o); } /** * @param obj an object * @param thread a thread * @return <code>true</code> if the lock on obj is currently owned * by thread <code>false</code> if it is not. */ public static boolean holdsLock(Object obj, VM_Thread thread) { return VM_JavaHeader.holdsLock(obj, thread); } /** * Obtains the heavy-weight lock, if there is one, associated with the * indicated object. Returns <code>null</code>, if there is no * heavy-weight lock associated with the object. * * @param o the object from which a lock is desired * @param create if true, create heavy lock if none found * @return the heavy-weight lock on the object (if any) */ public static VM_Lock getHeavyLock(Object o, boolean create) { return VM_JavaHeader.getHeavyLock(o, create); } /** * Non-atomic read of word containing available bits */ public static Word readAvailableBitsWord(Object o) { return VM_JavaHeader.readAvailableBitsWord(o); } /** * Non-atomic read of byte containing available bits */ public static byte readAvailableByte(Object o) { return VM_JavaHeader.readAvailableByte(o); } /** * Non-atomic write of word containing available bits */ public static void writeAvailableBitsWord(Object o, Word val) { VM_JavaHeader.writeAvailableBitsWord(o, val); } /** * Non-atomic write of byte containing available bits */ public static void writeAvailableByte(Object o, byte val) { VM_JavaHeader.writeAvailableByte(o, val); } /** * Return true if argument bit is 1, false if it is 0 */ public static boolean testAvailableBit(Object o, int idx) { return VM_JavaHeader.testAvailableBit(o, idx); } /** * Set argument bit to 1 if flag is true, 0 if flag is false */ public static void setAvailableBit(Object o, int idx, boolean flag) { VM_JavaHeader.setAvailableBit(o, idx, flag); } /** * Freeze the other bits in the byte containing the available bits * so that it is safe to update them using setAvailableBits. */ public static void initializeAvailableByte(Object o) { VM_JavaHeader.initializeAvailableByte(o); } /** * A prepare on the word containing the available bits */ public static Word prepareAvailableBits(Object o) { return VM_JavaHeader.prepareAvailableBits(o); } /** * An attempt on the word containing the available bits */ public static boolean attemptAvailableBits(Object o, Word oldVal, Word newVal) { return VM_JavaHeader.attemptAvailableBits(o, oldVal, newVal); } /** * Given the smallest base address in a region, return the smallest * object reference that could refer to an object in the region. */ public static Address minimumObjectRef(Address regionBaseAddr) { return VM_JavaHeader.minimumObjectRef(regionBaseAddr); } /** * Given the largest base address in a region, return the largest * object reference that could refer to an object in the region. */ public static Address maximumObjectRef(Address regionHighAddr) { return VM_JavaHeader.maximumObjectRef(regionHighAddr); } /** * Compute the header size of an instance of the given type. */ @Inline public static int computeHeaderSize(VM_Type type) { if (type.isArrayType()) { return computeArrayHeaderSize(type.asArray()); } else { return computeScalarHeaderSize(type.asClass()); } } /** * Compute the header size of an object */ @Interruptible public static int computeHeaderSize(Object ref) { return computeHeaderSize(getObjectType(ref)); } /** * Compute the header size of an instance of the given type. */ @Inline public static int computeScalarHeaderSize(VM_Class type) { return VM_JavaHeader.computeScalarHeaderSize(type); } /** * Compute the header size of an instance of the given type. */ public static int computeArrayHeaderSize(VM_Array type) { return VM_JavaHeader.computeArrayHeaderSize(type); } /** * Given a TIB, compute the header size of an instance of the TIB's class */ public static int computeHeaderSize(Object[] tib) { return computeHeaderSize(VM_Magic.objectAsType(tib[0])); } /** * For a reference to an object, what is the offset in bytes to the * last word of the header from an out-to-in perspective for the object? */ public static int getHeaderEndOffset() { return VM_JavaHeader.getHeaderEndOffset(); } /** * For a reference to an object, what is the offset in bytes to the bottom * word of the object? */ public static int objectStartOffset(VM_Class t) { return VM_JavaHeader.objectStartOffset(t); } /** * Return the desired aligment of the alignment point in the object returned * by getScalarOffsetForAlignment. * @param t VM_Class instance being created */ public static int getAlignment(VM_Class t) { return VM_JavaHeader.getAlignment(t); } /** * Return the desired aligment of the alignment point returned by * getOffsetForAlignment in instances of the argument VM_Class. * @param t VM_Class instance being copied * @param obj the object being copied */ public static int getAlignment(VM_Class t, Object obj) { return VM_JavaHeader.getAlignment(t, obj); } /** * Return the desired aligment of the alignment point returned by * getOffsetForAlignment in instances of the argument VM_Array. * @param t VM_Array instance being created */ public static int getAlignment(VM_Array t) { return VM_JavaHeader.getAlignment(t); } /** * Return the desired aligment of the alignment point returned by * getOffsetForAlignment in instances of the argument VM_Array. * @param t VM_Array instance being copied * @param obj the object being copied */ public static int getAlignment(VM_Array t, Object obj) { return VM_JavaHeader.getAlignment(t, obj); } /** * Return the offset relative to physical beginning of object * that must be aligned. * @param t VM_Class instance being created */ public static int getOffsetForAlignment(VM_Class t) { return VM_JavaHeader.getOffsetForAlignment(t); } /** * Return the offset relative to physical beginning of object * that must be aligned. * @param t VM_Class instance being copied * @param obj the object being copied */ public static int getOffsetForAlignment(VM_Class t, ObjectReference obj) { return VM_JavaHeader.getOffsetForAlignment(t, obj); } /** * Return the offset relative to physical beginning of object that must * be aligned. * @param t VM_Array instance being created */ public static int getOffsetForAlignment(VM_Array t) { return VM_JavaHeader.getOffsetForAlignment(t); } /** * Return the offset relative to physical beginning of object that must * be aligned. * @param t VM_Array instance being copied * @param obj the object being copied */ public static int getOffsetForAlignment(VM_Array t, ObjectReference obj) { return VM_JavaHeader.getOffsetForAlignment(t, obj); } /** * Initialize raw storage with low memory word ptr of size bytes * to be an uninitialized instance of the (scalar) type specified by tib. * * @param ptr address of raw storage * @param tib the type information block * @param size number of bytes of raw storage allocated. */ @Inline public static Object initializeScalar(Address ptr, Object[] tib, int size) { Object ref = VM_JavaHeader.initializeScalarHeader(ptr, tib, size); VM_MiscHeader.initializeHeader(ref, tib, size, true); setTIB(ref, tib); return ref; } /** * Allocate and initialize space in the bootimage (at bootimage writing time) * to be an uninitialized instance of the (scalar) type specified by klass. * NOTE: TIB is set by BootImageWriter2 * * @param bootImage the bootimage to put the object in * @param klass the VM_Class object of the instance to create. * @return the offset of object in bootimage (in bytes) */ @Interruptible public static Address allocateScalar(BootImageInterface bootImage, VM_Class klass) { Object[] tib = klass.getTypeInformationBlock(); int size = klass.getInstanceSize(); int align = getAlignment(klass); int offset = getOffsetForAlignment(klass); Address ptr = bootImage.allocateDataStorage(size, align, offset); Address ref = VM_JavaHeader.initializeScalarHeader(bootImage, ptr, tib, size); MM_Interface.initializeHeader(bootImage, ref, tib, size, true); VM_MiscHeader.initializeHeader(bootImage, ref, tib, size, klass, true); return ref; } /** * Fill an alignment gap with the alignment value */ @Interruptible public static void fillAlignmentGap(BootImageInterface bootImage, Address address, Extent size) { while (size.GT(Extent.zero())) { bootImage.setFullWord(address, VM_JavaHeader.ALIGNMENT_VALUE); address = address.plus(BYTES_IN_INT); size = size.minus(BYTES_IN_INT); } } /** * Initialize raw storage with low memory word ptr of size bytes * to be an uninitialized instance of the array type specific by tib * with numElems elements. * * @param ptr address of raw storage * @param tib the type information block * @param numElems number of elements in the array * @param size number of bytes of raw storage allocated. */ @Inline public static Object initializeArray(Address ptr, Object[] tib, int numElems, int size) { Object ref = VM_JavaHeader.initializeArrayHeader(ptr, tib, size); VM_MiscHeader.initializeHeader(ref, tib, size, false); setTIB(ref, tib); setArrayLength(ref, numElems); return ref; } /** * Allocate and initialize space in the bootimage (at bootimage writing time) * to be an uninitialized instance of the (array) type specified by array. * NOTE: TIB is set by BootimageWriter2 * * @param bootImage the bootimage to put the object in * @param array VM_Array object of array being allocated. * @param numElements number of elements * @return Address of object in bootimage (in bytes) */ @Interruptible public static Address allocateArray(BootImageInterface bootImage, VM_Array array, int numElements) { Object[] tib = array.getTypeInformationBlock(); int size = array.getInstanceSize(numElements); int align = getAlignment(array); int offset = getOffsetForAlignment(array); Address ptr = bootImage.allocateDataStorage(size, align, offset); Address ref = VM_JavaHeader.initializeArrayHeader(bootImage, ptr, tib, size); bootImage.setFullWord(ref.plus(getArrayLengthOffset()), numElements); MM_Interface.initializeHeader(bootImage, ref, tib, size, false); VM_MiscHeader.initializeHeader(bootImage, ref, tib, size, array, false); return ref; } /** * Allocate and initialize space in the bootimage (at bootimage writing time) * to be an uninitialized instance of the (array) type specified by array. * NOTE: TIB is set by BootimageWriter2 * * @param bootImage the bootimage to put the object in * @param array VM_Array object of array being allocated. * @param numElements number of elements * @return Address of object in bootimage */ @Interruptible public static Address allocateCode(BootImageInterface bootImage, VM_Array array, int numElements) { Object[] tib = array.getTypeInformationBlock(); int size = array.getInstanceSize(numElements); int align = getAlignment(array); int offset = getOffsetForAlignment(array); Address ptr = bootImage.allocateCodeStorage(size, align, offset); Address ref = VM_JavaHeader.initializeArrayHeader(bootImage, ptr, tib, size); bootImage.setFullWord(ref.plus(getArrayLengthOffset()), numElements); MM_Interface.initializeHeader(bootImage, ref, tib, size, false); VM_MiscHeader.initializeHeader(bootImage, ref, tib, size, array, false); return ref; } /** * For low level debugging of GC subsystem. * Dump the header word(s) of the given object reference. * @param ptr the object reference whose header should be dumped */ public static void dumpHeader(ObjectReference ptr) { dumpHeader(ptr.toObject()); } /** * For low level debugging of GC subsystem. * Dump the header word(s) of the given object reference. * @param ref the object reference whose header should be dumped */ public static void dumpHeader(Object ref) { VM.sysWrite(" TIB="); VM.sysWrite(VM_Magic.objectAsAddress(getTIB(ref))); VM_JavaHeader.dumpHeader(ref); VM_MiscHeader.dumpHeader(ref); } /** * For debugging. */ public static void describeObject(ObjectReference addr) { Object obj = addr.toObject(); VM_Type type = VM_Magic.getObjectType(obj); VM.sysWrite(type.getDescriptor()); } /** * The following method will emit code that moves a reference to an * object's TIB into a destination register. * * @param asm the assembler object to emit code with * @param dest the number of the destination register * @param object the number of the register holding the object reference */ @Interruptible public static void baselineEmitLoadTIB(VM_AbstractAssembler asm, int dest, int object, boolean forSubArch) { VM_JavaHeader.baselineEmitLoadTIB(asm, dest, object, forSubArch); } }