/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.objectmodel;
import static org.jikesrvm.objectmodel.JavaHeaderConstants.ADDRESS_BASED_HASHING;
import static org.jikesrvm.objectmodel.JavaHeaderConstants.ARRAY_LENGTH_OFFSET;
import static org.jikesrvm.objectmodel.JavaHeaderConstants.HASHCODE_BYTES;
import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.RVMArray;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.RVMType;
import org.jikesrvm.mm.mminterface.AlignmentEncoding;
import org.jikesrvm.mm.mminterface.MemoryManager;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.scheduler.Lock;
import org.jikesrvm.scheduler.RVMThread;
import org.vmmagic.pragma.Entrypoint;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Interruptible;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.pragma.Unpreemptible;
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 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 MemoryManager}. This portion
* of the object supports allocator-specific requirements such as
* mark/barrier bits, reference counts, etc.
* <li> The MiscHeader defined by {@link 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>
* <p>
* 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 bits 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 the key invariant that all elements of the header are
* available at the same offset from an objref for both arrays and
* scalar objects.<p>
*
* 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.<p>
*
* 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 JavaHeader
* @see MiscHeader
* @see MemoryManager
*/
@Uninterruptible
public class ObjectModel {
/** 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 FieldLayout layout;
static {
if (PACKED) {
layout = new FieldLayoutPacked(true, true);
} else {
layout = new FieldLayoutUnpacked(true, true);
}
}
/**
* Layout the instance fields declared in this class.
* @param klass the class to layout
*/
@Interruptible
public static void layoutInstanceFields(RVMClass klass) {
layout.layoutInstanceFields(klass);
}
/**
* Given a reference, return an address which is guaranteed to be inside
* the memory region allocated to the object.
*
* @param ref an object
* @return an address that's inside the memory region allocated to the
* object
*/
public static Address getPointerInMemoryRegion(ObjectReference ref) {
return 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;
}
public static TIB getTIB(ObjectReference ptr) {
return getTIB(ptr.toObject());
}
public static TIB getTIB(Object o) {
return JavaHeader.getTIB(o);
}
public static void setTIB(ObjectReference ptr, TIB tib) {
setTIB(ptr.toObject(), tib);
}
public static void setTIB(Object ref, TIB tib) {
JavaHeader.setTIB(ref, tib);
}
/**
* Sets the TIB for an object during bootimage writing.
*
* @param bootImage the bootimage
* @param refAddress the object's address
* @param tibAddr the TIB's address
* @param type the object's type
*/
@Interruptible
public static void setTIB(BootImageInterface bootImage, Address refAddress, Address tibAddr, RVMType type) {
JavaHeader.setTIB(bootImage, refAddress, tibAddr, type);
}
/**
* Get the pointer just past an object.
*
* @param obj the object in question
* @return first word after the object
*/
public static Address getObjectEndAddress(Object obj) {
TIB tib = getTIB(obj);
RVMType type = tib.getType();
if (type.isClassType()) {
return getObjectEndAddress(obj, type.asClass());
} else {
int numElements = Magic.getArrayLength(obj);
return getObjectEndAddress(obj, type.asArray(), numElements);
}
}
/**
* Gets the pointer just past an object.
*
* @param object the object in question
* @param type the object's class
* @return first word after the scalar object
*/
public static Address getObjectEndAddress(Object object, RVMClass type) {
return JavaHeader.getObjectEndAddress(object, type);
}
/**
* Gets the pointer just past an object.
*
* @param object the object in question
* @param type the object's class
* @param elements the array's length
* @return the first word after the array
*/
public static Address getObjectEndAddress(Object object, RVMArray type, int elements) {
return JavaHeader.getObjectEndAddress(object, type, elements);
}
/**
* Get an object reference from the address the lowest word of the object was allocated.
*
* @param start the lowest word in the storage of an allocated object
* @return the object reference for the object
*/
public static ObjectReference getObjectFromStartAddress(Address start) {
return JavaHeader.getObjectFromStartAddress(start);
}
/**
* Gets an object reference from the address the lowest word of the object was allocated.
*
* @param start the lowest word in the storage of an allocated object
* @return the object reference for the object
*/
public static ObjectReference getScalarFromStartAddress(Address start) {
return JavaHeader.getScalarFromStartAddress(start);
}
/**
* Gets an object reference from the address the lowest word of the object was allocated.
*
* @param start the lowest word in the storage of an allocated object
* @return the object reference for the object
*/
public static ObjectReference getArrayFromStartAddress(Address start) {
return JavaHeader.getArrayFromStartAddress(start);
}
/**
* @param obj an object
* @return the next object in the heap under contiguous allocation
*/
public static ObjectReference getNextObject(ObjectReference obj) {
TIB tib = getTIB(obj);
RVMType type = tib.getType();
if (type.isClassType()) {
return getNextObject(obj, type.asClass());
} else {
int numElements = Magic.getArrayLength(obj);
return getNextObject(obj, type.asArray(), numElements);
}
}
/**
* Gets the next object after this scalar under contiguous allocation.
*
* @param obj the current object, which must be a scalar
* @param type the object's type
* @return the next scalar object in the heap
*/
public static ObjectReference getNextObject(ObjectReference obj, RVMClass type) {
return JavaHeader.getNextObject(obj, type);
}
/**
* Get the next object after this array under contiguous allocation.
*
* @param obj the current object, which must be an array
* @param type the object's type
* @param numElements the length of the array
* @return the next scalar object in the heap
*/
public static ObjectReference getNextObject(ObjectReference obj, RVMArray type, int numElements) {
return JavaHeader.getNextObject(obj, type, numElements);
}
/**
* Gets the reference of an object after copying to a specified region.
*
* @param obj the object to copy
* @param to the target address for the copy
* @return the reference of the copy
*/
public static Object getReferenceWhenCopiedTo(Object obj, Address to) {
TIB tib = getTIB(obj);
RVMType type = tib.getType();
if (type.isClassType()) {
return getReferenceWhenCopiedTo(obj, to, type.asClass());
} else {
return getReferenceWhenCopiedTo(obj, to, type.asArray());
}
}
/**
* @param obj an object
* @return the number of bytes used by the object
*/
public static int bytesUsed(Object obj) {
TIB tib = getTIB(obj);
RVMType type = tib.getType();
if (type.isClassType()) {
return bytesUsed(obj, type.asClass());
} else {
int numElements = Magic.getArrayLength(obj);
return bytesUsed(obj, type.asArray(), numElements);
}
}
/**
* how many bytes are used by the scalar?
*
* @param obj an object
* @param type the object's type
* @return the number of bytes used by the object
*/
public static int bytesUsed(Object obj, RVMClass type) {
return JavaHeader.bytesUsed(obj, type);
}
/**
* how many bytes are used by the array?
*
* @param obj an object
* @param type the object's type
* @param numElements the array's length
* @return the number of bytes used by the object
*/
public static int bytesUsed(Object obj, RVMArray type, int numElements) {
return JavaHeader.bytesUsed(obj, type, numElements);
}
/**
* @param obj the object
* @return number of bytes that are required when the object is copied by GC
*/
public static int bytesRequiredWhenCopied(Object obj) {
TIB tib = getTIB(obj);
RVMType type = tib.getType();
if (type.isClassType()) {
return bytesRequiredWhenCopied(obj, type.asClass());
} else {
int numElements = Magic.getArrayLength(obj);
return bytesRequiredWhenCopied(obj, type.asArray(), numElements);
}
}
/**
* how many bytes are needed when the scalar object is copied by GC?
*
* @param fromObj the object to copy
* @param type the object's type
* @return number of needed bytes when the scalar object is copied by GC
*/
public static int bytesRequiredWhenCopied(Object fromObj, RVMClass type) {
return JavaHeader.bytesRequiredWhenCopied(fromObj, type);
}
/**
* how many bytes are needed when the array object is copied by GC?
*
* @param fromObj the object to copy
* @param type the object's type
* @param numElements the number of elements in the array
* @return the number of bytes that are required for the copy
*/
public static int bytesRequiredWhenCopied(Object fromObj, RVMArray type, int numElements) {
return JavaHeader.bytesRequiredWhenCopied(fromObj, type, numElements);
}
/**
* Maps from the object ref to the lowest address of the storage
* associated with the object.
*
* @param obj the object reference
* @return the lowest address in the object's memory region
*/
@Inline
public static Address objectStartRef(ObjectReference obj) {
return JavaHeader.objectStartRef(obj);
}
/**
* Get the reference of an object after copying to a specified region.
*
* @param obj the object to copy
* @param region the target address for the copy
* @param type the scalar's type
* @return the reference of the copy
*/
public static Object getReferenceWhenCopiedTo(Object obj, Address region, RVMClass type) {
return JavaHeader.getReferenceWhenCopiedTo(obj, region, type);
}
/**
* Get the reference of an object after copying to a specified region.
*
* @param obj the object to copy
* @param region the target address for the copy
* @param type the array's type
* @return the reference of the copy
*/
public static Object getReferenceWhenCopiedTo(Object obj, Address region, RVMArray type) {
return JavaHeader.getReferenceWhenCopiedTo(obj, region, type);
}
/**
* Copies a scalar object to the given raw storage address.
*
* @param fromObj the scalar to copy
* @param toObj target address for copy
* @param numBytes how many bytes to copy
* @param type the scalar's type
* @return the reference for the object's copy
*/
public static Object moveObject(Object fromObj, Object toObj, int numBytes, RVMClass type) {
return JavaHeader.moveObject(fromObj, toObj, numBytes, type);
}
/**
* Copy an array object to the given raw storage address.
*
* @param fromObj the object to copy
* @param toObj the target object
* @param numBytes the number of bytes to copy
* @param type the array's type
* @return the reference for the array's copy
*/
public static Object moveObject(Object fromObj, Object toObj, int numBytes, RVMArray type) {
return JavaHeader.moveObject(fromObj, toObj, numBytes, type);
}
/**
* Copy a scalar object to the given raw storage address.
*
* @param toAddress the target address
* @param fromObj the object to copy
* @param numBytes how many bytes to copy
* @param type the scalar's type
* @return the reference for the object's copy
*/
public static Object moveObject(Address toAddress, Object fromObj, int numBytes, RVMClass type) {
return JavaHeader.moveObject(toAddress, fromObj, numBytes, type);
}
/**
* Copy an array object to the given raw storage address
*
* @param toAddress the target address
* @param fromObj the object to copy
* @param numBytes how many bytes to copy
* @param type the array's type
* @return the reference for the object's copy
*/
public static Object moveObject(Address toAddress, Object fromObj, int numBytes, RVMArray type) {
return JavaHeader.moveObject(toAddress, fromObj, numBytes, type);
}
/**
* @param o an object
* @return the type of an object
*/
public static RVMType getObjectType(Object o) {
return Magic.getObjectType(o);
}
/**
* @param o an array
* @return the length of an array
*/
public static int getArrayLength(Object o) {
return Magic.getIntAtOffset(o, getArrayLengthOffset());
}
/**
* Sets the length of an array.
*
* @param o an array
* @param len the length of the array
*/
public static void setArrayLength(Object o, int len) {
Magic.setIntAtOffset(o, getArrayLengthOffset(), len);
}
@Interruptible
public static int getObjectHashCode(Object o) {
if (HASH_STATS) hashRequests++;
return JavaHeader.getObjectHashCode(o);
}
public static Offset getThinLockOffset(Object o) {
return JavaHeader.getThinLockOffset(o);
}
public static Offset defaultThinLockOffset() {
return JavaHeader.defaultThinLockOffset();
}
/**
* Allocates a thin lock word for instances of the type
* (if they already have one, then has no effect).
*
* @param t the type that is supposed to receive a thin
* lock word
*/
public static void allocateThinLock(RVMType t) {
JavaHeader.allocateThinLock(t);
}
@Entrypoint
@Unpreemptible("Become another thread when lock is contended, don't preempt in other cases")
public static void genericLock(Object o) {
JavaHeader.genericLock(o);
}
@Entrypoint
@Unpreemptible("No preemption normally, but may raise exceptions")
public static void genericUnlock(Object o) {
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, RVMThread thread) {
return 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)
*/
@Unpreemptible("May be interrupted for allocations of locks")
public static Lock getHeavyLock(Object o, boolean create) {
return JavaHeader.getHeavyLock(o, create);
}
/**
* Non-atomic read of word containing available bits
*
* @param o the object to read
* @return the available bits word
*/
public static Word readAvailableBitsWord(Object o) {
return JavaHeader.readAvailableBitsWord(o);
}
/**
* Non-atomic read of byte containing available bits
* @param o the object to read
* @return the available bits bytes
*/
public static byte readAvailableByte(Object o) {
return JavaHeader.readAvailableByte(o);
}
/**
* Non-atomic write of word containing available bits.
*
* @param o the object whose word will be written
* @param val the available bits word
*/
public static void writeAvailableBitsWord(Object o, Word val) {
JavaHeader.writeAvailableBitsWord(o, val);
}
/**
* Non-atomic write of byte containing available bits
*
* @param o the object whose available byte will be written
* @param val the value to write to the available byte
*/
public static void writeAvailableByte(Object o, byte val) {
JavaHeader.writeAvailableByte(o, val);
}
/**
* @param o the object whose bit will be tested
* @param idx the index in the bits
* @return {@code true} if argument bit is 1, {@code false} if it is 0
*/
public static boolean testAvailableBit(Object o, int idx) {
return JavaHeader.testAvailableBit(o, idx);
}
/**
* Sets argument bit to 1 if value is true, 0 if value is false
*
* @param o the object whose bit will be set
* @param idx the index in the bits
* @param flag {@code true} for 1, {@code false} for 0
*/
public static void setAvailableBit(Object o, int idx, boolean flag) {
JavaHeader.setAvailableBit(o, idx, flag);
}
/**
* Freezes the other bits in the byte containing the available bits
* so that it is safe to update them using setAvailableBits.
*
* @param o the object whose available bytes will be initialized
*/
@Interruptible
public static void initializeAvailableByte(Object o) {
JavaHeader.initializeAvailableByte(o);
}
/**
* A prepare on the word containing the available bits.
* <p>
* Note: this method is intended to be used in conjunction
* with the attempt method.
*
* @param o the object which has the available bits
* @return the current value of the word
* @see #attemptAvailableBits(Object, Word, Word)
*/
public static Word prepareAvailableBits(Object o) {
return JavaHeader.prepareAvailableBits(o);
}
/**
* An attempt on the word containing the available bits.
* <p>
* Note: this method is intended to be used in conjunction
* with the prepare method. If the method returns {@code false},
* callers must update their information about the old value of
* the available bits word before retrying again.
*
* @param o the object which has the available bits
* @param oldVal the old value that the word is expected to have
* @param newVal the new value that will be written, if possible
* @return whether the write occurred
*/
public static boolean attemptAvailableBits(Object o, Word oldVal, Word newVal) {
return 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.
*
* @param regionBaseAddr the smallest base address in the region
* @return the smallest address in the region that could possibly
* refer to an object in the region
*/
public static Address minimumObjectRef(Address regionBaseAddr) {
return 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.
*
* @param regionHighAddr the highest base address in the region
* @return the largest address in the region that could possibly
* refer to an object in the region
*/
public static Address maximumObjectRef(Address regionHighAddr) {
return JavaHeader.maximumObjectRef(regionHighAddr);
}
/**
* Computes the header size of an instance of the given type.
*
* @param type the instance's type
* @return size of the head in bytes
*/
@Inline
public static int computeHeaderSize(RVMType type) {
if (type.isArrayType()) {
return computeArrayHeaderSize(type.asArray());
} else {
return computeScalarHeaderSize(type.asClass());
}
}
/**
* Computes the header size of an object.
*
* @param ref the object whose header size is of interest
* @return the object's header size
*/
@Interruptible
public static int computeHeaderSize(Object ref) {
return computeHeaderSize(getObjectType(ref));
}
/**
* Computes the header size of an instance of the given type.
*
* @param type the instance's type
* @return size of the head in bytes
*/
@Inline
public static int computeScalarHeaderSize(RVMClass type) {
return JavaHeader.computeScalarHeaderSize(type);
}
/**
* Computes the header size of an instance of the given type.
*
* @param type the instance's type
* @return size of the head in bytes
*/
public static int computeArrayHeaderSize(RVMArray type) {
return JavaHeader.computeArrayHeaderSize(type);
}
/**
* Given a TIB, compute the header size of an instance of the TIB's class.
*
* @param tib a TIB
* @return the header size of an object from the class given by the TIB
*/
public static int computeHeaderSize(Object[] tib) {
return computeHeaderSize(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?
*
* @return offset of the last word of the header from an
* out-to-in perspective
*/
public static int getHeaderEndOffset() {
return JavaHeader.getHeaderEndOffset();
}
/**
* For a reference to an object, what is the offset in bytes to the bottom
* word of the object?
*
* @param t the class of the object
* @return offset of the first word of the class from the object
* reference
*/
public static int objectStartOffset(RVMClass t) {
return JavaHeader.objectStartOffset(t);
}
/**
* @param t RVMClass instance being created
* @return the desired alignment of the alignment point returned by
* getOffsetForAlignment in instances of the argument RVMClass.
*/
public static int getAlignment(RVMClass t) {
return JavaHeader.getAlignment(t);
}
/**
* @param t RVMClass instance being copied
* @param obj the object being copied
* @return the desired alignment of the alignment point returned by
* getOffsetForAlignment in instances of the argument RVMClass.
*/
public static int getAlignment(RVMClass t, Object obj) {
return JavaHeader.getAlignment(t, obj);
}
/**
* @param t RVMArray instance being created
* @return the desired alignment of the alignment point returned by
* getOffsetForAlignment in instances of the argument RVMArray.
*/
public static int getAlignment(RVMArray t) {
return JavaHeader.getAlignment(t);
}
/**
* @param t RVMArray instance being copied
* @param obj the object being copied
* @return the desired alignment of the alignment point returned by
* getOffsetForAlignment in instances of the argument RVMArray.
*/
public static int getAlignment(RVMArray t, Object obj) {
return JavaHeader.getAlignment(t, obj);
}
/**
* @param t RVMClass instance being created
* @param needsIdentityHash TODO document this parameter. IIs it still needed?
* It's never set to true.
* @return the offset relative to physical beginning of object
* that must be aligned.
*/
public static int getOffsetForAlignment(RVMClass t, boolean needsIdentityHash) {
return JavaHeader.getOffsetForAlignment(t, needsIdentityHash);
}
/**
* @param t RVMClass instance being copied
* @param obj the object being copied
* @return the offset relative to physical beginning of object
* that must be aligned.
*/
public static int getOffsetForAlignment(RVMClass t, ObjectReference obj) {
return JavaHeader.getOffsetForAlignment(t, obj);
}
/**
* @param t RVMArray instance being created
* @param needsIdentityHash TODO document this parameter. Is it still needed?
* It's never set to true.
* @return the offset relative to physical beginning of object that must
* be aligned.
*/
public static int getOffsetForAlignment(RVMArray t, boolean needsIdentityHash) {
return JavaHeader.getOffsetForAlignment(t, needsIdentityHash);
}
/**
* @param t RVMArray instance being copied
* @param obj the object being copied
* @return the offset relative to physical beginning of object that must
* be aligned.
*/
public static int getOffsetForAlignment(RVMArray t, ObjectReference obj) {
return 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.
* @return the object whose storage was initialized
*/
@Inline
public static Object initializeScalar(Address ptr, TIB tib, int size) {
Object ref = JavaHeader.initializeScalarHeader(ptr, tib, size);
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 RVMClass object of the instance to create.
* @param needsIdentityHash needs an identity hash value
* @param identityHashValue the value for the identity hash
* @return the offset of object in bootimage (in bytes)
*/
@Interruptible
public static Address allocateScalar(BootImageInterface bootImage, RVMClass klass, boolean needsIdentityHash, int identityHashValue) {
TIB tib = klass.getTypeInformationBlock();
int size = klass.getInstanceSize();
if (needsIdentityHash) {
if (ADDRESS_BASED_HASHING) {
size += HASHCODE_BYTES;
} else {
// TODO: support rehashing or header initialisation for object models
// that don't support an extra word for the hash code
throw new Error("Unsupported allocation");
}
}
int align = getAlignment(klass);
int offset = getOffsetForAlignment(klass, needsIdentityHash);
Address ptr = bootImage.allocateDataStorage(size, align, offset);
Address ref = JavaHeader.initializeScalarHeader(bootImage, ptr, tib, size, needsIdentityHash, identityHashValue);
MemoryManager.initializeHeader(bootImage, ref, tib, size, true);
MiscHeader.initializeHeader(bootImage, ref, tib, size, true);
return ref;
}
/**
* Fills an alignment gap with the alignment value
*
* @param bootImage the bootimage being compiled
* @param address the start address for the gap that needs to be filled
* @param size the size of the gap to be filled
*/
@Interruptible
public static void fillAlignmentGap(BootImageInterface bootImage, Address address, Extent size) {
while (size.GT(Extent.zero())) {
bootImage.setFullWord(address, 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.
* @return the array whose header was initialized
*/
@Inline
public static Object initializeArray(Address ptr, TIB tib, int numElems, int size) {
Object ref = JavaHeader.initializeArrayHeader(ptr, tib, size);
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 RVMArray object of array being allocated.
* @param numElements number of elements
* @param needsIdentityHash needs an identity hash value
* @param identityHashValue the value for the identity hash
* @param alignCode TODO
* @return Address of object in bootimage (in bytes)
*/
@Interruptible
public static Address allocateArray(BootImageInterface bootImage, RVMArray array, int numElements, boolean needsIdentityHash, int identityHashValue, int alignCode) {
int align = getAlignment(array);
return allocateArray(bootImage, array, numElements, needsIdentityHash, identityHashValue, align, alignCode);
}
/**
* 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 RVMArray object of array being allocated.
* @param numElements number of elements
* @param needsIdentityHash needs an identity hash value
* @param identityHashValue the value for the identity hash
* @param align special alignment value
* @param alignCode the alignment-encoded value
* @return Address of object in bootimage (in bytes)
*/
@Interruptible
public static Address allocateArray(BootImageInterface bootImage, RVMArray array, int numElements, boolean needsIdentityHash, int identityHashValue, int align, int alignCode) {
TIB tib = array.getTypeInformationBlock();
int size = array.getInstanceSize(numElements);
if (needsIdentityHash) {
if (ADDRESS_BASED_HASHING) {
size += HASHCODE_BYTES;
} else {
// TODO: support rehashing or header initialisation for object models
// that don't support an extra word for the hash code
throw new Error("Unsupported allocation");
}
}
int offset = getOffsetForAlignment(array, needsIdentityHash);
int padding = AlignmentEncoding.padding(alignCode);
Address ptr = bootImage.allocateDataStorage(size + padding, align, offset);
ptr = AlignmentEncoding.adjustRegion(alignCode, ptr);
Address ref = JavaHeader.initializeArrayHeader(bootImage, ptr, tib, size, numElements, needsIdentityHash, identityHashValue);
bootImage.setFullWord(ref.plus(getArrayLengthOffset()), numElements);
MemoryManager.initializeHeader(bootImage, ref, tib, size, false);
MiscHeader.initializeHeader(bootImage, ref, tib, size, 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 RVMArray object of array being allocated.
* @param numElements number of elements
* @return Address of object in bootimage
*/
@Interruptible
public static Address allocateCode(BootImageInterface bootImage, RVMArray array, int numElements) {
TIB tib = array.getTypeInformationBlock();
int size = array.getInstanceSize(numElements);
int align = getAlignment(array);
int offset = getOffsetForAlignment(array, false);
Address ptr = bootImage.allocateCodeStorage(size, align, offset);
Address ref = JavaHeader.initializeArrayHeader(bootImage, ptr, tib, size, numElements, false, 0);
bootImage.setFullWord(ref.plus(getArrayLengthOffset()), numElements);
MemoryManager.initializeHeader(bootImage, ref, tib, size, false);
MiscHeader.initializeHeader(bootImage, ref, tib, size, 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(Magic.objectAsAddress(getTIB(ref)));
JavaHeader.dumpHeader(ref);
MiscHeader.dumpHeader(ref);
}
/**
* For debugging: dumps descriptor of an object.
*
* @param addr the object to dump
*/
public static void describeObject(ObjectReference addr) {
Object obj = addr.toObject();
RVMType type = Magic.getObjectType(obj);
VM.sysWrite(type.getDescriptor());
}
}