Esempio n. 1
0
 /**
  * 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);
     }
   }
 }
Esempio n. 2
0
/** 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;
  }
}
Esempio n. 3
0
/**
 * 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));
  }
}