/** * Copy numbytes from src to dst. Assumption either the ranges are non overlapping, or src >= dst * + 4. Also, src and dst are 4 byte aligned and numBytes is a multiple of 4. * * @param dst the destination addr * @param src the source addr * @param numBytes the number of bytes top copy */ @Inline public static void aligned32Copy(Address dst, Address src, Offset numBytes) { if (USE_NATIVE && numBytes.sGT(Offset.fromIntSignExtend(NATIVE_THRESHOLD))) { memcopy(dst, src, numBytes.toWord().toExtent()); } else { if (VM.BuildFor64Addr) { Word wordMask = Word.one().lsh(LOG_BYTES_IN_ADDRESS).minus(Word.one()); Word srcAlignment = src.toWord().and(wordMask); if (srcAlignment.EQ(dst.toWord().and(wordMask))) { Offset i = Offset.zero(); if (srcAlignment.EQ(Word.fromIntZeroExtend(BYTES_IN_INT))) { dst.store(src.loadInt(i), i); i = i.plus(BYTES_IN_INT); } Word endAlignment = srcAlignment.plus(numBytes).and(Word.fromIntSignExtend(BYTES_IN_ADDRESS - 1)); numBytes = numBytes.minus(endAlignment.toOffset()); for (; i.sLT(numBytes); i = i.plus(BYTES_IN_ADDRESS)) { dst.store(src.loadWord(i), i); } if (!endAlignment.isZero()) { dst.store(src.loadInt(i), i); } return; } } // normal case: 32 bit or (64 bit not aligned) for (Offset i = Offset.zero(); i.sLT(numBytes); i = i.plus(BYTES_IN_INT)) { dst.store(src.loadInt(i), i); } } }
/** Each instance of this class corresponds to one explicitly managed large object space. */ @Uninterruptible public final class LargeObjectSpace extends BaseLargeObjectSpace { /** * ************************************************************************** * * <p>Class variables */ public static final int LOCAL_GC_BITS_REQUIRED = 2; public static final int GLOBAL_GC_BITS_REQUIRED = 0; private static final Word MARK_BIT = Word.one(); // ...01 private static final Word NURSERY_BIT = Word.fromIntZeroExtend(2); // ...10 private static final Word LOS_BIT_MASK = Word.fromIntZeroExtend(3); // ...11 /** * ************************************************************************** * * <p>Instance variables */ private Word markState; private boolean inNurseryGC; private final Treadmill treadmill; /** * ************************************************************************** * * <p>Initialization */ /** * The caller specifies the region of virtual memory to be used for this space. If this region * conflicts with an existing space, then the constructor will fail. * * @param name The name of this space (used when printing error messages etc) * @param pageBudget The number of pages this space may consume before consulting the plan * @param vmRequest An object describing the virtual memory requested. */ public LargeObjectSpace(String name, int pageBudget, VMRequest vmRequest) { super(name, pageBudget, vmRequest); treadmill = new Treadmill(LOG_BYTES_IN_PAGE, true); markState = Word.zero(); } /** * ************************************************************************** * * <p>Collection */ /** * Prepare for a new collection increment. For the mark-sweep collector we must flip the state of * the mark bit between collections. */ public void prepare(boolean fullHeap) { if (fullHeap) { if (VM.VERIFY_ASSERTIONS) { VM.assertions._assert(treadmill.fromSpaceEmpty()); } markState = MARK_BIT.minus(markState); } treadmill.flip(fullHeap); inNurseryGC = !fullHeap; } /** * A new collection increment has completed. For the mark-sweep collector this means we can * perform the sweep phase. */ public void release(boolean fullHeap) { // sweep the large objects sweepLargePages(true); // sweep the nursery if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(treadmill.nurseryEmpty()); if (fullHeap) sweepLargePages(false); // sweep the mature space } /** Sweep through the large pages, releasing all superpages on the "from space" treadmill. */ private void sweepLargePages(boolean sweepNursery) { while (true) { Address cell = sweepNursery ? treadmill.popNursery() : treadmill.pop(); if (cell.isZero()) break; release(getSuperPage(cell)); } if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(sweepNursery ? treadmill.nurseryEmpty() : treadmill.fromSpaceEmpty()); } /** * Release a group of pages that were allocated together. * * @param first The first page in the group of pages that were allocated together. */ @Inline public void release(Address first) { ((FreeListPageResource) pr).releasePages(first); } /** * ************************************************************************** * * <p>Object processing and tracing */ /** * Trace a reference to an object under a mark sweep collection policy. If the object header is * not already marked, mark the object in either the bitmap or by moving it off the treadmill, and * enqueue the object for subsequent processing. The object is marked as (an atomic) side-effect * of checking whether already marked. * * @param trace The trace being conducted. * @param object The object to be traced. * @return The object (there is no object forwarding in this collector, so we always return the * same object: this could be a void method but for compliance to a more general interface). */ @Inline public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) { boolean nurseryObject = isInNursery(object); if (!inNurseryGC || nurseryObject) { if (testAndMark(object, markState)) { internalMarkObject(object, nurseryObject); trace.processNode(object); } } return object; } /** * @param object The object in question * @return True if this object is known to be live (i.e. it is marked) */ @Inline public boolean isLive(ObjectReference object) { return testMarkBit(object, markState); } /** * An object has been marked (identifiged as live). Large objects are added to the to-space * treadmill, while all other objects will have a mark bit set in the superpage header. * * @param object The object which has been marked. */ @Inline private void internalMarkObject(ObjectReference object, boolean nurseryObject) { Address cell = VM.objectModel.objectStartRef(object); Address node = Treadmill.midPayloadToNode(cell); treadmill.copy(node, nurseryObject); } /** * ************************************************************************** * * <p>Header manipulation */ /** * Perform any required initialization of the GC portion of the header. * * @param object the object ref to the storage to be initialized * @param alloc is this initialization occuring due to (initial) allocation (true) or due to * copying (false)? */ @Inline public void initializeHeader(ObjectReference object, boolean alloc) { Word oldValue = VM.objectModel.readAvailableBitsWord(object); Word newValue = oldValue.and(LOS_BIT_MASK.not()).or(markState); if (alloc) newValue = newValue.or(NURSERY_BIT); if (Plan.NEEDS_LOG_BIT_IN_HEADER) newValue = newValue.or(Plan.UNLOGGED_BIT); VM.objectModel.writeAvailableBitsWord(object, newValue); Address cell = VM.objectModel.objectStartRef(object); treadmill.addToTreadmill(Treadmill.midPayloadToNode(cell), alloc); } /** * Atomically attempt to set the mark bit of an object. Return true if successful, false if the * mark bit was already set. * * @param object The object whose mark bit is to be written * @param value The value to which the mark bit will be set */ @Inline private boolean testAndMark(ObjectReference object, Word value) { Word oldValue, markBit; do { oldValue = VM.objectModel.prepareAvailableBits(object); markBit = oldValue.and(inNurseryGC ? LOS_BIT_MASK : MARK_BIT); if (markBit.EQ(value)) return false; } while (!VM.objectModel.attemptAvailableBits( object, oldValue, oldValue.and(LOS_BIT_MASK.not()).or(value))); return true; } /** * Return true if the mark bit for an object has the given value. * * @param object The object whose mark bit is to be tested * @param value The value against which the mark bit will be tested * @return True if the mark bit for the object has the given value. */ @Inline private boolean testMarkBit(ObjectReference object, Word value) { return VM.objectModel.readAvailableBitsWord(object).and(MARK_BIT).EQ(value); } /** * Return true if the object is in the logical nursery * * @param object The object whose status is to be tested * @return True if the object is in the logical nursery */ @Inline private boolean isInNursery(ObjectReference object) { return VM.objectModel.readAvailableBitsWord(object).and(NURSERY_BIT).EQ(NURSERY_BIT); } /** * Return the size of the per-superpage header required by this system. In this case it is just * the underlying superpage header size. * * @return The size of the per-superpage header required by this system. */ @Inline protected int superPageHeaderSize() { return Treadmill.headerSize(); } /** * Return the size of the per-cell header for cells of a given class size. * * @return The size of the per-cell header for cells of a given class size. */ @Inline protected int cellHeaderSize() { return 0; } /** * This is the treadmill used by the large object space. * * <p>Note that it depends on the specific local in use whether this is being used. * * @return The treadmill associated with this large object space. */ public Treadmill getTreadmill() { return this.treadmill; } }
/** * This class implements tracing for a simple immortal collection policy. Under this policy all that * is required is for the "collector" to propogate marks in a liveness trace. It does not actually * collect. This class does not hold any state, all methods are static. * * <p>$Id: ImmortalSpace.java,v 1.18 2005/01/19 02:49:02 steveb-oss Exp $ * * @author Perry Cheng * @author <a href="http://cs.anu.edu.au/~Steve.Blackburn">Steve Blackburn</a> * @version $Revision: 1.18 $ * @date $Date: 2005/01/19 02:49:02 $ */ public final class ImmortalSpace extends Space implements Constants, Uninterruptible { /** * ************************************************************************** * * <p>Class variables */ static final Word GC_MARK_BIT_MASK = Word.one(); public static Word immortalMarkState = Word.zero(); // when GC off, the initialization value /** * ************************************************************************** * * <p>Initialization */ /** * The caller specifies the region of virtual memory to be used for this space. If this region * conflicts with an existing space, then the constructor will fail. * * @param name The name of this space (used when printing error messages etc) * @param pageBudget The number of pages this space may consume before consulting the plan * @param start The start address of the space in virtual memory * @param bytes The size of the space in virtual memory, in bytes */ public ImmortalSpace(String name, int pageBudget, Address start, Extent bytes) { super(name, false, true, start, bytes); pr = new MonotonePageResource(pageBudget, this, start, extent); } /** * Construct a space of a given number of megabytes in size. * * <p>The caller specifies the amount virtual memory to be used for this space <i>in * megabytes</i>. If there is insufficient address space, then the constructor will fail. * * @param name The name of this space (used when printing error messages etc) * @param pageBudget The number of pages this space may consume before consulting the plan * @param mb The size of the space in virtual memory, in megabytes (MB) */ public ImmortalSpace(String name, int pageBudget, int mb) { super(name, false, true, mb); pr = new MonotonePageResource(pageBudget, this, start, extent); } /** * Construct a space that consumes a given fraction of the available virtual memory. * * <p>The caller specifies the amount virtual memory to be used for this space <i>as a fraction of * the total available</i>. If there is insufficient address space, then the constructor will * fail. * * @param name The name of this space (used when printing error messages etc) * @param pageBudget The number of pages this space may consume before consulting the plan * @param frac The size of the space in virtual memory, as a fraction of all available virtual * memory */ public ImmortalSpace(String name, int pageBudget, float frac) { super(name, false, true, frac); pr = new MonotonePageResource(pageBudget, this, start, extent); } /** * Construct a space that consumes a given number of megabytes of virtual memory, at either the * top or bottom of the available virtual memory. * * <p>The caller specifies the amount virtual memory to be used for this space <i>in * megabytes</i>, and whether it should be at the top or bottom of the available virtual memory. * If the request clashes with existing virtual memory allocations, then the constructor will * fail. * * @param name The name of this space (used when printing error messages etc) * @param pageBudget The number of pages this space may consume before consulting the plan * @param mb The size of the space in virtual memory, in megabytes (MB) * @param top Should this space be at the top (or bottom) of the available virtual memory. */ public ImmortalSpace(String name, int pageBudget, int mb, boolean top) { super(name, false, true, mb, top); pr = new MonotonePageResource(pageBudget, this, start, extent); } /** * Construct a space that consumes a given fraction of the available virtual memory, at either the * top or bottom of the available virtual memory. * * <p>The caller specifies the amount virtual memory to be used for this space <i>as a fraction of * the total available</i>, and whether it should be at the top or bottom of the available virtual * memory. If the request clashes with existing virtual memory allocations, then the constructor * will fail. * * @param name The name of this space (used when printing error messages etc) * @param pageBudget The number of pages this space may consume before consulting the plan * @param frac The size of the space in virtual memory, as a fraction of all available virtual * memory * @param top Should this space be at the top (or bottom) of the available virtual memory. */ public ImmortalSpace(String name, int pageBudget, float frac, boolean top) { super(name, false, true, frac, top); pr = new MonotonePageResource(pageBudget, this, start, extent); } /** * ************************************************************************** * * <p>Object header manipulations */ /** test to see if the mark bit has the given value */ private static boolean testMarkBit(ObjectReference object, Word value) { return !(ObjectModel.readAvailableBitsWord(object).and(value).isZero()); } /** write the given value in the mark bit. */ private static void writeMarkBit(ObjectReference object, Word value) { Word oldValue = ObjectModel.readAvailableBitsWord(object); Word newValue = oldValue.and(GC_MARK_BIT_MASK.not()).or(value); ObjectModel.writeAvailableBitsWord(object, newValue); } /** atomically write the given value in the mark bit. */ private static void atomicWriteMarkBit(ObjectReference object, Word value) { while (true) { Word oldValue = ObjectModel.prepareAvailableBits(object); Word newValue = oldValue.and(GC_MARK_BIT_MASK.not()).or(value); if (ObjectModel.attemptAvailableBits(object, oldValue, newValue)) break; } } /** * Used to mark boot image objects during a parallel scan of objects during GC Returns true if * marking was done. */ private static boolean testAndMark(ObjectReference object, Word value) throws InlinePragma { Word oldValue; do { oldValue = ObjectModel.prepareAvailableBits(object); Word markBit = oldValue.and(GC_MARK_BIT_MASK); if (markBit.EQ(value)) return false; } while (!ObjectModel.attemptAvailableBits(object, oldValue, oldValue.xor(GC_MARK_BIT_MASK))); return true; } /** * Trace a reference to an object under an immortal collection policy. If the object is not * already marked, enqueue the object for subsequent processing. The object is marked as (an * atomic) side-effect of checking whether already marked. * * @param object The object to be traced. */ public final ObjectReference traceObject(ObjectReference object) throws InlinePragma { if (testAndMark(object, immortalMarkState)) Plan.enqueue(object); return object; } public static void postAlloc(ObjectReference object) throws InlinePragma { writeMarkBit(object, immortalMarkState); } /** * Prepare for a new collection increment. For the immortal collector we must flip the state of * the mark bit between collections. */ public void prepare() { immortalMarkState = GC_MARK_BIT_MASK.sub(immortalMarkState); } public void release() {} /** * Release an allocated page or pages. In this case we do nothing because we only release pages * enmasse. * * @param start The address of the start of the page or pages */ public final void release(Address start) throws InlinePragma { Assert._assert(false); // this policy only releases pages enmasse } public final boolean isLive(ObjectReference object) throws InlinePragma { return true; } /** * Returns if the object in question is currently thought to be reachable. This is done by * comparing the mark bit to the current mark state. For the immortal collector reachable and live * are different, making this method necessary. * * @param object The address of an object in immortal space to test * @return True if <code>ref</code> may be a reachable object (e.g., having the current mark * state). While all immortal objects are live, some may be unreachable. */ public static boolean isReachable(ObjectReference object) { return (ObjectModel.readAvailableBitsWord(object).and(GC_MARK_BIT_MASK).EQ(immortalMarkState)); } }