/* * 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_Configuration; import org.jikesrvm.VM_SizeConstants; import org.jikesrvm.annotations.NoSubArchCompile; 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_Constants; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.runtime.VM_Memory; import org.jikesrvm.scheduler.VM_Lock; import org.jikesrvm.scheduler.VM_ThinLock; import org.jikesrvm.scheduler.VM_Thread; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Interruptible; import org.vmmagic.pragma.NoInline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; /** * Defines the JavaHeader portion of the object header for the * default JikesRVM object model. * The default object model uses a two word header. <p> * * One word holds a TIB pointer. <p> * * The other word ("status word") contains an inline thin lock, * either the hash code or hash code state, and a few unallocated * bits that can be used for other purposes. * If {@link VM_JavaHeaderConstants#ADDRESS_BASED_HASHING} is false, * then to implement default hashcodes, Jikes RVM uses a 10 bit hash code * that is completely stored in the status word, which is laid out as * shown below: * <pre> * TTTT TTTT TTTT TTTT TTTT HHHH HHHH HHAA * T = thin lock bits * H = hash code * A = available for use by GCHeader and/or MiscHeader. * </pre> * * If {@link VM_JavaHeaderConstants#ADDRESS_BASED_HASHING ADDRESS_BASED_HASHING} is true, * then Jikes RVM uses two bits of the status word to record the hash code state in * a typical three state scheme ({@link #HASH_STATE_UNHASHED}, {@link #HASH_STATE_HASHED}, * and {@link #HASH_STATE_HASHED_AND_MOVED}). In this case, the status word is laid * out as shown below: * <pre> * TTTT TTTT TTTT TTTT TTTT TTHH AAAA AAAA * T = thin lock bits * H = hash code state bits * A = available for use by GCHeader and/or MiscHeader. * </pre> */ @Uninterruptible public class VM_JavaHeader implements VM_JavaHeaderConstants { protected static final int SCALAR_HEADER_SIZE = JAVA_HEADER_BYTES + OTHER_HEADER_BYTES; protected static final int ARRAY_HEADER_SIZE = SCALAR_HEADER_SIZE + ARRAY_LENGTH_BYTES; /** offset of object reference from the lowest memory word */ protected static final int OBJECT_REF_OFFSET = ARRAY_HEADER_SIZE; // from start to ref public static final Offset TIB_OFFSET = JAVA_HEADER_OFFSET; public static final Offset STATUS_OFFSET = TIB_OFFSET.plus(STATUS_BYTES); protected static final Offset AVAILABLE_BITS_OFFSET = VM.LittleEndian ? (STATUS_OFFSET) : (STATUS_OFFSET.plus(STATUS_BYTES - 1)); /* * Used for 10 bit header hash code in header (!ADDRESS_BASED_HASHING) */ protected static final int HASH_CODE_SHIFT = 2; protected static final Word HASH_CODE_MASK = Word.one().lsh(10).minus(Word.one()).lsh(HASH_CODE_SHIFT); protected static Word hashCodeGenerator; // seed for generating hash codes with copying collectors. /** How many bits are allocated to a thin lock? */ public static final int NUM_THIN_LOCK_BITS = ADDRESS_BASED_HASHING && !SUBARCH_CLASS_IDX_IN_HEADER ? 22 : 20; /** How many bits to shift to get the thin lock? */ public static final int THIN_LOCK_SHIFT = ADDRESS_BASED_HASHING && !SUBARCH_CLASS_IDX_IN_HEADER ? 10 : 12; /** The alignment value **/ public static final int ALIGNMENT_VALUE = VM_JavaHeaderConstants.ALIGNMENT_VALUE; public static final int LOG_MIN_ALIGNMENT = VM_JavaHeaderConstants.LOG_MIN_ALIGNMENT; static { if (VM.VerifyAssertions) { VM._assert(VM_MiscHeader.REQUESTED_BITS + MM_Constants.GC_HEADER_BITS <= NUM_AVAILABLE_BITS); } } /** * Return the TIB offset. */ public static Offset getTibOffset() { return TIB_OFFSET; } /** * What is the offset of the first word after the class? * For use by VM_ObjectModel.layoutInstanceFields */ public static Offset objectEndOffset(VM_Class klass) { return Offset.fromIntSignExtend(klass.getInstanceSizeInternal() - OBJECT_REF_OFFSET); } /** * What is the first word after the class? */ public static Address getObjectEndAddress(Object obj, VM_Class type) { int size = type.getInstanceSize(); if (ADDRESS_BASED_HASHING && DYNAMIC_HASH_OFFSET) { Word hashState = VM_Magic.objectAsAddress(obj).loadWord(STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { size += HASHCODE_BYTES; } } return VM_Magic.objectAsAddress(obj).plus(VM_Memory.alignUp(size, VM_SizeConstants.BYTES_IN_INT) - OBJECT_REF_OFFSET); } /** * What is the first word after the array? */ @NoSubArchCompile public static Address getObjectEndAddress(Object obj, VM_Array type, int numElements) { int size = type.getInstanceSize(numElements); if (ADDRESS_BASED_HASHING && DYNAMIC_HASH_OFFSET) { Word hashState = VM_Magic.getWordAtOffset(obj, STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { size += HASHCODE_BYTES; } } return VM_Magic.objectAsAddress(obj).plus(VM_Memory.alignUp(size, VM_SizeConstants.BYTES_IN_INT) - OBJECT_REF_OFFSET); } /** * What is the offset of the first word of the class? */ public static int objectStartOffset(VM_Class klass) { return -OBJECT_REF_OFFSET; } /** * What is the last word of the header from an out-to-in perspective? */ public static int getHeaderEndOffset() { return SCALAR_HEADER_SIZE - OBJECT_REF_OFFSET; } /** * How small is the minimum object header size? * Can be used to pick chunk sizes for allocators. */ public static int minimumObjectSize() { return SCALAR_HEADER_SIZE; } /** * 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 ref.toAddress().plus(TIB_OFFSET); } /** * Get the TIB for an object. */ @NoSubArchCompile public static Object[] getTIB(Object o) { return VM_Magic.getObjectArrayAtOffset(o, TIB_OFFSET); } /** * Set the TIB for an object. */ public static void setTIB(Object ref, Object[] tib) { VM_Magic.setObjectAtOffset(ref, TIB_OFFSET, tib); } /** * Set the TIB for an object. */ @Interruptible public static void setTIB(BootImageInterface bootImage, Address refOffset, Address tibAddr, VM_Type type) { bootImage.setAddressWord(refOffset.plus(TIB_OFFSET), tibAddr.toWord(), false); } /** * how many bytes are needed when the scalar object is copied by GC? */ @NoSubArchCompile public static int bytesRequiredWhenCopied(Object fromObj, VM_Class type) { int size = type.getInstanceSize(); if (ADDRESS_BASED_HASHING) { Word hashState = VM_Magic.getWordAtOffset(fromObj, STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.NE(HASH_STATE_UNHASHED)) { size += HASHCODE_BYTES; } } return size; } /** * how many bytes are used by the scalar object? */ @NoSubArchCompile public static int bytesUsed(Object obj, VM_Class type) { int size = type.getInstanceSize(); if (MM_Constants.MOVES_OBJECTS) { if (ADDRESS_BASED_HASHING) { Word hashState = VM_Magic.getWordAtOffset(obj, STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { size += HASHCODE_BYTES; } } } return size; } /** * how many bytes are needed when the array object is copied by GC? */ @NoSubArchCompile public static int bytesRequiredWhenCopied(Object fromObj, VM_Array type, int numElements) { int size = type.getInstanceSize(numElements); if (ADDRESS_BASED_HASHING) { Word hashState = VM_Magic.getWordAtOffset(fromObj, STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.NE(HASH_STATE_UNHASHED)) { size += HASHCODE_BYTES; } } return VM_Memory.alignUp(size, VM_SizeConstants.BYTES_IN_INT); } /** * how many bytes are used by the array object? */ @NoSubArchCompile public static int bytesUsed(Object obj, VM_Array type, int numElements) { int size = type.getInstanceSize(numElements); if (MM_Constants.MOVES_OBJECTS) { if (ADDRESS_BASED_HASHING) { Word hashState = VM_Magic.getWordAtOffset(obj, STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { size += HASHCODE_BYTES; } } } return VM_Memory.alignUp(size, VM_SizeConstants.BYTES_IN_INT); } /** * Map from the object ref to the lowest address of the storage * associated with the object */ @Inline public static Address objectStartRef(ObjectReference obj) { if (MM_Constants.MOVES_OBJECTS) { if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) { Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { return obj.toAddress().minus(OBJECT_REF_OFFSET + HASHCODE_BYTES); } } } return obj.toAddress().minus(OBJECT_REF_OFFSET); } /** * Get an object reference from the address the lowest word of the * object was allocated. In general this required that we are using * a dynamic hash offset or not using address based * hashing. However, the GC algorithm could safely do this in the * nursery so we can't assert DYNAMIC_HASH_OFFSET. */ public static ObjectReference getObjectFromStartAddress(Address start) { if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) { start = start.plus(VM_SizeConstants.BYTES_IN_WORD); if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) { start = start.plus(VM_SizeConstants.BYTES_IN_WORD); if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) { start = start.plus(VM_SizeConstants.BYTES_IN_WORD); if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) { start = start.plus(VM_SizeConstants.BYTES_IN_WORD); if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) { return ObjectReference.nullReference(); } } } } } return start.plus(OBJECT_REF_OFFSET).toObjectReference(); } /** * Get an object reference from the address the lowest word of the * object was allocated. */ public static ObjectReference getScalarFromStartAddress(Address start) { return getObjectFromStartAddress(start); } /** * Get an object reference from the address the lowest word of the * object was allocated. */ public static ObjectReference getArrayFromStartAddress(Address start) { return getObjectFromStartAddress(start); } /** * Get the next object in the heap under contiguous * allocation. Handles alignment issues only when there are no GC or * Misc header words. In the case there are we probably have to ask * MM_Interface to distinguish this for us. */ protected static ObjectReference getNextObject(ObjectReference obj, int size) { if (VM.VerifyAssertions) VM._assert(OTHER_HEADER_BYTES == 0); return getObjectFromStartAddress(obj.toAddress().plus(size).minus(OBJECT_REF_OFFSET)); } /** * Get the next scalar in the heap under contiguous * allocation. Handles alignment issues */ public static ObjectReference getNextObject(ObjectReference obj, VM_Class type) { return getObjectFromStartAddress(getObjectEndAddress(obj.toObject(), type)); } /** * Get the next array in the heap under contiguous * allocation. Handles alignment issues */ public static ObjectReference getNextObject(ObjectReference obj, VM_Array type, int numElements) { return getObjectFromStartAddress(getObjectEndAddress(obj.toObject(), type, numElements)); } /** * Get the reference of an array when copied to the specified region. */ @Inline public static Object getReferenceWhenCopiedTo(Object obj, Address to, VM_Array type) { return getReferenceWhenCopiedTo(obj, to); } /** * Get the reference of a scalar when copied to the specified region. */ @Inline public static Object getReferenceWhenCopiedTo(Object obj, Address to, VM_Class type) { return getReferenceWhenCopiedTo(obj, to); } @Inline @NoSubArchCompile protected static Object getReferenceWhenCopiedTo(Object obj, Address to) { if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) { // Read the hash state (used below) Word statusWord = VM_Magic.getWordAtOffset(obj, STATUS_OFFSET); Word hashState = statusWord.and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED)) { to = to.plus(HASHCODE_BYTES); } } return VM_Magic.addressAsObject(to.plus(OBJECT_REF_OFFSET)); } /** * Copy a scalar to the given raw storage address */ @Inline public static Object moveObject(Address toAddress, Object fromObj, int numBytes, boolean noGCHeader, VM_Class type) { // We copy arrays and scalars the same way return moveObject(toAddress, fromObj, null, numBytes, noGCHeader); } /** * Copy an array to the given location. */ @Inline public static Object moveObject(Object fromObj, Object toObj, int numBytes, boolean noGCHeader, VM_Class type) { // We copy arrays and scalars the same way return moveObject(Address.zero(), fromObj, toObj, numBytes, noGCHeader); } /** * Copy an array to the given raw storage address */ @Inline public static Object moveObject(Address toAddress, Object fromObj, int numBytes, boolean noGCHeader, VM_Array type) { // We copy arrays and scalars the same way return moveObject(toAddress, fromObj, null, numBytes, noGCHeader); } /** * Copy an array to the given location. */ @Inline public static Object moveObject(Object fromObj, Object toObj, int numBytes, boolean noGCHeader, VM_Array type) { // We copy arrays and scalars the same way return moveObject(Address.zero(), fromObj, toObj, numBytes, noGCHeader); } /** * Copy an object to the given raw storage address */ @Inline @NoSubArchCompile public static Object moveObject(Address toAddress, Object fromObj, Object toObj, int numBytes, boolean noGCHeader) { // Default values int copyBytes = numBytes; int objRefOffset = OBJECT_REF_OFFSET; Word statusWord = Word.zero(); Word hashState = HASH_STATE_UNHASHED; if (ADDRESS_BASED_HASHING) { // Read the hash state (used below) statusWord = VM_Magic.getWordAtOffset(fromObj, STATUS_OFFSET); hashState = statusWord.and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED)) { // We do not copy the hashcode, but we do allocate it copyBytes -= HASHCODE_BYTES; if (!DYNAMIC_HASH_OFFSET) { // The hashcode is the first word, so we copy to object one word higher if (toObj == null) { toAddress = toAddress.plus(HASHCODE_BYTES); } } } else if (!DYNAMIC_HASH_OFFSET && hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { // Simple operation (no hash state change), but one word larger header objRefOffset += HASHCODE_BYTES; } } if (toObj != null) { toAddress = VM_Magic.objectAsAddress(toObj).minus(OBJECT_REF_OFFSET); } // Low memory word of source object Address fromAddress = VM_Magic.objectAsAddress(fromObj).minus(objRefOffset); // Was the GC header stolen at allocation time? ok for arrays and scalars. if (noGCHeader) { if (VM.VerifyAssertions) { // No object can be hashed and moved unless using dynamic hash offset VM._assert(hashState.NE(HASH_STATE_HASHED_AND_MOVED) || DYNAMIC_HASH_OFFSET); } // We copy less but start higher in memory. copyBytes -= GC_HEADER_BYTES; objRefOffset -= GC_HEADER_BYTES; toAddress = toAddress.plus(GC_HEADER_BYTES); } // Do the copy VM_Memory.aligned32Copy(toAddress, fromAddress, copyBytes); toObj = VM_Magic.addressAsObject(toAddress.plus(objRefOffset)); // Do we need to copy the hash code? if (hashState.EQ(HASH_STATE_HASHED)) { int hashCode = VM_Magic.objectAsAddress(fromObj).toWord().rshl(VM_SizeConstants.LOG_BYTES_IN_ADDRESS).toInt(); if (DYNAMIC_HASH_OFFSET) { VM_Magic.setIntAtOffset(toObj, Offset.fromIntSignExtend(numBytes - objRefOffset - HASHCODE_BYTES), hashCode); } else { VM_Magic.setIntAtOffset(toObj, HASHCODE_OFFSET, (hashCode << 1) | ALIGNMENT_MASK); } VM_Magic.setWordAtOffset(toObj, STATUS_OFFSET, statusWord.or(HASH_STATE_HASHED_AND_MOVED)); if (VM_ObjectModel.HASH_STATS) VM_ObjectModel.hashTransition2++; } return toObj; } /** * Get the hash code of an object. */ @Inline @NoSubArchCompile public static int getObjectHashCode(Object o) { if (ADDRESS_BASED_HASHING) { if (MM_Constants.MOVES_OBJECTS) { Word hashState = VM_Magic.getWordAtOffset(o, STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.EQ(HASH_STATE_HASHED)) { // HASHED, NOT MOVED return VM_Magic.objectAsAddress(o).toWord().rshl(VM_SizeConstants.LOG_BYTES_IN_ADDRESS).toInt(); } else if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) { // HASHED AND MOVED if (DYNAMIC_HASH_OFFSET) { // Read the size of this object. VM_Type t = VM_Magic.getObjectType(o); int offset = t.isArrayType() ? t.asArray().getInstanceSize(VM_Magic.getArrayLength(o)) - OBJECT_REF_OFFSET : t.asClass().getInstanceSize() - OBJECT_REF_OFFSET; return VM_Magic.getIntAtOffset(o, Offset.fromIntSignExtend(offset)); } else { return (VM_Magic.getIntAtOffset(o, HASHCODE_OFFSET) >>> 1); } } else { // UNHASHED Word tmp; do { tmp = VM_Magic.prepareWord(o, STATUS_OFFSET); } while (!VM_Magic.attemptWord(o, STATUS_OFFSET, tmp, tmp.or(HASH_STATE_HASHED))); if (VM_ObjectModel.HASH_STATS) VM_ObjectModel.hashTransition1++; return getObjectHashCode(o); } } else { return VM_Magic.objectAsAddress(o).toWord().rshl(VM_SizeConstants.LOG_BYTES_IN_ADDRESS).toInt(); } } else { // 10 bit hash code in status word int hashCode = VM_Magic.getWordAtOffset(o, STATUS_OFFSET).and(HASH_CODE_MASK).rshl(HASH_CODE_SHIFT).toInt(); if (hashCode != 0) { return hashCode; } return installHashCode(o); } } /** Install a new hashcode (only used if !ADDRESS_BASED_HASHING) */ @NoInline protected static int installHashCode(Object o) { Word hashCode; do { hashCodeGenerator = hashCodeGenerator.plus(Word.one().lsh(HASH_CODE_SHIFT)); hashCode = hashCodeGenerator.and(HASH_CODE_MASK); } while (hashCode.isZero()); while (true) { Word statusWord = VM_Magic.prepareWord(o, STATUS_OFFSET); if (!(statusWord.and(HASH_CODE_MASK).isZero())) // some other thread installed a hashcode { return statusWord.and(HASH_CODE_MASK).rshl(HASH_CODE_SHIFT).toInt(); } if (VM_Magic.attemptWord(o, STATUS_OFFSET, statusWord, statusWord.or(hashCode))) { return hashCode.rshl(HASH_CODE_SHIFT).toInt(); // we installed the hash code } } } /** * Get the offset of the thin lock word in this object */ public static Offset getThinLockOffset(Object o) { return STATUS_OFFSET; } /** * what is the default offset for a thin lock? */ public static Offset defaultThinLockOffset() { return STATUS_OFFSET; } /** * 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) { // nothing to do (all objects have thin locks in this object model); } /** * Generic lock */ public static void genericLock(Object o) { VM_ThinLock.lock(o, STATUS_OFFSET); } /** * Generic unlock */ public static void genericUnlock(Object o) { VM_ThinLock.unlock(o, STATUS_OFFSET); } /** * @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_ThinLock.holdsLock(obj, STATUS_OFFSET, 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_ThinLock.getHeavyLock(o, STATUS_OFFSET, create); } /** * Non-atomic read of word containing available bits */ @NoSubArchCompile public static Word readAvailableBitsWord(Object o) { return VM_Magic.getWordAtOffset(o, STATUS_OFFSET); } /** * Non-atomic read of byte containing available bits */ @NoSubArchCompile public static byte readAvailableByte(Object o) { return VM_Magic.getByteAtOffset(o, AVAILABLE_BITS_OFFSET); } /** * Non-atomic write of word containing available bits */ @NoSubArchCompile public static void writeAvailableBitsWord(Object o, Word val) { VM_Magic.setWordAtOffset(o, STATUS_OFFSET, val); } /** * Non-atomic write of word containing available bits */ @Interruptible @NoSubArchCompile public static void writeAvailableBitsWord(BootImageInterface bootImage, Address ref, Word val) { bootImage.setAddressWord(ref.plus(STATUS_OFFSET), val, false); } /** * Non-atomic write of byte containing available bits */ @NoSubArchCompile public static void writeAvailableByte(Object o, byte val) { VM_Magic.setByteAtOffset(o, AVAILABLE_BITS_OFFSET, val); } /** * Non-atomic write of byte containing available bits */ @Interruptible @NoSubArchCompile public static void writeAvailableByteBootImage(BootImageInterface bootImage, Address objectRef, byte val) { bootImage.setByte(objectRef.plus(AVAILABLE_BITS_OFFSET), val); } /** * Return true if argument bit is 1, false if it is 0 */ @NoSubArchCompile public static boolean testAvailableBit(Object o, int idx) { Word mask = Word.fromIntSignExtend(1 << idx); Word status = VM_Magic.getWordAtOffset(o, STATUS_OFFSET); return mask.and(status).NE(Word.zero()); } /** * Set argument bit to 1 if value is true, 0 if value is false */ @NoSubArchCompile public static void setAvailableBit(Object o, int idx, boolean flag) { Word status = VM_Magic.getWordAtOffset(o, STATUS_OFFSET); if (flag) { Word mask = Word.fromIntSignExtend(1 << idx); VM_Magic.setWordAtOffset(o, STATUS_OFFSET, status.or(mask)); } else { Word mask = Word.fromIntSignExtend(1 << idx).not(); VM_Magic.setWordAtOffset(o, STATUS_OFFSET, status.and(mask)); } } /** * 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) { if (!ADDRESS_BASED_HASHING) getObjectHashCode(o); } /** * A prepare on the word containing the available bits */ public static Word prepareAvailableBits(Object o) { return VM_Magic.prepareWord(o, STATUS_OFFSET); } /** * An attempt on the word containing the available bits */ public static boolean attemptAvailableBits(Object o, Word oldVal, Word newVal) { return VM_Magic.attemptWord(o, STATUS_OFFSET, 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 regionBaseAddr.plus(OBJECT_REF_OFFSET); } /** * 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 regionHighAddr.plus(OBJECT_REF_OFFSET - SCALAR_HEADER_SIZE); } /** * Compute the header size of an instance of the given type. */ public static int computeScalarHeaderSize(VM_Class type) { return SCALAR_HEADER_SIZE; } /** * Compute the header size of an instance of the given type. */ public static int computeArrayHeaderSize(VM_Array type) { return ARRAY_HEADER_SIZE; } /** * Return the desired aligment of the alignment point returned by * getOffsetForAlignment in instances of the argument VM_Class. * @param t VM_Class instance being created */ public static int getAlignment(VM_Class t) { return t.getAlignment(); } /** * 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 t.getAlignment(); } /** * 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 t.getAlignment(); } /** * 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 t.getAlignment(); } /** * 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) { /* Align the first field - note that this is one word off from the reference. */ return SCALAR_HEADER_SIZE; } /** * 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) { if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) { Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.NE(HASH_STATE_UNHASHED)) { return SCALAR_HEADER_SIZE + HASHCODE_BYTES; } } return SCALAR_HEADER_SIZE; } /** * 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) { /* although array_header_size == object_ref_offset we say this because the whole point is to align the object ref */ return OBJECT_REF_OFFSET; } /** * 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) { /* although array_header_size == object_ref_offset we say this because the whole point is to align the object ref */ if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) { Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK); if (hashState.NE(HASH_STATE_UNHASHED)) { return OBJECT_REF_OFFSET + HASHCODE_BYTES; } } return OBJECT_REF_OFFSET; } /** * Perform any required initialization of the JAVA portion of the header. * @param ptr the raw storage to be initialized * @param tib the TIB of the instance being created * @param size the number of bytes allocated by the GC system for this object. */ public static Object initializeScalarHeader(Address ptr, Object[] tib, int size) { // (TIB set by VM_ObjectModel) Object ref = VM_Magic.addressAsObject(ptr.plus(OBJECT_REF_OFFSET)); return ref; } /** * Perform any required initialization of the JAVA portion of the header. * @param bootImage The bootimage being written * @param ptr The object ref to the storage to be initialized * @param tib The TIB of the instance being created * @param size The number of bytes allocated by the GC system for this object. */ @Interruptible public static Address initializeScalarHeader(BootImageInterface bootImage, Address ptr, Object[] tib, int size) { Address ref = ptr.plus(OBJECT_REF_OFFSET); return ref; } /** * Perform any required initialization of the JAVA portion of the header. * @param ptr the raw storage to be initialized * @param tib the TIB of the instance being created * @param size the number of bytes allocated by the GC system for this object. */ public static Object initializeArrayHeader(Address ptr, Object[] tib, int size) { Object ref = VM_Magic.addressAsObject(ptr.plus(OBJECT_REF_OFFSET)); // (TIB and array length set by VM_ObjectModel) return ref; } /** * Perform any required initialization of the JAVA portion of the header. * XXX This documentation probably needs fixing TODO * * @param bootImage the bootimage being written * @param ptr the object ref to the storage to be initialized * @param tib the TIB of the instance being created * @param size the number of bytes allocated by the GC system for this object. * @return Document ME TODO XXX */ @Interruptible public static Address initializeArrayHeader(BootImageInterface bootImage, Address ptr, Object[] tib, int size) { Address ref = ptr.plus(OBJECT_REF_OFFSET); // (TIB set by BootImageWriter; array length set by VM_ObjectModel) return ref; } /** * 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 */ @NoSubArchCompile public static void dumpHeader(Object ref) { // TIB dumped in VM_ObjectModel VM.sysWrite(" STATUS="); VM.sysWriteHex(VM_Magic.getWordAtOffset(ref, STATUS_OFFSET).toAddress()); } /** * 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 @NoSubArchCompile public static void baselineEmitLoadTIB(VM_AbstractAssembler asm, int dest, int object, boolean forSubArch) { if (forSubArch) { VM_Configuration.subArchHelper.baselineEmitLoadTIB(asm, dest, object, STATUS_OFFSET); } else { VM_Configuration.archHelper.baselineEmitLoadTIB(asm, dest, object, TIB_OFFSET); } } }