[vmkit-commits] [vmkit] r75904 [2/2] - in /vmkit/trunk/mmtk: ./ java/ java/src/ java/src/org/ java/src/org/j3/ java/src/org/j3/config/ java/src/org/j3/mmtk/ java/src/org/j3/options/ java/src/org/j3/runtime/ java/src/org/jikesrvm/ java/src/org/mmtk/ java/src/org/mmtk/plan/ java/src/org/mmtk/plan/copyms/ java/src/org/mmtk/plan/generational/ java/src/org/mmtk/plan/generational/copying/ java/src/org/mmtk/plan/generational/immix/ java/src/org/mmtk/plan/generational/marksweep/ java/src/org/mmtk/plan/immix/ java/src/org/mmtk/p...

Nicolas Geoffray nicolas.geoffray at lip6.fr
Thu Jul 16 04:26:41 PDT 2009


Added: vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ImmixSpace.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ImmixSpace.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ImmixSpace.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ImmixSpace.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,756 @@
+/*
+ *  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.mmtk.policy.immix;
+
+import static org.mmtk.policy.immix.ImmixConstants.*;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.plan.TransitiveClosure;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.heap.*;
+import org.mmtk.utility.options.LineReuseRatio;
+import org.mmtk.utility.options.Options;
+import org.mmtk.utility.Constants;
+import org.mmtk.utility.Log;
+
+import org.mmtk.vm.Lock;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * Each instance of this class corresponds to one immix *space*.
+ * Each of the instance methods of this class may be called by any
+ * thread (i.e. synchronization must be explicit in any instance or
+ * class method).  This contrasts with the SquishLocal, where
+ * instances correspond to *plan* instances and therefore to kernel
+ * threads.  Thus unlike this class, synchronization is not necessary
+ * in the instance methods of SquishLocal.
+ *
+ */
+ at Uninterruptible
+public final class ImmixSpace extends Space implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+  private static short reusableMarkStateThreshold = 0;
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private Word markState = ObjectHeader.MARK_BASE_VALUE;
+          byte lineMarkState = RESET_LINE_MARK_STATE;
+  private byte lineUnavailState = RESET_LINE_MARK_STATE;
+  private boolean inCollection;
+  private int linesConsumed = 0;
+
+  private Lock mutatorLock = VM.newLock(getName()+"mutator");
+  private Lock gcLock = VM.newLock(getName()+"gc");
+
+  private Address allocBlockCursor = Address.zero();
+  private Address allocBlockSentinel = Address.zero();
+  private boolean exhaustedReusableSpace = true;
+
+  private final ChunkList chunkMap = new ChunkList();
+  private final Defrag defrag;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  static {
+    Options.lineReuseRatio = new LineReuseRatio();
+    reusableMarkStateThreshold = (short) (Options.lineReuseRatio.getValue() * MAX_BLOCK_MARK_STATE);
+  }
+
+  /**
+   * 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 The virtual memory request
+   */
+  public ImmixSpace(String name, int pageBudget, VMRequest vmRequest) {
+    super(name, false, false, vmRequest);
+    if (vmRequest.isDiscontiguous())
+      pr = new FreeListPageResource(pageBudget, this, Chunk.getRequiredMetaDataPages());
+    else
+      pr = new FreeListPageResource(pageBudget, this, start, extent, Chunk.getRequiredMetaDataPages());
+    defrag = new Defrag((FreeListPageResource) pr);
+  }
+
+  /****************************************************************************
+   *
+   * Global prepare and release
+   */
+
+  /**
+   * Prepare for a new collection increment.
+   */
+  public void prepare(boolean majorGC) {
+    if (majorGC) {
+      markState = ObjectHeader.deltaMarkState(markState, true);
+        lineMarkState++;
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(lineMarkState <= MAX_LINE_MARK_STATE);
+    }
+    chunkMap.reset();
+    defrag.prepare(chunkMap, this);
+    inCollection = true;
+
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(VM.activePlan.collectorCount() <= MAX_COLLECTORS);
+  }
+
+  /**
+   * A new collection increment has completed.  Release global resources.
+   * @param majorGC TODO
+   */
+  public boolean release(boolean majorGC) {
+    boolean didDefrag = defrag.inDefrag();
+    if (majorGC) {
+      if (lineMarkState == MAX_LINE_MARK_STATE)
+        lineMarkState = RESET_LINE_MARK_STATE;
+     lineUnavailState = lineMarkState;
+    }
+    chunkMap.reset();
+    defrag.globalRelease();
+    inCollection = false;
+
+    /* set up reusable space */
+    if (allocBlockCursor.isZero()) allocBlockCursor = chunkMap.getHeadChunk();
+    allocBlockSentinel = allocBlockCursor;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isRecycleAllocChunkAligned(allocBlockSentinel));
+    exhaustedReusableSpace = false;
+    if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+      Log.write("gr[allocBlockCursor: "); Log.write(allocBlockCursor); Log.write(" allocBlockSentinel: "); Log.write(allocBlockSentinel); Log.writeln("]");
+    }
+
+    /* really just want this to happen once after options are booted, but no harm in re-doing it */
+    reusableMarkStateThreshold = (short) (Options.lineReuseRatio.getValue() * MAX_BLOCK_MARK_STATE);
+    Defrag.defragReusableMarkStateThreshold = (short) (Options.defragLineReuseRatio.getValue() * MAX_BLOCK_MARK_STATE);
+
+    linesConsumed = 0;
+    return didDefrag;
+  }
+
+  /**
+   * Determine the collection kind.
+   *
+   * @param emergencyCollection Is this collection an emergency (last did not yield enough)?
+   * @param collectWholeHeap Is this a whole heap collection?
+   * @param collectionAttempt Which attempt is this to collect?
+   * @param collectionTrigger What is triggering the collection?
+   */
+  public void decideWhetherToDefrag(boolean emergencyCollection, boolean collectWholeHeap, int collectionAttempt, int collectionTrigger) {
+    defrag.decideWhetherToDefrag(emergencyCollection, collectWholeHeap, collectionAttempt, collectionTrigger, exhaustedReusableSpace);
+  }
+
+ /****************************************************************************
+  *
+  * Collection state access methods
+  */
+
+  /**
+   * Return true if this space is currently being collected.
+   *
+   * @return True if this space is currently being collected.
+   */
+  @Inline
+  public boolean inImmixCollection() {
+    return inCollection;
+  }
+
+  /**
+   * Return true if this space is currently being defraged.
+   *
+   * @return True if this space is currently being defraged.
+   */
+  @Inline
+  public boolean inImmixDefragCollection() {
+    return inCollection && defrag.inDefrag();
+  }
+
+  /**
+   * Return the number of pages allocated since the last collection
+   *
+   * @return The number of pages allocated since the last collection
+   */
+  public int getPagesAllocated() {
+    return linesConsumed>>(LOG_BYTES_IN_PAGE-LOG_BYTES_IN_LINE);
+  }
+
+  /**
+   * Return the reusable mark state threshold, which determines how
+   * eagerly lines should be recycled (by default these values are
+   * set so that all lines are recycled).
+   *
+   * @param forDefrag The query is the context of a defragmenting collection
+   * @return The reusable mark state threshold
+   */
+  @Inline
+  public static short getReusuableMarkStateThreshold(boolean forDefrag) {
+    return forDefrag ? Defrag.defragReusableMarkStateThreshold : reusableMarkStateThreshold;
+  }
+
+  /****************************************************************************
+   *
+   * Allocation
+   */
+
+  /**
+   * Return a pointer to a set of new usable blocks, or null if none are available.
+   * Use different block selection heuristics depending on whether the allocation
+   * request is "hot" or "cold".
+   *
+   * @param hot True if the requesting context is for hot allocations (used for
+   * allocations from high allocation volume sites).
+   * @return The pointer into the alloc table containing usable blocks.
+   */
+  public Address getSpace(boolean hot, boolean copy, int lineUseCount) {
+    Address rtn;
+    if (copy)
+      defrag.getBlock();
+
+    linesConsumed += lineUseCount;
+
+    rtn = acquire(PAGES_IN_BLOCK);
+
+    if (VM.VERIFY_ASSERTIONS) {
+      VM.assertions._assert(Block.isAligned(rtn));
+      VM.assertions._assert(!(copy && Block.isDefragSource(rtn)));
+    }
+
+    if (!rtn.isZero()) {
+      Block.setBlockAsInUse(rtn);
+      Chunk.updateHighWater(rtn);
+      if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+        Log.write("gs["); Log.write(rtn); Log.write(" -> "); Log.write(rtn.plus(BYTES_IN_BLOCK-1)); Log.write(" copy: "); Log.write(copy); Log.writeln("]");
+      }
+    }
+
+    return rtn;
+  }
+
+ /**
+  * This hook is called by page resources each time a space grows.  The space may
+  * tap into the hook to monitor heap growth.  The call is made from within the
+  * page resources' critical region, immediately before yielding the lock.
+  *
+  * @param start The start of the newly allocated space
+  * @param bytes The size of the newly allocated space
+  * @param newChunk True if the new space encroached upon or started a new chunk or chunks.
+  */
+  @Override
+  public void growSpace(Address start, Extent bytes, boolean newChunk) {
+    super.growSpace(start, bytes, newChunk);
+     if (newChunk) {
+      Address chunk = chunkAlign(start.plus(bytes), true);
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(chunkAlign(start.plus(bytes), true).EQ(chunk));
+      Chunk.clearMetaData(chunk);
+      chunkMap.addNewChunkToMap(chunk);
+    }
+  }
+
+  public Address acquireReusableBlocks() {
+    if (VM.VERIFY_ASSERTIONS) {
+      VM.assertions._assert(isRecycleAllocChunkAligned(allocBlockCursor));
+      VM.assertions._assert(isRecycleAllocChunkAligned(allocBlockSentinel));
+    }
+    Address rtn;
+
+    lock();
+    if (exhaustedReusableSpace)
+      rtn = Address.zero();
+    else {
+      rtn = allocBlockCursor;
+      Address lastAllocChunk = chunkAlign(allocBlockCursor, true);
+      allocBlockCursor = allocBlockCursor.plus(BYTES_IN_RECYCLE_ALLOC_CHUNK);
+      if (allocBlockCursor.GT(Chunk.getHighWater(lastAllocChunk)))
+        allocBlockCursor = chunkMap.nextChunk(lastAllocChunk);
+      if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+        Log.write("arb[ rtn: "); Log.write(rtn); Log.write(" allocBlockCursor: "); Log.write(allocBlockCursor); Log.write(" allocBlockSentinel: "); Log.write(allocBlockSentinel); Log.writeln("]");
+      }
+
+      if (allocBlockCursor.isZero() || allocBlockCursor.EQ(allocBlockSentinel)) {
+        exhaustedReusableSpace = true;
+        if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+          Log.writeln("[Reusable space exhausted]");
+        }
+      }
+    }
+    unlock();
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isRecycleAllocChunkAligned(rtn));
+    return rtn;
+  }
+
+  /**
+   * Release a block.  A block is free, so call the underlying page allocator
+   * to release the associated storage.
+   *
+   * @param block The address of the block to be released
+   */
+  @Inline
+  public void release(Address block) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.isAligned(block));
+    Block.setBlockAsUnallocated(block);
+    ((FreeListPageResource) pr).releasePages(block);
+  }
+
+ /**
+  * Release one or more contiguous chunks associated with a discontiguous
+  * space. This hook is called by the page level allocators whenever a
+  * complete discontiguous chunk is released.
+  *
+  * @param chunk THe address of the start of the contiguous chunk or chunks
+  * @return The number of chunks freed
+  */
+  @Override
+  public int releaseDiscontiguousChunks(Address chunk) {
+    chunkMap.removeChunkFromMap(chunk);
+    return super.releaseDiscontiguousChunks(chunk);
+  }
+
+  /****************************************************************************
+  *
+  * Header manipulation
+  */
+
+ /**
+  * Perform any required post allocation initialization
+  *
+  * @param object the object ref to the storage to be initialized
+  */
+  @Inline
+  public void postAlloc(ObjectReference object, int bytes) {
+    if (bytes > BYTES_IN_LINE)
+      ObjectHeader.markAsStraddling(object);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(ObjectHeader.isNewObject(object));
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!ObjectHeader.isForwardedOrBeingForwarded(object));
+  }
+
+ /**
+  * Perform any required post copy (i.e. in-GC allocation) initialization.
+  * This is relevant (for example) when Squish is used as the mature space in
+  * a copying GC.
+  *
+  * @param object the object ref to the storage to be initialized
+ * @param majorGC Is this copy happening during a major gc?
+  */
+  @Inline
+  public void postCopy(ObjectReference object, int bytes, boolean majorGC) {
+    ObjectHeader.writeMarkState(object, markState, bytes > BYTES_IN_LINE);
+    if (!MARK_LINE_AT_SCAN_TIME && majorGC) markLines(object);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!ObjectHeader.isForwardedOrBeingForwarded(object));
+    if (VM.VERIFY_ASSERTIONS && Plan.NEEDS_LOG_BIT_IN_HEADER) VM.assertions._assert(ObjectHeader.isUnloggedObject(object));
+  }
+
+  /****************************************************************************
+   *
+   * Object tracing
+   */
+
+  /**
+   * Trace a reference to an object.  If the object header is not already
+   * marked, mark the object and enqueue it for subsequent processing.
+   *
+   * @param trace The trace performing the transitive closure
+   * @param object The object to be traced.
+   * @param allocator The allocator to which any copying should be directed
+   * @return The object, which may have been moved.
+   */
+  @Inline
+  public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object, int allocator) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(defrag.determined(true));
+
+    ObjectReference rtn = object;
+    if (isDefragSource(object))
+      rtn = traceObjectWithOpportunisticCopy(trace, object, allocator, false);
+    else
+      traceObjectWithoutMoving(trace, object);
+
+    if (VM.VERIFY_ASSERTIONS) {
+      VM.assertions._assert(!rtn.isNull());
+      VM.assertions._assert(defrag.spaceExhausted() || !isDefragSource(rtn) || (ObjectHeader.isPinnedObject(rtn)));
+    }
+    return rtn;
+  }
+
+  /**
+   * Trace a reference to an object in the context of a non-moving collection.  This
+   * call is optimized for the simpler non-moving case.
+   *
+   * @param trace The trace performing the transitive closure
+   * @param object The object to be traced.
+   * @return The object (there is no object forwarding in this
+   * trace method, so we always return the same object: this could be a
+   * void method but for compliance to a more general interface).
+   */
+  @Inline
+  public ObjectReference fastTraceObject(TransitiveClosure trace, ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(defrag.determined(false));
+    traceObjectWithoutMoving(trace, object);
+    return object;
+  }
+
+  /**
+   * Trace a reference to an object during a nursery collection for
+   * a sticky mark bits implementation of immix.  If the object header
+   * is not already marked, mark the object and enqueue it for subsequent
+   * processing.
+   *
+   * @param trace The trace performing the transitive closure
+   * @param object The object to be traced.
+   * @param allocator The allocator to which any copying should be directed
+   * @return Either the object or a forwarded object, depending on
+   * the policy in place.
+   */
+  @Inline
+  public ObjectReference nurseryTraceObject(TransitiveClosure trace, ObjectReference object, int allocator) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!defrag.inDefrag());
+    if (TMP_PREFER_COPY_ON_NURSERY_GC)
+      return traceObjectWithOpportunisticCopy(trace, object, allocator, true);
+    else
+      return fastTraceObject(trace, object);
+  }
+
+  /**
+   * Trace a reference to an object.  This interface is not supported by immix, since
+   * we require the allocator to be identified except for the special case of the fast
+   * trace.
+   *
+   * @param trace The trace performing the transitive closure
+   * @param object The object to be traced.
+   * @return null and fail.
+   */
+  public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) {
+    VM.assertions.fail("unsupported interface");
+    return null;
+  }
+
+  /**
+   * Trace a reference to an object in the context of a non-moving collection.  This
+   * call is optimized for the simpler non-moving case.
+   *
+   * @param trace The trace performing the transitive closure
+   * @param object The object to be traced.
+   */
+  @Inline
+  private void traceObjectWithoutMoving(TransitiveClosure trace, ObjectReference object) {
+    Word markValue = Plan.NEEDS_LOG_BIT_IN_HEADER ? markState.or(ObjectHeader.UNLOGGED_BIT) : markState;
+    Word oldMarkState = ObjectHeader.testAndMark(object, markValue);
+    if (VM.VERIFY_ASSERTIONS)  VM.assertions._assert(!defrag.inDefrag() || defrag.spaceExhausted() || !isDefragSource(object));
+    if (oldMarkState != markValue) {
+      if (!MARK_LINE_AT_SCAN_TIME)
+        markLines(object);
+      trace.processNode(object);
+    }
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!ObjectHeader.isForwardedOrBeingForwarded(object));
+    if (VM.VERIFY_ASSERTIONS  && Plan.NEEDS_LOG_BIT_IN_HEADER) VM.assertions._assert(ObjectHeader.isUnloggedObject(object));
+  }
+
+  /**
+   * Trace a reference to an object, forwarding the object if appropriate
+   * If the object is not already marked, mark the object and enqueue it
+   * for subsequent processing.
+   *
+   * @param trace The trace performing the transitive closure
+   * @param object The object to be traced.
+   * @param allocator The allocator to which any copying should be directed
+   * @return Either the object or a forwarded object, if it was forwarded.
+   */
+  @Inline
+  private ObjectReference traceObjectWithOpportunisticCopy(TransitiveClosure trace, ObjectReference object, int allocator, boolean nurseryCollection) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(nurseryCollection || (defrag.determined(true) && isDefragSource(object)));
+
+    /* now race to be the (potential) forwarder */
+    Word priorForwardingWord = ObjectHeader.attemptToBeForwarder(object);
+    if (ObjectHeader.isForwardedOrBeingForwarded(priorForwardingWord)) {
+      /* We lost the race; the object is either forwarded or being forwarded by another thread. */
+      /* Note that the concurrent attempt to forward the object may fail, so the object may remain in-place */
+      ObjectReference rtn = ObjectHeader.spinAndGetForwardedObject(object, priorForwardingWord);
+      if (VM.VERIFY_ASSERTIONS && rtn == object) VM.assertions._assert((nurseryCollection && ObjectHeader.testMarkState(object, markState)) || defrag.spaceExhausted() || ObjectHeader.isPinnedObject(object));
+      if (VM.VERIFY_ASSERTIONS && rtn != object) VM.assertions._assert(nurseryCollection || !isDefragSource(rtn));
+      if (VM.VERIFY_ASSERTIONS && Plan.NEEDS_LOG_BIT_IN_HEADER) VM.assertions._assert(ObjectHeader.isUnloggedObject(rtn));
+      return rtn;
+    } else {
+      /* the object is unforwarded, either because this is the first thread to reach it, or because the object can't be forwarded */
+      if (ObjectHeader.testMarkState(priorForwardingWord, markState)) {
+        /* the object has not been forwarded, but has the correct mark state; unlock and return unmoved object */
+        /* Note that in a sticky mark bits collector, the mark state does not change at each GC, so correct mark state does not imply another thread got there first */
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(nurseryCollection || defrag.spaceExhausted() || ObjectHeader.isPinnedObject(object));
+        ObjectHeader.setForwardingWordAndEnsureUnlogged(object, priorForwardingWord); // return to uncontested state
+        if (VM.VERIFY_ASSERTIONS && Plan.NEEDS_LOG_BIT_IN_HEADER) VM.assertions._assert(ObjectHeader.isUnloggedObject(object));
+        return object;
+      } else {
+        /* we are the first to reach the object; either mark in place or forward it */
+        ObjectReference newObject;
+        if (ObjectHeader.isPinnedObject(object) || defrag.spaceExhausted()) {
+          /* mark in place */
+          ObjectHeader.setMarkStateUnlogAndUnlock(object, priorForwardingWord, markState);
+          newObject = object;
+          if (VM.VERIFY_ASSERTIONS && Plan.NEEDS_LOG_BIT_IN_HEADER) VM.assertions._assert(ObjectHeader.isUnloggedObject(newObject));
+        } else {
+          /* forward */
+          newObject = ObjectHeader.forwardObject(object, allocator);
+          if (VM.VERIFY_ASSERTIONS && Plan.NEEDS_LOG_BIT_IN_HEADER) VM.assertions._assert(ObjectHeader.isUnloggedObject(newObject));
+        }
+        if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+          Log.write("C["); Log.write(object); Log.write("/");
+          Log.write(getName()); Log.write("] -> ");
+          Log.write(newObject); Log.write("/");
+          Log.write(Space.getSpaceForObject(newObject).getName());
+          Log.writeln("]");
+        }
+        if (!MARK_LINE_AT_SCAN_TIME)
+          markLines(newObject);
+        trace.processNode(newObject);
+        if (VM.VERIFY_ASSERTIONS) {
+          if (!((getSpaceForObject(newObject) != this) ||
+                (newObject == object) ||
+                (nurseryCollection && willNotMoveThisNurseryGC(newObject)) ||
+                (defrag.inDefrag() && willNotMoveThisGC(newObject))
+               )) {
+            Log.write("   object: "); Log.writeln(object);
+            Log.write("newObject: "); Log.writeln(newObject);
+            Log.write("    space: "); Log.writeln(getName());
+            Log.write(" nursery?: "); Log.writeln(nurseryCollection);
+            Log.write("  mature?: "); Log.writeln(ObjectHeader.isMatureObject(object));
+            Log.write("  wnmngc?: "); Log.writeln(willNotMoveThisNurseryGC(newObject));
+            Log.write("  pinned?: "); Log.writeln(ObjectHeader.isPinnedObject(object));
+            Space otherSpace = getSpaceForObject(newObject);
+            Log.write(" space(o): "); Log.writeln(otherSpace == null ? "<NULL>" : otherSpace.getName());
+            VM.assertions._assert(false);
+          }
+        }
+        return newObject;
+      }
+    }
+  }
+
+  /**
+   * Mark the line/s associated with a given object.  This is distinct from the
+   * above tracing code because line marks are stored separately from the
+   * object headers (thus both must be set), and also because we found empirically
+   * that it was more efficient to perform the line mark of the object during
+   * the scan phase (which occurs after the trace phase), presumably because
+   * the latency of the associated memory operations was better hidden in the
+   * context of that code
+   *
+   * @param object The object which is live and for which the associated lines
+   * must be marked.
+   */
+  public void markLines(ObjectReference object) {
+    Address address = VM.objectModel.objectStartRef(object);
+    Line.mark(address, lineMarkState);
+    if (ObjectHeader.isStraddlingObject(object))
+      Line.markMultiLine(address, object, lineMarkState);
+  }
+
+  public int getNextUnavailableLine(Address baseLineAvailAddress, int line) {
+    return Line.getNextUnavailable(baseLineAvailAddress, line, lineUnavailState);
+  }
+
+  public int getNextAvailableLine(Address baseLineAvailAddress, int line) {
+    return Line.getNextAvailable(baseLineAvailAddress, line, lineUnavailState);
+  }
+
+  /****************************************************************************
+  *
+  * Establish available lines
+  */
+
+  /**
+   * Establish the number of recyclable lines lines available for allocation
+   * during defragmentation, populating the spillAvailHistogram, which buckets
+   * available lines according to the number of holes on the block on which
+   * the available lines reside.
+   *
+   * @param spillAvailHistogram A histogram of availability to be populated
+   * @return The number of available recyclable lines
+   */
+  int getAvailableLines(int[] spillAvailHistogram) {
+    int availableLines;
+    if (allocBlockCursor.isZero() || exhaustedReusableSpace) {
+      availableLines = 0;
+    } else {
+      if (allocBlockCursor.EQ(allocBlockSentinel)) {
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!exhaustedReusableSpace);
+        allocBlockCursor = chunkMap.getHeadChunk();
+        allocBlockSentinel = allocBlockCursor;
+      }
+      availableLines = getUsableLinesInRegion(allocBlockCursor, allocBlockSentinel, spillAvailHistogram);
+    }
+    return availableLines;
+  }
+
+  /**
+   * Return the number of lines usable for allocation during defragmentation in the
+   * address range specified by start and end.  Populate a histogram to indicate where
+   * the usable lines reside as a function of block hole count.
+   *
+   * @param start  The start of the region to be checked for availability
+   * @param end The end of the region to be checked for availability
+   * @param spillAvailHistogram The histogram which will be populated
+   * @return The number of usable lines
+   */
+  private int getUsableLinesInRegion(Address start, Address end, int[] spillAvailHistogram) {
+    int usableLines = 0;
+    Address blockCursor = Chunk.isAligned(start) ? start.plus(Chunk.FIRST_USABLE_BLOCK_INDEX<<LOG_BYTES_IN_BLOCK) : start;
+    Address blockStateCursor = Block.getBlockMarkStateAddress(blockCursor);
+    Address chunkCursor = Chunk.align(blockCursor);
+    if (Chunk.getByteOffset(end) < Chunk.FIRST_USABLE_BLOCK_INDEX<<LOG_BYTES_IN_BLOCK)
+      end = Chunk.align(end).plus(Chunk.FIRST_USABLE_BLOCK_INDEX<<LOG_BYTES_IN_BLOCK);
+
+    for (int i = 0; i <= MAX_CONSV_SPILL_COUNT; i++) spillAvailHistogram[i] = 0;
+
+    Address highwater = Chunk.getHighWater(chunkCursor);
+    do {
+      short markState = blockStateCursor.loadShort();
+      if (markState != 0 && markState <= reusableMarkStateThreshold) {
+        int usable = LINES_IN_BLOCK - markState;
+        short bucket = (short) Block.getConservativeSpillCount(blockCursor);
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bucket >= 0 && bucket <= MAX_CONSV_SPILL_COUNT);
+        spillAvailHistogram[bucket] += usable;
+        usableLines += usable;
+      }
+      blockCursor = blockCursor.plus(BYTES_IN_BLOCK);
+      if (blockCursor.GT(highwater)) {
+        chunkCursor = chunkMap.nextChunk(chunkCursor);
+        if (chunkCursor.isZero()) break;
+        blockCursor = chunkCursor.plus(Chunk.FIRST_USABLE_BLOCK_INDEX<<LOG_BYTES_IN_BLOCK);
+        blockStateCursor = Block.getBlockMarkStateAddress(blockCursor);
+        highwater = Chunk.getHighWater(chunkCursor);
+      } else
+        blockStateCursor = blockStateCursor.plus(Block.BYTES_IN_BLOCK_STATE_ENTRY);
+    } while (blockCursor.NE(end));
+
+    return usableLines;
+  }
+
+  /****************************************************************************
+   *
+   * Object state
+   */
+
+  /**
+   * Generic test of the liveness of an 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) {
+    if (defrag.inDefrag() && isDefragSource(object))
+      return ObjectHeader.isForwardedOrBeingForwarded(object) || ObjectHeader.testMarkState(object, markState);
+    else
+      return ObjectHeader.testMarkState(object, markState);
+  }
+
+  /**
+   * Test the liveness of an object during copying sticky mark bits collection
+   *
+   * @param object The object in question
+   * @return True if this object is known to be live (i.e. it is marked)
+   */
+  @Inline
+  public boolean copyNurseryIsLive(ObjectReference object) {
+    return ObjectHeader.isForwardedOrBeingForwarded(object) || ObjectHeader.testMarkState(object, markState);
+  }
+
+  /**
+   * Test the liveness of an object during defragmentation
+   *
+   * @param object The object in question
+   * @return True if this object is known to be live (i.e. it is marked)
+   */
+  @Inline
+  public boolean fastIsLive(ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!defrag.inDefrag());
+    return ObjectHeader.testMarkState(object, markState);
+  }
+
+  @Inline
+  public boolean willNotMoveThisGC(ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSpaceForObject(object) == this && defrag.inDefrag());
+    return ObjectHeader.isPinnedObject(object) || willNotMoveThisGC(VM.objectModel.refToAddress(object));
+  }
+
+  @Inline
+  public boolean willNotMoveThisNurseryGC(ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSpaceForObject(object) == this);
+    return ObjectHeader.isMatureObject(object);
+  }
+
+  @Inline
+  private boolean isDefragSource(ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSpaceForObject(object) == this);
+    return isDefragSource(VM.objectModel.refToAddress(object));
+  }
+
+  @Inline
+  public boolean willNotMoveThisGC(Address address) {
+    return !defrag.inDefrag() || defrag.spaceExhausted() || !isDefragSource(address);
+  }
+
+  @Inline
+  public boolean isDefragSource(Address address) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSpaceForObject(address.toObjectReference()) == this);
+    return Block.isDefragSource(address);
+  }
+
+
+  /****************************************************************************
+   *
+   * Locks
+   */
+
+  /**
+   * Acquire the appropriate lock depending on whether the context is
+   * GC or mutator.
+   */
+  private void lock() {
+    if (inCollection)
+      gcLock.acquire();
+    else
+      mutatorLock.acquire();
+  }
+
+   /**
+    * Release the appropriate lock depending on whether the context is
+    * GC or mutator.
+    */
+  private void unlock() {
+    if (inCollection)
+      gcLock.release();
+    else
+       mutatorLock.release();
+  }
+
+
+ /****************************************************************************
+  *
+  * Misc
+  */
+  public static boolean isRecycleAllocChunkAligned(Address ptr) {
+    return ptr.toWord().and(RECYCLE_ALLOC_CHUNK_MASK).EQ(Word.zero());
+  }
+
+  ChunkList getChunkMap() { return chunkMap; }
+  Defrag getDefrag() { return defrag; }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/Line.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/Line.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/Line.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/Line.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,125 @@
+/*
+ *  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.mmtk.policy.immix;
+
+import static org.mmtk.policy.immix.ImmixConstants.*;
+
+import org.mmtk.utility.Constants;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.Inline;
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Address;
+import org.vmmagic.unboxed.ObjectReference;
+import org.vmmagic.unboxed.Offset;
+
+ at Uninterruptible
+public class Line implements Constants {
+
+  public static Address align(Address ptr) {
+    return ptr.toWord().and(LINE_MASK.not()).toAddress();
+  }
+
+  public static boolean isAligned(Address address) {
+    return address.EQ(align(address));
+  }
+
+  static int getChunkIndex(Address line) {
+    return line.toWord().and(CHUNK_MASK).rshl(LOG_BYTES_IN_LINE).toInt();
+  }
+
+ /***************************************************************************
+  * Line marking
+  */
+  static void mark(Address address, final byte markValue) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Block.isUnused(Block.align(address)));
+    getMarkAddress(address).store(markValue);
+  }
+
+  static void markMultiLine(Address start, ObjectReference object, final byte markValue) {
+    /* endLine is the address of the last (highest) line touched by this object */
+    Address endLine = Line.align(VM.objectModel.getObjectEndAddress(object).minus(1));
+    Address line = Line.align(start.plus(BYTES_IN_LINE));
+    while (line.LT(endLine)) {
+      if (VM.VERIFY_ASSERTIONS)
+        VM.assertions._assert(Block.align(start) == Block.align(line));
+      mark(line, markValue);
+      line = line.plus(BYTES_IN_LINE);
+    }
+  }
+
+  /***************************************************************************
+   * Scanning through avail lines
+   */
+  public static Address getChunkMarkTable(Address chunk) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk));
+    return getMarkAddress(chunk);
+  }
+
+  public static Address getBlockMarkTable(Address block) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.isAligned(block));
+    return getMarkAddress(block);
+  }
+
+  @Inline
+  public static int getNextUnavailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
+    while (line < LINES_IN_BLOCK &&
+        baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)) < unavailableState)
+      line++;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
+    return line;
+  }
+
+  @Inline
+  public static int getNextAvailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line < LINES_IN_BLOCK);
+    byte last = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
+    byte thisline;
+    line++;
+    while (line < LINES_IN_BLOCK) {
+      thisline = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
+      if (thisline < unavailableState && last < unavailableState)
+        break;
+      last = thisline;
+      line++;
+    }
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
+    return line;
+  }
+
+  private static Address getMetaAddress(Address address, final int tableOffset) {
+    Address chunk = Chunk.align(address);
+    int index = getChunkIndex(address);
+    Address rtn = chunk.plus(tableOffset + (index<<LOG_BYTES_IN_LINE_STATUS));
+    if (VM.VERIFY_ASSERTIONS) {
+      Address line = chunk.plus(index<<LOG_BYTES_IN_LINE);
+      VM.assertions._assert(isAligned(line));
+      VM.assertions._assert(align(address).EQ(line));
+      boolean valid = rtn.GE(chunk.plus(tableOffset)) && rtn.LT(chunk.plus(tableOffset + LINE_MARK_TABLE_BYTES));
+      VM.assertions._assert(valid);
+    }
+    return rtn;
+  }
+
+  private static Address getMarkAddress(Address address) {
+    return getMetaAddress(address, Chunk.LINE_MARK_TABLE_OFFSET);
+  }
+
+  /* per-line mark bytes */
+  static final int LOG_BYTES_IN_LINE_STATUS = 0;
+  static final int BYTES_IN_LINE_STATUS = 1<<LOG_BYTES_IN_LINE_STATUS;
+
+  static final int LINE_MARK_TABLE_BYTES = LINES_IN_CHUNK<<LOG_BYTES_IN_LINE_STATUS;
+  static final int LOG_LINE_MARK_BYTES_PER_BLOCK = LOG_LINES_IN_BLOCK+LOG_BYTES_IN_LINE_STATUS;
+  static final int LINE_MARK_BYTES_PER_BLOCK = (1<<LOG_LINE_MARK_BYTES_PER_BLOCK);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/MutatorLocal.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/MutatorLocal.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/MutatorLocal.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/MutatorLocal.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,55 @@
+/*
+ *  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.mmtk.policy.immix;
+
+import org.mmtk.utility.alloc.ImmixAllocator;
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.pragma.*;
+
+/**
+ *
+ */
+ at Uninterruptible
+public final class MutatorLocal extends ImmixAllocator
+  implements Constants {
+  /**
+   * Constructor
+   *
+   * @param space The mark-sweep space to which this allocator
+   * instances is bound.
+   * @param hot TODO
+   */
+  public MutatorLocal(ImmixSpace space, boolean hot) {
+    super(space, hot, false);
+  }
+
+  /****************************************************************************
+   *
+   * Collection
+   */
+
+  /**
+   * Prepare for a collection. If paranoid, perform a sanity check.
+   */
+  public void prepare() {
+    reset();
+  }
+
+  /**
+   * Finish up after a collection.
+   */
+  public void release() {
+    reset();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ObjectHeader.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ObjectHeader.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ObjectHeader.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/policy/immix/ObjectHeader.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,257 @@
+/*
+ *  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.mmtk.policy.immix;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.Inline;
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.ObjectReference;
+import org.vmmagic.unboxed.Word;
+
+ at Uninterruptible
+public class ObjectHeader {
+  /** number of header bits we may use */
+  static final int MAX_BITS = 8;
+
+  /* header requirements */
+  public static final int LOCAL_GC_BITS_REQUIRED = MAX_BITS;
+  public static final int GLOBAL_GC_BITS_REQUIRED = 0;
+  public static final int GC_HEADER_WORDS_REQUIRED = 0;
+
+  /* stolen bits */
+  static final Word NEW_OBJECT_MARK = Word.fromIntZeroExtend(0); // using zero means no need for explicit initialization on allocation
+  private static final Word BEING_FORWARDED = Word.fromIntZeroExtend(2); // second bit indicates an object is in the process of being forwarded
+  private static final Word FORWARDED       = Word.fromIntZeroExtend(3); // second bit indicates an object is in the process of being forwarded
+  private static final Word FORWARDING_MASK = Word.fromIntZeroExtend(3);
+
+  private static final int UNLOGGED_BIT_NUMBER = 3;
+  public static final Word UNLOGGED_BIT = Word.one().lsh(UNLOGGED_BIT_NUMBER);
+  public static final Word LOG_SET_MASK = UNLOGGED_BIT;
+
+  private static final int STOLEN_LO_BITS = UNLOGGED_BIT_NUMBER + 1; // both used for forwarding, also the all zero state is used to represent new objects
+  private static final int STOLEN_HI_BITS = 2;
+
+  static final int  MAX_MARKCOUNT_BITS = MAX_BITS-(STOLEN_LO_BITS+STOLEN_HI_BITS);
+  private static final int FIRST_STOLEN_HI_BIT_NUMBER = STOLEN_LO_BITS + MAX_MARKCOUNT_BITS;
+
+  public static final int PINNED_BIT_NUMBER = FIRST_STOLEN_HI_BIT_NUMBER;
+  public static final Word PINNED_BIT = Word.one().lsh(PINNED_BIT_NUMBER);
+
+  private static final int STRADDLE_BIT_NUMBER = PINNED_BIT_NUMBER + 1;
+  public static final Word STRADDLE_BIT = Word.one().lsh(STRADDLE_BIT_NUMBER);
+
+  /* mark bits */
+  private static final int  MARK_BASE = STOLEN_LO_BITS;
+  private static final Word MARK_INCREMENT = Word.one().lsh(MARK_BASE);
+  public static final Word MARK_MASK = Word.one().lsh(MAX_MARKCOUNT_BITS).minus(Word.one()).lsh(MARK_BASE);
+  public static final Word MARK_AND_LOG_BITS_MASK = Word.one().lsh(MAX_BITS-STOLEN_HI_BITS).minus(Word.one());
+  public static final Word MARK_BITS_MASK = MARK_AND_LOG_BITS_MASK.xor(UNLOGGED_BIT);
+
+  public static final Word MARK_BASE_VALUE = MARK_INCREMENT;
+
+
+
+  /****************************************************************************
+   *
+   * Marking
+   */
+
+  /**
+   * Non-atomically test and 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 markState The value to which the mark bits will be set
+   */
+  static Word testAndMark(ObjectReference object, Word markState) {
+    int oldValue, newValue, oldMarkState;
+
+    oldValue = VM.objectModel.readAvailableByte(object);
+    oldMarkState = oldValue & MARK_AND_LOG_BITS_MASK.toInt();
+    if (oldMarkState != markState.toInt()) {
+      newValue = (oldValue & ~MARK_AND_LOG_BITS_MASK.toInt()) | markState.toInt();
+      VM.objectModel.writeAvailableByte(object, (byte) newValue);
+    }
+    return Word.fromIntZeroExtend(oldMarkState);
+  }
+
+  static void setMarkStateUnlogAndUnlock(ObjectReference object, Word originalForwardingWord, Word markState) {
+    Word markValue = Plan.NEEDS_LOG_BIT_IN_HEADER ? markState.or(ObjectHeader.UNLOGGED_BIT) : markState;
+    int oldValue = originalForwardingWord.toInt();
+    int newValue = (oldValue & (MARK_AND_LOG_BITS_MASK.or(FORWARDING_MASK)).not().toInt()) | markValue.toInt();
+    VM.objectModel.writeAvailableByte(object, (byte) newValue);
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert((oldValue & MARK_AND_LOG_BITS_MASK.toInt()) != markValue.toInt());
+  }
+
+  /**
+   * Return true if the mark count 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.
+   */
+  static boolean testMarkState(ObjectReference object, Word value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(MARK_MASK).EQ(value));
+    return testMarkState(VM.objectModel.readAvailableBitsWord(object), value);
+  }
+
+  static boolean testMarkState(Word forwardingWord, Word value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(MARK_MASK).EQ(value));
+    return forwardingWord.and(MARK_MASK).EQ(value);
+  }
+
+  static boolean isNewObject(ObjectReference object) {
+    Word markBits = VM.objectModel.readAvailableBitsWord(object).and(MARK_AND_LOG_BITS_MASK);
+    return markBits.EQ(NEW_OBJECT_MARK);
+  }
+
+  static boolean isMatureObject(ObjectReference object) {
+    Word markBits = VM.objectModel.readAvailableBitsWord(object).and(MARK_AND_LOG_BITS_MASK);
+    boolean unforwarded = markBits.and(FORWARDING_MASK).isZero();
+    boolean newObj = markBits.EQ(NEW_OBJECT_MARK);
+    return unforwarded && !newObj;
+  }
+
+  @Inline
+  static void markAsStraddling(ObjectReference object) {
+    Word old = VM.objectModel.readAvailableBitsWord(object);
+    VM.objectModel.writeAvailableBitsWord(object, old.or(STRADDLE_BIT));
+  }
+
+  @Inline
+  static boolean isStraddlingObject(ObjectReference object) {
+    return isStraddleBitSet(VM.objectModel.readAvailableBitsWord(object));
+  }
+
+  @Inline
+  private static boolean isStraddleBitSet(Word header) {
+    return header.and(STRADDLE_BIT).EQ(STRADDLE_BIT);
+  }
+
+  @Inline
+  static boolean isUnloggedObject(ObjectReference object) {
+    return isUnloggedBitSet(VM.objectModel.readAvailableBitsWord(object));
+  }
+
+  @Inline
+  static boolean isUnloggedBitSet(Word header) {
+    return header.and(UNLOGGED_BIT).EQ(UNLOGGED_BIT);
+  }
+
+  @Inline
+  public static void pinObject(ObjectReference object) {
+    byte header = VM.objectModel.readAvailableByte(object);
+    VM.objectModel.writeAvailableByte(object, (byte)(header | PINNED_BIT.toInt()));
+  }
+
+  @Inline
+  static boolean isPinnedObject(ObjectReference object) {
+    return isPinnedBitSet(VM.objectModel.readAvailableBitsWord(object));
+  }
+
+  @Inline
+  private static boolean isPinnedBitSet(Word header) {
+    return header.and(PINNED_BIT).EQ(PINNED_BIT);
+  }
+
+  /**
+   * Write the allocState into the mark state fields of an object non-atomically.
+   * This is appropriate for collection time initialization.
+   *
+   * @param object The object whose mark state is to be written
+   * @param markState TODO: what am I?
+   * @param straddle TODO: what am I?
+   */
+  static void writeMarkState(ObjectReference object, Word markState, boolean straddle) {
+    Word oldValue = VM.objectModel.readAvailableBitsWord(object);
+    Word markValue = Plan.NEEDS_LOG_BIT_IN_HEADER ? markState.or(ObjectHeader.UNLOGGED_BIT) : markState;
+    Word newValue = oldValue.and(MARK_AND_LOG_BITS_MASK.not()).or(markValue);
+    if (straddle)
+      newValue = newValue.or(STRADDLE_BIT);
+    VM.objectModel.writeAvailableBitsWord(object, newValue);
+  }
+
+  /****************************************************************************
+   *
+   * Forwarding
+   */
+
+  /**
+   * Either return the forwarding pointer if the object is already
+   * forwarded (or being forwarded) or write the bit pattern that
+   * indicates that the object is being forwarded
+   *
+   * @param object The object to be forwarded
+   * @return The forwarding pointer for the object if it has already
+   * been forwarded.
+   */
+  static Word attemptToBeForwarder(ObjectReference object) {
+    Word oldValue;
+    do {
+      oldValue = VM.objectModel.prepareAvailableBits(object);
+      if (oldValue.and(FORWARDING_MASK).EQ(FORWARDED))
+        return oldValue;
+    } while (!VM.objectModel.attemptAvailableBits(object, oldValue, oldValue.or(BEING_FORWARDED)));
+    return oldValue;
+  }
+
+  static ObjectReference forwardObject(ObjectReference object, int allocator) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!isPinnedObject(object));
+    ObjectReference newObject = VM.objectModel.copy(object, allocator);
+    VM.objectModel.writeAvailableBitsWord(object, newObject.toAddress().toWord().or(FORWARDED));
+    return newObject;
+  }
+
+  static void setForwardingWordAndEnsureUnlogged(ObjectReference object, Word forwardingWord) {
+    if (Plan.NEEDS_LOG_BIT_IN_HEADER) forwardingWord = forwardingWord.or(UNLOGGED_BIT);
+    VM.objectModel.writeAvailableBitsWord(object, forwardingWord);
+  }
+
+  static boolean isForwardedOrBeingForwarded(ObjectReference object) {
+    return isForwardedOrBeingForwarded(VM.objectModel.readAvailableBitsWord(object));
+  }
+
+  static boolean isForwardedOrBeingForwarded(Word forwardingWord) {
+    return !forwardingWord.and(FORWARDING_MASK).isZero();
+  }
+
+  static ObjectReference spinAndGetForwardedObject(ObjectReference object, Word forwardingWord) {
+    /* We must wait (spin) if the object is not yet fully forwarded */
+    while (forwardingWord.and(FORWARDING_MASK).EQ(BEING_FORWARDED))
+      forwardingWord = VM.objectModel.readAvailableBitsWord(object);
+
+    /* Now extract the object reference from the forwarding word and return it */
+    if (forwardingWord.and(FORWARDING_MASK).EQ(FORWARDED))
+      return forwardingWord.and(FORWARDING_MASK.not()).toAddress().toObjectReference();
+    else
+      return object;
+  }
+
+  /**
+   * Return the mark state incremented or decremented by one.
+   *
+   * @param increment If true, then return the incremented value else return the decremented value
+   * @return the mark state incremented or decremented by one.
+   */
+  static Word deltaMarkState(Word state, boolean increment) {
+    Word rtn = state;
+    do {
+      rtn = increment ? rtn.plus(MARK_INCREMENT) : rtn.minus(MARK_INCREMENT);
+      rtn = rtn.and(MARK_MASK);
+      } while (rtn.LT(MARK_BASE_VALUE));
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn.NE(state));
+    return rtn;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/BaseGenericFreeList.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/BaseGenericFreeList.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/BaseGenericFreeList.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/BaseGenericFreeList.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,366 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This is a very simple, generic malloc-free allocator.  It works
+ * abstractly, in "units", which the user may associate with some
+ * other allocatable resource (e.g. heap blocks).  The user issues
+ * requests for N units and the allocator returns the index of the
+ * first of a contiguous set of N units or fails, returning -1.  The
+ * user frees the block of N units by calling <code>free()</code> with
+ * the index of the first unit as the argument.<p>
+ *
+ * Properties/Constraints:<ul>
+ *   <li> The allocator consumes one word per allocatable unit (plus
+ *   a fixed overhead of about 128 words).</li>
+ *   <li> The allocator can only deal with MAX_UNITS units (see below for
+ *   the value).</li>
+ * </ul>
+ *
+ * The basic data structure used by the algorithm is a large table,
+ * with one word per allocatable unit.  Each word is used in a
+ * number of different ways, some combination of "undefined" (32),
+ * "free/used" (1), "multi/single" (1), "prev" (15), "next" (15) &
+ * "size" (15) where field sizes in bits are in parenthesis.
+ * <pre>
+ *                       +-+-+-----------+-----------+
+ *                       |f|m|    prev   | next/size |
+ *                       +-+-+-----------+-----------+
+ *
+ *   - single free unit: "free", "single", "prev", "next"
+ *   - single used unit: "used", "single"
+ *    - contiguous free units
+ *     . first unit: "free", "multi", "prev", "next"
+ *     . second unit: "free", "multi", "size"
+ *     . last unit: "free", "multi", "size"
+ *    - contiguous used units
+ *     . first unit: "used", "multi", "prev", "next"
+ *     . second unit: "used", "multi", "size"
+ *     . last unit: "used", "multi", "size"
+ *    - any other unit: undefined
+ *
+ *                       +-+-+-----------+-----------+
+ *   top sentinel        |0|0|    tail   |   head    |  [-1]
+ *                       +-+-+-----------+-----------+
+ *                                     ....
+ *            /--------  +-+-+-----------+-----------+
+ *            |          |1|1|   prev    |   next    |  [j]
+ *            |          +-+-+-----------+-----------+
+ *            |          |1|1|           |   size    |  [j+1]
+ *         free multi    +-+-+-----------+-----------+
+ *         unit block    |              ...          |  ...
+ *            |          +-+-+-----------+-----------+
+ *            |          |1|1|           |   size    |
+ *           >--------  +-+-+-----------+-----------+
+ *   single free unit    |1|0|   prev    |   next    |
+ *           >--------  +-+-+-----------+-----------+
+ *   single used unit    |0|0|                       |
+ *           >--------  +-+-+-----------------------+
+ *            |          |0|1|                       |
+ *            |          +-+-+-----------+-----------+
+ *            |          |0|1|           |   size    |
+ *         used multi    +-+-+-----------+-----------+
+ *         unit block    |              ...          |
+ *            |          +-+-+-----------+-----------+
+ *            |          |0|1|           |   size    |
+ *            \--------  +-+-+-----------+-----------+
+ *                                     ....
+ *                       +-+-+-----------------------+
+ *   bottom sentinel     |0|0|                       |  [N]
+ *                       +-+-+-----------------------+
+ * </pre>
+ * The sentinels serve as guards against out of range coalescing
+ * because they both appear as "used" blocks and so will never
+ * coalesce.  The top sentinel also serves as the head and tail of
+ * the doubly linked list of free blocks.
+ */
+ at Uninterruptible abstract class BaseGenericFreeList implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Allocate <code>size</code> units. Return the unit ID
+   *
+   * @param size  The number of units to be allocated
+   * @return The index of the first of the <code>size</code>
+   * contiguous units, or -1 if the request can't be satisfied
+   */
+  public final int alloc(int size) {
+    // Note: -1 is both the default return value *and* the start sentinel index
+    int unit = head; // HEAD = -1
+    int s = 0;
+    while (((unit = getNext(unit)) != head) && ((s = getSize(unit)) < size));
+
+    return (unit == head) ? FAILURE : alloc(size, unit, s);
+  }
+
+  /**
+   * Would an allocation of <code>size</code> units succeed?
+   *
+   * @param size The number of units to test for
+   * @return True if such a request could be satisfied.
+   */
+  public final boolean couldAlloc(int size) {
+    // Note: -1 is both the default return value *and* the start sentinel index
+    int unit = head; // HEAD = -1
+    while (((unit = getNext(unit)) != head) && (getSize(unit) < size));
+
+    return (unit != head);
+  }
+
+  /**
+   * Allocate <code>size</code> units. Return the unit ID
+   *
+   * @param size  The number of units to be allocated
+   * @return The index of the first of the <code>size</code>
+   * contiguous units, or -1 if the request can't be satisfied
+   */
+  public final int alloc(int size, int unit) {
+    int s = 0;
+
+    if (getFree(unit) && (s = getSize(unit)) >= size)
+      return alloc(size, unit, s);
+    else
+      return FAILURE;
+  }
+
+  /**
+   * Allocate <code>size</code> units. Return the unit ID
+   *
+   * @param size  The number of units to be allocated
+   * @return The index of the first of the <code>size</code>
+   * contiguous units, or -1 if the request can't be satisfied
+   */
+  private int alloc(int size, int unit, int unitSize) {
+    if (unitSize >= size) {
+      if (unitSize > size)
+        split(unit, size);
+      removeFromFree(unit);
+      setFree(unit, false);
+    }
+
+    if (DEBUG) dbgPrintFree();
+
+    return unit;
+  }
+
+  /**
+   * Free a previously allocated contiguous lump of units.
+   *
+   * @param unit The index of the first unit.
+   * @return return the size of the unit which was freed.
+   */
+  public final int free(int unit) {
+    return free(unit, false);
+  }
+
+  /**
+   * Free a previously allocated contiguous lump of units.
+   *
+   * @param unit The index of the first unit.
+   * @param returnCoalescedSize if true, return the coalesced size
+   * @return The number of units freed. if returnCoalescedSize is
+   *  false, return the size of the unit which was freed.  Otherwise
+   *   return the size of the unit now available (the coalesced size)
+   */
+  public final int free(int unit, boolean returnCoalescedSize) {
+    int freed = getSize(unit);
+    int left = getLeft(unit);
+    int start = isCoalescable(unit) && getFree(left) ? left : unit;
+    int right = getRight(unit);
+    int end = isCoalescable(right) && getFree(right) ? right : unit;
+    if (start != end)
+      coalesce(start, end);
+
+    if (returnCoalescedSize)
+      freed = getSize(start);
+    addToFree(start);
+
+    if (DEBUG) dbgPrintFree();
+    return freed;
+  }
+
+  /**
+   * Return the size of the specified lump of units
+   *
+   * @param unit The index of the first unit in the lump.
+   * @return The size of the lump, in units.
+   */
+  public final int size(int unit) {
+    return getSize(unit);
+  }
+
+  /****************************************************************************
+   *
+   * Private fields and methods
+   */
+
+  /**
+   * Initialize a new heap.  Fabricate a free list entry containing
+   * everything
+   *
+   * @param units The number of units in the heap
+   */
+  protected final void initializeHeap(int units) {
+    initializeHeap(units, units);
+  }
+
+  /**
+   * Initialize a new heap.  Fabricate a free list entry containing
+   * everything
+   *
+   * @param units The number of units in the heap
+   */
+  protected final void initializeHeap(int units, int grain) {
+    // Initialize the sentinels
+    for (int i = 1; i <= heads; i++)
+      setSentinel(-i);
+    setSentinel(units);
+
+    // create the free list item
+    int offset = units % grain;
+    int cursor = units - offset;
+    if (offset > 0) {
+      setSize(cursor, offset);
+      addToFree(cursor);
+    }
+    cursor -= grain;
+    while (cursor >= 0) {
+      setSize(cursor, grain);
+      addToFree(cursor);
+      cursor -= grain;
+    }
+    if (DEBUG) dbgPrintFree();
+  }
+
+  /**
+   * Reduce a lump of units to size, freeing any excess.
+   *
+   * @param unit The index of the first unit
+   * @param size The size of the first part
+   */
+  private void split(int unit, int size) {
+    int basesize = getSize(unit);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(basesize > size);
+    setSize(unit, size);
+    setSize(unit + size, basesize - size);
+    addToFree(unit + size);
+    if (DEBUG) dbgPrintFree();
+  }
+
+  /**
+   * Coalesce two or three contiguous lumps of units, removing start
+   * and end lumps from the free list as necessary.
+   * @param start The index of the start of the first lump
+   * @param end The index of the start of the last lump
+   */
+  private void coalesce(int start, int end) {
+    if (getFree(end))
+      removeFromFree(end);
+    if (getFree(start))
+      removeFromFree(start);
+
+    setSize(start, end - start + getSize(end));
+  }
+
+  /**
+   * Add a lump of units to the free list
+   *
+   * @param unit The first unit in the lump of units to be added
+   */
+  private void addToFree(int unit) {
+    setFree(unit, true);
+    int next = getNext(head);
+    setNext(unit, next);
+    setNext(head, unit);
+    setPrev(unit, head);
+    setPrev(next, unit);
+  }
+
+  /**
+   * Remove a lump of units from the free list
+   *
+   * @param unit The first unit in the lump of units to be removed
+   */
+  private void removeFromFree(int unit) {
+    int next = getNext(unit);
+    int prev = getPrev(unit);
+    setNext(prev, next);
+    setPrev(next, prev);
+    if (DEBUG) dbgPrintFree();
+  }
+
+  /**
+   * Get the lump to the "right" of the current lump (i.e. "below" it)
+   *
+   * @param unit The index of the first unit in the lump in question
+   * @return The index of the first unit in the lump to the
+   * "right"/"below" the lump in question.
+   */
+  private int getRight(int unit) {
+    return unit + getSize(unit);
+  }
+
+
+  /**
+   * Print the free list (for debugging purposes)
+   */
+  void dbgPrintFree() {
+    if (DEBUG) {
+      Log.write("FL[");
+      int i = head;
+      while ((i = getNext(i)) != head) {
+        boolean f = getFree(i);
+        int s = getSize(i);
+        if (!f)
+          Log.write("->");
+        Log.write(i);
+        if (!f)
+          Log.write("<-");
+        Log.write("(");
+        Log.write(s);
+        Log.write(")");
+        Log.write(" ");
+        Log.flush();
+      }
+      Log.writeln("]FL");
+    }
+  }
+
+  abstract void setSentinel(int unit);
+  abstract int getSize(int unit);
+  abstract void setSize(int unit, int size);
+  abstract boolean getFree(int unit);
+  abstract void setFree(int unit, boolean isFree);
+  abstract int getNext(int unit);
+  abstract void setNext(int unit, int next);
+  abstract int getPrev(int unit);
+  abstract void setPrev(int unit, int prev);
+  abstract int getLeft(int unit);
+  abstract boolean isCoalescable(int unit);
+
+  protected static final boolean DEBUG = false;
+  public static final int FAILURE = -1;
+  protected static final int MAX_HEADS = 128; // somewhat arbitrary
+
+  protected int heads = 1;
+  protected int head = -heads;
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/CallSite.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/CallSite.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/CallSite.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/CallSite.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,18 @@
+/*
+ *  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.mmtk.utility;
+
+/*
+ */
+public class CallSite {
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/Constants.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/Constants.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/Constants.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/Constants.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,145 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.utility.alloc.EmbeddedMetaData;
+import org.mmtk.vm.VM;
+
+/**
+ * MMTk follows the pattern set by Jikes RVM for defining sizes of
+ * primitive types thus:
+ *
+ * <pre>
+ * static final int LOG_BYTES_IN_INT = 2;
+ * static final int BYTES_IN_INT = 1<<LOG_BYTES_IN_INT;
+ * static final int LOG_BITS_IN_INT = LOG_BITS_IN_BYTE + LOG_BYTES_IN_INT;
+ * static final int BITS_IN_INT = 1<<LOG_BITS_IN_INT;
+ * </pre>
+ */
+public interface Constants {
+
+  /****************************************************************************
+   *
+   * MMTk constants
+   */
+  int PUTFIELD_WRITE_BARRIER = 0;
+  int GETFIELD_READ_BARRIER = 0;
+  int PUTSTATIC_WRITE_BARRIER = 1;
+  int GETSTATIC_READ_BARRIER = 1;
+  int AASTORE_WRITE_BARRIER = 2;
+  int AALOAD_READ_BARRIER = 2;
+
+
+  /****************************************************************************
+   *
+   * Generic sizes
+   */
+  byte LOG_BYTES_IN_BYTE = 0;
+  int BYTES_IN_BYTE = 1;
+  byte LOG_BITS_IN_BYTE = 3;
+  int BITS_IN_BYTE = 1 << LOG_BITS_IN_BYTE;
+
+  byte LOG_BYTES_IN_MBYTE = 20;
+  int BYTES_IN_MBYTE = 1 << LOG_BYTES_IN_MBYTE;
+
+  byte LOG_BYTES_IN_KBYTE = 10;
+  int BYTES_IN_KBYTE = 1 << LOG_BYTES_IN_KBYTE;
+
+  /****************************************************************************
+   *
+   * Card scanning
+   */
+  boolean SUPPORT_CARD_SCANNING = false;
+  int LOG_CARD_META_SIZE = 2;// each card consumes four bytes of metadata
+  int LOG_CARD_UNITS = 10;  // number of units tracked per card
+  int LOG_CARD_GRAIN = 0;   // track at byte grain, save shifting
+  int LOG_CARD_BYTES = LOG_CARD_UNITS + LOG_CARD_GRAIN;
+  int LOG_CARD_META_BYTES = EmbeddedMetaData.LOG_BYTES_IN_REGION - LOG_CARD_BYTES + LOG_CARD_META_SIZE;
+  int LOG_CARD_META_PAGES = LOG_CARD_META_BYTES - VM.LOG_BYTES_IN_PAGE;
+  int CARD_META_PAGES_PER_REGION = SUPPORT_CARD_SCANNING ? (1<<LOG_CARD_META_PAGES) : 0;
+  int CARD_MASK = (1<<LOG_CARD_BYTES) - 1;
+
+
+  /****************************************************************************
+   *
+   * Java-specific sizes currently required by MMTk
+   *
+   * TODO MMTk should really become independent of these Java types
+   */
+  byte LOG_BYTES_IN_SHORT = 1;
+  int BYTES_IN_SHORT = 1 << LOG_BYTES_IN_SHORT;
+  byte LOG_BITS_IN_SHORT = LOG_BITS_IN_BYTE + LOG_BYTES_IN_SHORT;
+  int BITS_IN_SHORT = 1 << LOG_BITS_IN_SHORT;
+
+  byte LOG_BYTES_IN_INT = 2;
+  int BYTES_IN_INT = 1 << LOG_BYTES_IN_INT;
+  byte LOG_BITS_IN_INT = LOG_BITS_IN_BYTE + LOG_BYTES_IN_INT;
+  int BITS_IN_INT = 1 << LOG_BITS_IN_INT;
+
+  int MAX_INT = 0x7fffffff;
+  int MIN_INT = 0x80000000;
+
+  /****************************************************************************
+   *
+   * VM-Specific sizes
+   */
+  byte LOG_BYTES_IN_ADDRESS = VM.LOG_BYTES_IN_ADDRESS;
+  int BYTES_IN_ADDRESS = 1 << LOG_BYTES_IN_ADDRESS;
+  int LOG_BITS_IN_ADDRESS = LOG_BITS_IN_BYTE + LOG_BYTES_IN_ADDRESS;
+  int BITS_IN_ADDRESS = 1 << LOG_BITS_IN_ADDRESS;
+
+  // Note that in MMTk we currently define WORD & ADDRESS to be the same size
+  byte LOG_BYTES_IN_WORD = LOG_BYTES_IN_ADDRESS;
+  int BYTES_IN_WORD = 1 << LOG_BYTES_IN_WORD;
+  int LOG_BITS_IN_WORD = LOG_BITS_IN_BYTE + LOG_BYTES_IN_WORD;
+  int BITS_IN_WORD = 1 << LOG_BITS_IN_WORD;
+
+  byte LOG_BYTES_IN_PAGE = VM.LOG_BYTES_IN_PAGE;
+  int BYTES_IN_PAGE = 1 << LOG_BYTES_IN_PAGE;
+  int LOG_BITS_IN_PAGE = LOG_BITS_IN_BYTE + LOG_BYTES_IN_PAGE;
+  int BITS_IN_PAGE = 1 << LOG_BITS_IN_PAGE;
+
+  /* Assume byte-addressability */
+  byte LOG_BYTES_IN_ADDRESS_SPACE = (byte) BITS_IN_ADDRESS;
+
+  /**
+   * This value specifies the <i>minimum</i> allocation alignment
+   * requirement of the VM.  When making allocation requests, both
+   * <code>align</code> and <code>offset</code> must be multiples of
+   * <code>MIN_ALIGNMENT</code>.
+   *
+   * This value is required to be a power of 2.
+   */
+  byte LOG_MIN_ALIGNMENT = VM.LOG_MIN_ALIGNMENT;
+  int MIN_ALIGNMENT = 1 << LOG_MIN_ALIGNMENT;
+
+  /**
+   * The maximum alignment request the vm will make. This must be a
+   * power of two multiple of the minimum alignment.
+   */
+  int MAX_ALIGNMENT = MIN_ALIGNMENT<<VM.MAX_ALIGNMENT_SHIFT;
+
+  /**
+   * The VM will add at most this value minus BYTES_IN_INT bytes of
+   * padding to the front of an object that it places in a region of
+   * memory. This value must be a power of 2.
+   */
+  int MAX_BYTES_PADDING = VM.MAX_BYTES_PADDING;
+
+  /**
+   * The VM will add at most this value minus BYTES_IN_INT bytes of
+   * padding to the front of an object that it places in a region of
+   * memory. This value must be a power of 2.
+   */
+  int ALIGNMENT_VALUE = VM.ALIGNMENT_VALUE;
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/Conversions.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/Conversions.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/Conversions.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/Conversions.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,163 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.utility.heap.*;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/*
+ import org.jikesrvm.Offset;
+ * Conversions between different units.
+ */
+ at Uninterruptible public class Conversions implements Constants {
+
+  // public static Address roundDownVM(Address addr) {
+  //   return roundDown(addr.toWord(), VMResource.LOG_BYTES_IN_REGION).toAddress();
+  // }
+
+  // public static Extent roundDownVM(Extent bytes) {
+  //   return roundDown(bytes.toWord(), VMResource.LOG_BYTES_IN_REGION).toExtent();
+  // }
+
+  public static Address roundDownMB(Address addr) {
+    return roundDown(addr.toWord(), LOG_BYTES_IN_MBYTE).toAddress();
+  }
+
+  public static Extent roundDownMB(Extent bytes) {
+    return roundDown(bytes.toWord(), LOG_BYTES_IN_MBYTE).toExtent();
+  }
+
+  private static Word roundDown(Word value, int logBase) {
+    Word mask = Word.one().lsh(logBase).minus(Word.one()).not();
+    return value.and(mask);
+  }
+
+  public static int roundDown(int value, int alignment) {
+    return value & ~(alignment - 1);
+  }
+
+  // Round up (if necessary)
+  //
+  public static int MBToPages(int megs) {
+    if (LOG_BYTES_IN_PAGE <= LOG_BYTES_IN_MBYTE)
+      return (megs << (LOG_BYTES_IN_MBYTE - LOG_BYTES_IN_PAGE));
+    else
+      return (megs + ((BYTES_IN_PAGE >>> LOG_BYTES_IN_MBYTE) - 1)) >>> (LOG_BYTES_IN_PAGE - LOG_BYTES_IN_MBYTE);
+  }
+
+  public static int bytesToMmapChunksUp(Extent bytes) {
+    return bytes.plus(Mmapper.MMAP_CHUNK_BYTES - 1).toWord().rshl(Mmapper.LOG_MMAP_CHUNK_BYTES).toInt();
+  }
+
+  public static int pagesToMmapChunksUp(int pages) {
+    return bytesToMmapChunksUp(pagesToBytes(pages));
+  }
+
+  public static int addressToMmapChunksDown(Address addr) {
+    Word chunk = addr.toWord().rshl(Mmapper.LOG_MMAP_CHUNK_BYTES);
+    return chunk.toInt();
+  }
+
+  public static int addressToPagesDown(Address addr) {
+    Word chunk = addr.toWord().rshl(LOG_BYTES_IN_PAGE);
+    return chunk.toInt();
+  }
+
+  public static int addressToPages(Address addr) {
+    int page = addressToPagesDown(addr);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(pagesToAddress(page).EQ(addr));
+    return page;
+  }
+
+  public static Address pagesToAddress(int pages) {
+    return Word.fromIntZeroExtend(pages).lsh(LOG_BYTES_IN_PAGE).toAddress();
+  }
+
+  public static int addressToMmapChunksUp(Address addr) {
+    Word chunk = addr.plus(Mmapper.MMAP_CHUNK_BYTES - 1).toWord().rshl(Mmapper.LOG_MMAP_CHUNK_BYTES);
+    return chunk.toInt();
+  }
+
+  public static Extent pagesToBytes(int pages) {
+    return Word.fromIntZeroExtend(pages).lsh(LOG_BYTES_IN_PAGE).toExtent();
+  }
+
+  public static int pagesToMBytes(int pages) {
+    return pages >> (LOG_BYTES_IN_MBYTE - LOG_BYTES_IN_PAGE);
+  }
+
+  public static int pagesToKBytes(int pages) {
+    return pages << (LOG_BYTES_IN_PAGE - LOG_BYTES_IN_KBYTE);
+  }
+
+  /**
+    @deprecated : use int bytesToPagesUp(Extent bytes) if possible
+   */
+  @Deprecated
+  public static int bytesToPagesUp(int bytes) {
+    return bytesToPagesUp(Extent.fromIntZeroExtend(bytes));
+  }
+
+  /**
+    @deprecated : use int bytesToPagesUp(Extent bytes) if possible
+   */
+  @Deprecated
+  public static int bytesToPages(int bytes) {
+    return bytesToPages(Extent.fromIntZeroExtend(bytes));
+  }
+
+  public static int bytesToPagesUp(Extent bytes) {
+    return bytes.plus(BYTES_IN_PAGE-1).toWord().rshl(LOG_BYTES_IN_PAGE).toInt();
+  }
+
+  public static int bytesToPages(Extent bytes) {
+    int pages = bytesToPagesUp(bytes);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(pagesToAddress(pages).toWord().toExtent().EQ(bytes));
+    return pages;
+  }
+
+  public static int bytesToPages(Offset bytes) {
+    if (VM.VERIFY_ASSERTIONS) {
+      long val = bytes.toLong();
+      VM.assertions._assert(val >= MIN_INT && val <= MAX_INT);
+    }
+    if (bytes.sGE(Offset.zero()))
+      return bytesToPagesUp(Extent.fromIntSignExtend(bytes.toInt()));
+    else
+      return -bytesToPagesUp(Extent.fromIntSignExtend(-bytes.toInt()));
+  }
+
+  public static Address mmapChunksToAddress(int chunk) {
+    return Word.fromIntZeroExtend(chunk).lsh(Mmapper.LOG_MMAP_CHUNK_BYTES).toAddress();
+  }
+
+  public static Address pageAlign(Address address) {
+    return address.toWord().rshl(LOG_BYTES_IN_PAGE).lsh(LOG_BYTES_IN_PAGE).toAddress();
+  }
+
+  public static int pageAlign(int value) {
+    return (value>>LOG_BYTES_IN_PAGE)<<LOG_BYTES_IN_PAGE;
+  }
+
+  public static boolean isPageAligned(Address address) {
+    return pageAlign(address).EQ(address);
+  }
+
+  public static boolean isPageAligned(int value) {
+    return pageAlign(value) == value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/CycleDetector.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/CycleDetector.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/CycleDetector.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/CycleDetector.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,32 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.utility.options.*;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/*
+ */
+ at Uninterruptible abstract class CycleDetector {
+
+  static {
+    Options.cycleFilterThreshold = new CycleFilterThreshold();
+    Options.cycleMetaDataLimit = new CycleMetaDataLimit();
+    Options.cycleTriggerThreshold = new CycleTriggerThreshold();
+  }
+
+  abstract boolean collectCycles(boolean primary, boolean time);
+  abstract void possibleCycleRoot(ObjectReference object);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/DoublyLinkedList.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/DoublyLinkedList.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/DoublyLinkedList.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/DoublyLinkedList.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,208 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+
+import org.mmtk.vm.Lock;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * FIXME This class must be re-written as it makes the assumption that
+ * the implementation language (Java) and the language being
+ * implemented are the same.  This is true in the case of Jikes RVM,
+ * but it is not true for any VM implementing a language other than
+ * Java.
+ *
+ *
+ * Each instance of this class is a doubly-linked list, in which
+ * each item or node is a piece of memory.  The first two words of each node
+ * contains the forward and backward links.  The third word contains
+ * the treadmill.  The remaining portion is the payload.
+ *
+ * The treadmill object itself must not be moved.
+ *
+ * Access to the instances may be synchronized depending on the
+ * constructor argument.
+ */
+ at Uninterruptible public final class DoublyLinkedList implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private Address head;
+  private final Lock lock;
+  private final int logGranularity;  // Each node on the treadmill is guaranteed to be a multiple of granularity.
+
+  /****************************************************************************
+   *
+   * Instance Methods
+   */
+
+  /**
+   * Constructor
+   */
+  public DoublyLinkedList(int logGranularity, boolean shared) {
+    head = Address.zero();
+    lock = shared ? VM.newLock("DoublyLinkedList") : null;
+    this.logGranularity = logGranularity;
+
+    // ensure that granularity is big enough for midPayloadToNode to work
+    Word tmp = Word.one().lsh(logGranularity);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tmp.and(nodeMask).EQ(tmp));
+  }
+
+  // Offsets are relative to the node (not the payload)
+  //
+  private static final Offset PREV_OFFSET = Offset.fromIntSignExtend(0 * BYTES_IN_ADDRESS);
+  private static Offset NEXT_OFFSET = Offset.fromIntSignExtend(1 * BYTES_IN_ADDRESS);
+  private static Offset HEADER_SIZE = Offset.fromIntSignExtend(2 * BYTES_IN_ADDRESS);
+
+  private static final Word nodeMask;
+  static {
+    Word mask = Word.one();
+    while (mask.LE(HEADER_SIZE.plus(MAX_BYTES_PADDING).toWord())) mask = mask.lsh(1);
+    nodeMask = mask.minus(Word.one()).not();
+  }
+
+  @Inline
+  public static int headerSize() {
+    return HEADER_SIZE.toInt();
+  }
+
+  public boolean isNode(Address node) {
+    return node.toWord().rshl(logGranularity).lsh(logGranularity).EQ(node.toWord());
+  }
+
+  @Inline
+  public static Address nodeToPayload(Address node) {
+    return node.plus(HEADER_SIZE);
+  }
+
+  @Inline
+  public static Address midPayloadToNode(Address payload) {
+    // This method words as long as you are less than MAX_BYTES_PADDING into the payload.
+    return payload.toWord().and(nodeMask).toAddress();
+  }
+
+  @Inline
+  public void add(Address node) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isNode(node));
+    if (lock != null) lock.acquire();
+    node.store(Address.zero(), PREV_OFFSET);
+    node.store(head, NEXT_OFFSET);
+    if (!head.isZero())
+      head.store(node, PREV_OFFSET);
+    head = node;
+    if (lock != null) lock.release();
+  }
+
+  @Inline
+  public void remove(Address node) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isNode(node));
+    if (lock != null) lock.acquire();
+    Address prev = node.loadAddress(PREV_OFFSET);
+    Address next = node.loadAddress(NEXT_OFFSET);
+    // Splice the node out of the list
+    if (!next.isZero())
+      next.store(prev, PREV_OFFSET);
+    if (prev.isZero())
+      head = next;
+    else
+      prev.store(next, NEXT_OFFSET);
+    // Null out node's reference to the list
+    node.store(Address.zero(), PREV_OFFSET);
+    node.store(Address.zero(), NEXT_OFFSET);
+    if (lock != null) lock.release();
+  }
+
+  @Inline
+  public Address getHead() {
+    return head;
+  }
+
+  @Inline
+  public Address getNext(Address node) {
+    return node.loadAddress(NEXT_OFFSET);
+  }
+
+  @Inline
+  public Address pop() {
+    Address first = head;
+    if (!first.isZero())
+      remove(first);
+    return first;
+  }
+
+  @Inline
+  public boolean isEmpty() {
+    return head.isZero();
+  }
+
+  /**
+   * Return true if a cell is on a given treadmill
+   *
+   * @param node The cell being searched for
+   * @return True if the cell is found on the treadmill
+   */
+  public boolean isMember(Address node) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isNode(node));
+    boolean result = false;
+    if (lock != null) lock.acquire();
+    Address cur = head;
+    while (!cur.isZero()) {
+      if (cur.EQ(node)) {
+        result = true;
+        break;
+      }
+      cur = cur.loadAddress(NEXT_OFFSET);
+    }
+    if (lock != null) lock.release();
+    return result;
+  }
+
+  public void show() {
+    if (lock != null) lock.acquire();
+    Address cur = head;
+    Log.write(cur);
+    while (!cur.isZero()) {
+      cur = cur.loadAddress(NEXT_OFFSET);
+      Log.write(" -> "); Log.write(cur);
+    }
+    Log.writeln();
+    if (lock != null) lock.release();
+  }
+
+
+  /**
+   * Gather data for GCSpy
+   * @param driver the GCSpy space driver
+   */
+  void gcspyGatherData(AbstractDriver driver) {
+    // GCSpy doesn't need a lock (in its stop the world config)
+    Address cur = head;
+    while (!cur.isZero()) {
+      driver.scan(cur);
+      cur = cur.loadAddress(NEXT_OFFSET);
+    }
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/GenericFreeList.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/GenericFreeList.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/GenericFreeList.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/GenericFreeList.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,383 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This is a very simple, generic malloc-free allocator.  It works
+ * abstractly, in "units", which the user may associate with some
+ * other allocatable resource (e.g. heap blocks).  The user issues
+ * requests for N units and the allocator returns the index of the
+ * first of a contiguous set of N units or fails, returning -1.  The
+ * user frees the block of N units by calling <code>free()</code> with
+ * the index of the first unit as the argument.<p>
+ *
+ * Properties/Constraints:<ul>
+ *   <li> The allocator consumes one word per allocatable unit (plus
+ *   a fixed overhead of about 128 words).</li>
+ *   <li> The allocator can only deal with MAX_UNITS units (see below for
+ *   the value).</li>
+ * </ul>
+ *
+ * The basic data structure used by the algorithm is a large table,
+ * with one word per allocatable unit.  Each word is used in a
+ * number of different ways, some combination of "undefined" (32),
+ * "free/used" (1), "multi/single" (1), "prev" (15), "next" (15) &
+ * "size" (15) where field sizes in bits are in parenthesis.
+ * <pre>
+ *                       +-+-+-----------+-----------+
+ *                       |f|m|    prev   | next/size |
+ *                       +-+-+-----------+-----------+
+ *
+ *   - single free unit: "free", "single", "prev", "next"
+ *   - single used unit: "used", "single"
+ *    - contiguous free units
+ *     . first unit: "free", "multi", "prev", "next"
+ *     . second unit: "free", "multi", "size"
+ *     . last unit: "free", "multi", "size"
+ *    - contiguous used units
+ *     . first unit: "used", "multi", "prev", "next"
+ *     . second unit: "used", "multi", "size"
+ *     . last unit: "used", "multi", "size"
+ *    - any other unit: undefined
+ *
+ *                       +-+-+-----------+-----------+
+ *   top sentinel        |0|0|    tail   |   head    |  [-1]
+ *                       +-+-+-----------+-----------+
+ *                                     ....
+ *            /--------  +-+-+-----------+-----------+
+ *            |          |1|1|   prev    |   next    |  [j]
+ *            |          +-+-+-----------+-----------+
+ *            |          |1|1|           |   size    |  [j+1]
+ *         free multi    +-+-+-----------+-----------+
+ *         unit block    |              ...          |  ...
+ *            |          +-+-+-----------+-----------+
+ *            |          |1|1|           |   size    |
+ *           >--------  +-+-+-----------+-----------+
+ *   single free unit    |1|0|   prev    |   next    |
+ *           >--------  +-+-+-----------+-----------+
+ *   single used unit    |0|0|                       |
+ *           >--------  +-+-+-----------------------+
+ *            |          |0|1|                       |
+ *            |          +-+-+-----------+-----------+
+ *            |          |0|1|           |   size    |
+ *         used multi    +-+-+-----------+-----------+
+ *         unit block    |              ...          |
+ *            |          +-+-+-----------+-----------+
+ *            |          |0|1|           |   size    |
+ *            \--------  +-+-+-----------+-----------+
+ *                                     ....
+ *                       +-+-+-----------------------+
+ *   bottom sentinel     |0|0|                       |  [N]
+ *                       +-+-+-----------------------+
+ * </pre>
+ * The sentinels serve as guards against out of range coalescing
+ * because they both appear as "used" blocks and so will never
+ * coalesce.  The top sentinel also serves as the head and tail of
+ * the doubly linked list of free blocks.
+ */
+ at Uninterruptible
+public final class GenericFreeList extends BaseGenericFreeList implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param units The number of allocatable units for this free list
+   */
+  public GenericFreeList(int units) {
+    this(units, units);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param units The number of allocatable units for this free list
+   * @param grain Units are allocated such that they will never cross this granularity boundary
+   */
+  public GenericFreeList(int units, int grain) {
+    this(units, grain, 1);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param units The number of allocatable units for this free list
+   * @param grain Units are allocated such that they will never cross this granularity boundary
+   * @param heads The number of free lists which will share this instance
+   */
+  public GenericFreeList(int units, int grain, int heads) {
+    this.parent = null;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(units <= MAX_UNITS && heads <= MAX_HEADS);
+    this.heads = heads;
+    head = -1;
+
+    // allocate the data structure, including space for top & bottom sentinels
+    table = new int[(units + 1 + heads) << 1];
+    initializeHeap(units, grain);
+  }
+
+  /**
+   * Resize the free list for a parent free list.
+   * This must not be called dynamically (ie not after bootstrap).
+   *
+   * @param units The number of allocatable units for this free list
+   * @param grain Units are allocated such that they will never cross this granularity boundary
+   */
+  @Interruptible
+  public void resizeFreeList(int units, int grain) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(parent == null && !Plan.isInitialized());
+    table = new int[(units + 1 + heads) << 1];
+    initializeHeap(units, grain);
+  }
+
+  /**
+   * Resize the free list for a child free list.
+   * This must not be called dynamically (ie not after bootstrap).
+   */
+  @Interruptible
+  public void resizeFreeList() {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(parent != null && !Plan.isInitialized());
+    table = parent.getTable();
+  }
+
+  /**
+   * Constructor
+   *
+   * @param parent The parent, owning the data structures this instance will share
+   * @param ordinal The ordinal number of this child
+   */
+  public GenericFreeList(GenericFreeList parent, int ordinal) {
+    this.parent = parent;
+    this.table = parent.getTable();
+    this.heads = parent.getHeads();
+    this.head = -(1 + ordinal);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(-this.head <= this.heads);
+  }
+
+  /** Getter */
+  int[] getTable() { return table; }
+  int getHeads() { return heads; }
+
+  /**
+   * Initialize a unit as a sentinel
+   *
+   * @param unit The unit to be initialized
+   */
+  protected void setSentinel(int unit) {
+    setLoEntry(unit, NEXT_MASK & unit);
+    setHiEntry(unit, PREV_MASK & unit);
+  }
+
+  /**
+   * Get the size of a lump of units
+   *
+   * @param unit The first unit in the lump of units
+   * @return The size of the lump of units
+   */
+  protected int getSize(int unit) {
+    if ((getHiEntry(unit) & MULTI_MASK) == MULTI_MASK)
+      return (getHiEntry(unit + 1) & SIZE_MASK);
+    else
+      return 1;
+  }
+
+  /**
+   * Set the size of lump of units
+   *
+   * @param unit The first unit in the lump of units
+   * @param size The size of the lump of units
+   */
+  protected void setSize(int unit, int size) {
+    if (size > 1) {
+      setHiEntry(unit, getHiEntry(unit) | MULTI_MASK);
+      setHiEntry(unit + 1, MULTI_MASK | size);
+      setHiEntry(unit + size - 1, MULTI_MASK | size);
+    } else
+      setHiEntry(unit, getHiEntry(unit) & ~MULTI_MASK);
+  }
+
+  /**
+   * Establish whether a lump of units is free
+   *
+   * @param unit The first or last unit in the lump
+   * @return True if the lump is free
+   */
+  protected boolean getFree(int unit) {
+    return ((getLoEntry(unit) & FREE_MASK) == FREE_MASK);
+  }
+
+  /**
+   * Set the "free" flag for a lump of units (both the first and last
+   * units in the lump are set.
+   *
+   * @param unit The first unit in the lump
+   * @param isFree True if the lump is to be marked as free
+   */
+  protected void setFree(int unit, boolean isFree) {
+    int size;
+    if (isFree) {
+      setLoEntry(unit, getLoEntry(unit) | FREE_MASK);
+      if ((size = getSize(unit)) > 1)
+        setLoEntry(unit + size - 1, getLoEntry(unit + size - 1) | FREE_MASK);
+    } else {
+      setLoEntry(unit, getLoEntry(unit) & ~FREE_MASK);
+      if ((size = getSize(unit)) > 1)
+        setLoEntry(unit + size - 1, getLoEntry(unit + size - 1) & ~FREE_MASK);
+    }
+  }
+
+  /**
+   * Get the next lump in the doubly linked free list
+   *
+   * @param unit The index of the first unit in the current lump
+   * @return The index of the first unit of the next lump of units in the list
+   */
+  protected int getNext(int unit) {
+    int next = getHiEntry(unit) & NEXT_MASK;
+    return (next <= MAX_UNITS) ? next : head;
+  }
+
+  /**
+   * Set the next lump in the doubly linked free list
+   *
+   * @param unit The index of the first unit in the lump to be set
+   * @param next The value to be set.
+   */
+  protected void setNext(int unit, int next) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((next >= -heads) && (next <= MAX_UNITS));
+    int oldValue = getHiEntry(unit);
+    int newValue = (oldValue & ~NEXT_MASK) | (next & NEXT_MASK);
+    setHiEntry(unit, newValue);
+  }
+
+  /**
+   * Get the previous lump in the doubly linked free list
+   *
+   * @param unit The index of the first unit in the current lump
+   * @return The index of the first unit of the previous lump of units
+   * in the list
+   */
+  protected int getPrev(int unit) {
+    int prev = getLoEntry(unit) & PREV_MASK;
+    return (prev <= MAX_UNITS) ? prev : head;
+  }
+
+  /**
+   * Set the previous lump in the doubly linked free list
+   *
+   * @param unit The index of the first unit in the lump to be set
+   * @param prev The value to be set.
+   */
+  protected void setPrev(int unit, int prev) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((prev >= -heads) && (prev <= MAX_UNITS));
+    int oldValue = getLoEntry(unit);
+    int newValue = (oldValue & ~PREV_MASK) | (prev & PREV_MASK);
+    setLoEntry(unit, newValue);
+  }
+
+  /**
+   * Set the uncoalescable bit associated with this unit.
+   * This ensures this unit cannot be coalesced with units below
+   * it.
+   *
+   * @param unit The unit whose uncoalescable bit is to be set
+   */
+  public void setUncoalescable(int unit) {
+    setLoEntry(unit, getLoEntry(unit) | COALESC_MASK);
+  }
+
+  /**
+   * Clear the uncoalescable bit associated with this unit.
+   * This allows this unit to be coalesced with units below
+   * it.
+   *
+   * @param unit The unit whose uncoalescable bit is to be cleared
+   */
+  public void clearUncoalescable(int unit) {
+    setLoEntry(unit, getLoEntry(unit) & ~COALESC_MASK);
+  }
+
+  /**
+   * Return true if this unit may be coalesced with the unit below it.
+   *
+   * @param unit The unit in question
+   * @return True if this unit may be coalesced with the unit below it.
+   */
+  @Override
+  public boolean isCoalescable(int unit) {
+    return (getLoEntry(unit) & COALESC_MASK) == 0;
+  }
+
+ /**
+   * Get the lump to the "left" of the current lump (i.e. "above" it)
+   *
+   * @param unit The index of the first unit in the lump in question
+   * @return The index of the first unit in the lump to the
+   * "left"/"above" the lump in question.
+   */
+  protected int getLeft(int unit) {
+    if ((getHiEntry(unit - 1) & MULTI_MASK) == MULTI_MASK)
+      return unit - (getHiEntry(unit - 1) & SIZE_MASK);
+    else
+      return unit - 1;
+  }
+
+
+  /**
+   * Get the contents of an entry
+   *
+   * @param unit The index of the unit
+   * @return The contents of the unit
+   */
+  private int getLoEntry(int unit) {
+    return table[(unit + heads) << 1];
+  }
+  private int getHiEntry(int unit) {
+    return table[((unit + heads) << 1) + 1];
+  }
+
+  /**
+   * Set the contents of an entry
+   *
+   * @param unit The index of the unit
+   * @param value The contents of the unit
+   */
+  private void setLoEntry(int unit, int value) {
+    table[(unit + heads) << 1] = value;
+  }
+  private void setHiEntry(int unit, int value) {
+    table[((unit + heads) << 1) + 1] = value;
+  }
+
+  private static final int TOTAL_BITS = 32;
+  private static final int UNIT_BITS = (TOTAL_BITS - 2);
+  public static final int MAX_UNITS = (int) (((((long) 1) << UNIT_BITS) - 1) - MAX_HEADS - 1);
+  private static final int NEXT_MASK = (int) ((((long) 1) << UNIT_BITS) - 1);
+  private static final int PREV_MASK = (int) ((((long) 1) << UNIT_BITS) - 1);
+  private static final int FREE_MASK = 1 << (TOTAL_BITS - 1);
+  private static final int MULTI_MASK = 1 << (TOTAL_BITS - 1);
+  private static final int COALESC_MASK = 1 << (TOTAL_BITS - 2);
+  private static final int SIZE_MASK = (int) ((((long) 1) << UNIT_BITS) - 1);
+
+  private int[] table;
+  private final GenericFreeList parent;
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/Log.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/Log.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/Log.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/Log.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,842 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Error and trace logging.
+ */
+ at Uninterruptible
+public class Log implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  /**
+   * characters in the write buffer for the caller's message.  This
+   * does not include characters reserved for the overflow message.
+   *
+   * This needs to be large because Jikes RVM's implementation of Lock.java
+   * logs a lot of information when there is potential GC deadlock.
+   */
+  private static final int MESSAGE_BUFFER_SIZE = 3000;
+
+  /** message added when the write buffer has overflown */
+  private static final String OVERFLOW_MESSAGE = "... WARNING: Text truncated.\n";
+
+  private static final char OVERFLOW_MESSAGE_FIRST_CHAR = OVERFLOW_MESSAGE.charAt(0);
+
+  /** characters in the overflow message, including the (optional) final
+   * newline  */
+  private static final int OVERFLOW_SIZE = OVERFLOW_MESSAGE.length();
+
+  /**
+   * characters in buffer for building string representations of
+   * longs.  A long is a signed 64-bit integer in the range -2^63 to
+   * 2^63+1.  The number of digits in the decimal representation of
+   * 2^63 is ceiling(log10(2^63)) == ceiling(63 * log10(2)) == 19.  An
+   * extra character may be required for a minus sign (-).  So the
+   * maximum number of characters is 20.
+   */
+  private static final int TEMP_BUFFER_SIZE = 20;
+
+  /** string that prefixes numbers logged in hexadecimal */
+  private static final String HEX_PREFIX = "0x";
+
+  /**
+   * log2 of number of bits represented by a single hexidemimal digit
+   */
+  private static final int LOG_BITS_IN_HEX_DIGIT = 2;
+
+  /**
+   * log2 of number of digits in the unsigned hexadecimal
+   * representation of a byte
+   */
+  private static final int LOG_HEX_DIGITS_IN_BYTE = LOG_BITS_IN_BYTE - LOG_BITS_IN_HEX_DIGIT;
+
+  /**
+   * map of hexadecimal digit values to their character representations
+   */
+  private static final char [] hexDigitCharacter =
+  { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+  /** new line character. Emitted by writeln methods. */
+  private static final char NEW_LINE_CHAR = '\n';
+
+  /** log instance used at build time. */
+  private static Log log = new Log();
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  /** buffer to store written message until flushing */
+  private char [] buffer = new char[MESSAGE_BUFFER_SIZE + OVERFLOW_SIZE];
+
+  /** location of next character to be written */
+  private int bufferIndex = 0;
+
+  /** <code>true</code> if the buffer has overflown */
+  private boolean overflow = false;
+
+  /** The last character that was written by #addToBuffer(char).  This is
+      used to check whether we want to newline-terminate the text. */
+  private char overflowLastChar = '\0';
+
+  /** <code>true</code> if a thread id will be prepended */
+  private boolean threadIdFlag = false;
+
+  /** buffer for building string representations of longs */
+  private char[] tempBuffer = new char[TEMP_BUFFER_SIZE];
+
+  /** constructor */
+  public Log() {
+    for (int i = 0; i < OVERFLOW_SIZE; i++) {
+      buffer[MESSAGE_BUFFER_SIZE + i] = OVERFLOW_MESSAGE.charAt(i);
+    }
+  }
+
+  /**
+   * writes a boolean. Either "true" or "false" is logged.
+   *
+   * @param b boolean value to be logged.
+   */
+  public static void write(boolean b) {
+    write(b ? "true" : "false");
+  }
+
+  /**
+   * writes a character
+   *
+   * @param c character to be logged
+   */
+  public static void write(char c) {
+    add(c);
+  }
+
+  /**
+   * writes a long, in decimal.  The value is not padded and no
+   * thousands seperator is logged.  If the value is negative a
+   * leading minus sign (-) is logged.
+   *
+   *
+   * @param l long value to be logged
+   */
+  public static void write(long l) {
+    boolean negative = l < 0;
+    int nextDigit;
+    char nextChar;
+    int index = TEMP_BUFFER_SIZE - 1;
+    char[] intBuffer = getIntBuffer();
+
+    nextDigit = (int) (l % 10);
+    nextChar = hexDigitCharacter[negative ? - nextDigit : nextDigit];
+    intBuffer[index--] = nextChar;
+    l = l / 10;
+
+    while (l != 0) {
+      nextDigit = (int) (l % 10);
+      nextChar = hexDigitCharacter[negative ? - nextDigit : nextDigit];
+      intBuffer[index--] = nextChar;
+      l = l / 10;
+    }
+
+    if (negative) {
+      intBuffer[index--] = '-';
+    }
+
+    for (index++; index < TEMP_BUFFER_SIZE; index++) {
+      add(intBuffer[index]);
+    }
+  }
+
+  /**
+   * writes a <code>double</code>.  Two digits after the decimal point
+   * are always logged.  The value is not padded and no thousands
+   * seperator is used.  If the value is negative a leading
+   * hyphen-minus (-) is logged.  The decimal point is a full stop
+   * (.).
+   *
+   * @param d the double to be logged
+   */
+  public static void write(double d) { write(d, 2); }
+
+  /**
+   * writes a <code>double</code>.  The number of digits after the
+   * decimal point is determined by <code>postDecimalDigits</code>.
+   * The value is not padded and not thousands seperator is used. If
+   * the value is negative a leading hyphen-minus (-) is logged.  The
+   * decimal point is a full stop (.) and is logged even if
+   * <postDecimcalDigits</code> is zero. If <code>d</code> is greater
+   * than the largest representable value of type <code>int</code>, it
+   * is logged as "TooBig".  Similarly, if it is less than
+   * the negative of the largest representable value, it is logged as
+   * "TooSmall".  If <code>d</code> is NaN is is logged as "NaN".
+   *
+   * @param d the double to be logged
+   * @param postDecimalDigits the number of digits to be logged after
+   * the decimal point.  If less than or equal to zero no digits are
+   * logged, but the decimal point is.
+   */
+  public static void write(double d, int postDecimalDigits) {
+    if (d != d) {
+      write("NaN");
+      return;
+    }
+    if (d > Integer.MAX_VALUE) {
+      write("TooBig");
+      return;
+    }
+    if (d < -Integer.MAX_VALUE) {
+      write("TooSmall");
+      return;
+    }
+
+    boolean negative = (d < 0.0);
+    d = negative ? (-d) : d;       // Take absolute value
+    int ones = (int) d;
+    int multiplier = 1;
+    while (postDecimalDigits-- > 0)
+      multiplier *= 10;
+    int remainder = (int) (multiplier * (d - ones));
+    if (remainder < 0) remainder = 0;
+    if (negative) write('-');
+    write(ones);
+    write('.');
+    while (multiplier > 1) {
+      multiplier /= 10;
+      write(remainder / multiplier);
+      remainder %= multiplier;
+    }
+  }
+
+  /**
+   * writes an array of characters
+   *
+   * @param c the array of characters to be logged
+   */
+  public static void write(char[] c) {
+    write(c, c.length);
+  }
+
+  /**
+   * writes the start of an array of characters
+   *
+   * @param c the array of characters
+   * @param len the number of characters to be logged, starting with
+   * the first character
+   */
+  public static void write(char[] c, int len) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(len <= c.length);
+    for (int i = 0; i < len; i++) {
+      add(c[i]);
+    }
+  }
+
+  /**
+   * writes an array of bytes.  The bytes are interpretted
+   * as characters.
+   *
+   * @param b the array of bytes to be logged
+   */
+  public static void write(byte[] b) {
+    for (int i = 0; i < b.length; i++) {
+      add((char)b[i]);
+    }
+  }
+
+  /**
+   * writes a string
+   *
+   * @param s the string to be logged
+   */
+  public static void write(String s) {
+    add(s);
+  }
+
+  /**
+   * writes a word, in hexadecimal.  It is zero-padded to the size of
+   * an address.
+   *
+   * @param w the word to be logged
+   */
+  public static void write(Word w) {
+    writeHex(w, BYTES_IN_ADDRESS);
+  }
+
+  /**
+   * writes a word, in decimal.
+   *
+   * @param w the word to be logged
+   */
+  public static void writeDec(Word w) {
+    if (BYTES_IN_ADDRESS == 4) {
+      write(w.toInt());
+    } else {
+      write(w.toLong());
+    }
+  }
+
+  /**
+   * writes an address, in hexademical. It is zero-padded.
+   *
+   * @param a the address to be logged
+   */
+  public static void write(Address a) {
+    writeHex(a.toWord(), BYTES_IN_ADDRESS);
+  }
+
+  /**
+   * writes a string followed by an address, in hexademical.
+   * @see #write(String)
+   * @see #write(Address)
+   *
+   * @param s the string to be logged
+   * @param a the address to be logged
+   */
+  public static void write(String s, Address a) {
+    write(s);
+    write(a);
+  }
+
+  /**
+   * Write a string followed by a long
+   * @see #write(String)
+   * @see #write(long)
+   *
+   * @param s the string to be logged
+   * @param l the long to be logged
+   */
+  public static void write(String s, long l) {
+    write(s);
+    write(l);
+  }
+
+  /**
+   * writes an object reference, in hexademical. It is zero-padded.
+   *
+   * @param o the object reference to be logged
+   */
+  public static void write(ObjectReference o) {
+    writeHex(o.toAddress().toWord(), BYTES_IN_ADDRESS);
+  }
+
+  /**
+   * writes an offset, in hexademical. It is zero-padded.
+   *
+   * @param o the offset to be logged
+   */
+  public static void write(Offset o) {
+    writeHex(o.toWord(), BYTES_IN_ADDRESS);
+  }
+
+  /**
+   * writes an extent, in hexademical. It is zero-padded.
+   *
+   * @param e the extent to be logged
+   */
+  public static void write(Extent e) {
+    writeHex(e.toWord(), BYTES_IN_ADDRESS);
+  }
+
+  /**
+   * write a new-line and flushes the buffer
+   */
+  public static void writeln() {
+    writelnWithFlush(true);
+  }
+
+  /**
+   * writes a boolean and a new-line, then flushes the buffer.
+   * @see #write(boolean)
+   *
+   * @param b boolean value to be logged.
+   */
+  public static void writeln(boolean b) { writeln(b, true); }
+
+  /**
+   * writes a character and a new-line, then flushes the buffer.
+   * @see #write(char)
+   *
+   * @param c character to be logged
+   */
+  public static void writeln(char c)    { writeln(c, true); }
+
+  /**
+   * writes a long, in decimal, and a new-line, then flushes the buffer.
+   * @see #write(long)
+   *
+   * @param l long value to be logged
+   */
+  public static void writeln(long l)    { writeln(l, true); }
+
+  /**
+   * writes a <code>double</code> and a new-line, then flushes the buffer.
+   * @see #write(double)
+   *
+   * @param d the double to be logged
+   */
+  public static void writeln(double d)  { writeln(d, true); }
+
+  /**
+   * writes a <code>double</code> and a new-line, then flushes the buffer.
+   * @see #write(double, int)
+   *
+   * @param d the double to be logged
+   */
+  public static void writeln(double d, int postDecimalDigits) {
+    writeln(d, postDecimalDigits, true); }
+
+  /**
+   * writes an array of characters and a new-line, then flushes the buffer.
+   * @see #write(char [])
+   *
+   * @param ca the array of characters to be logged
+   */
+  public static void writeln(char [] ca) { writeln(ca, true); }
+
+  /**
+   * writes the start of an array of characters and a new-line, then
+   * flushes the buffer.
+   * @see #write(char[], int)
+   *
+   * @param ca the array of characters
+   * @param len the number of characters to be logged, starting with
+   * the first character
+   */
+  public static void writeln(char [] ca, int len) { writeln(ca, len, true); }
+
+  /**
+   * writes an array of bytes and a new-line, then
+   * flushes the buffer.
+   * @see #write(byte[])
+   *
+   * @param b the array of bytes to be logged
+   */
+  public static void writeln(byte [] b) { writeln(b, true); }
+
+  /**
+   * writes a string and a new-line, then flushes the buffer.
+   *
+   * @param s the string to be logged
+   */
+  public static void writeln(String s)  { writeln(s, true); }
+
+  /**
+   * writes a word, in hexadecimal, and a new-line, then flushes the buffer.
+   * @see #write(Word)
+   *
+   * @param w the word to be logged
+   */
+  public static void writeln(Word w) { writeln(w, true); }
+
+  /**
+   * writes an address, in hexademical, and a new-line, then flushes
+   * the buffer.
+   * @see #write(Address)
+   *
+   * @param a the address to be logged
+   */
+  public static void writeln(Address a) { writeln(a, true); }
+
+  /**
+   * writes an object reference, in hexademical, and a new-line, then
+   * flushes the buffer.
+   * @see #write(ObjectReference)
+   *
+   * @param o the object reference to be logged
+   */
+  public static void writeln(ObjectReference o) { writeln(o, true); }
+
+  /**
+   * writes an offset, in hexademical, and a new-line, then flushes the buffer.
+   * @see #write(Offset)
+   *
+   * @param o the offset to be logged
+   */
+  public static void writeln(Offset o) { writeln(o, true); }
+
+  /**
+   * writes an extent, in hexademical, and a new-line, then flushes the buffer.
+   * @see #write(Extent)
+   *
+   * @param e the extent to be logged
+   */
+  public static void writeln(Extent e) { writeln(e, true); }
+
+  /**
+   * writes a new-line without flushing the buffer
+   */
+  public static void writelnNoFlush() {
+    writelnWithFlush(false);
+  }
+
+  /**
+   * writes a boolean and a new-line, then optionally flushes the buffer.
+   * @see #write(boolean)
+   *
+   * @param b boolean value to be logged.
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(boolean b, boolean flush) {
+    write(b);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes a character and a new-line, then optionally flushes the
+   * buffer.
+   * @see #write(char)
+   *
+   * @param c character to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(char c, boolean flush) {
+    write(c);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes a long, in decimal, and a new-line, then optionally flushes
+   * the buffer.
+   * @see #write(long)
+   *
+   * @param l long value to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(long l, boolean flush) {
+    write(l);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes a <code>double</code> and a new-line, then optionally flushes
+   * the buffer.
+   * @see #write(double)
+   *
+   * @param d the double to be logged
+   * @param flush if <code>true</code> then flush the buffer
+   */
+  public static void writeln(double d, boolean flush) {
+    write(d);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes a <code>double</code> and a new-line, then optionally flushes
+   * the buffer.
+   * @see #write(double, int)
+   *
+   * @param d the double to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(double d, int postDecimalDigits, boolean flush) {
+    write(d, postDecimalDigits);
+    writelnWithFlush(flush);
+  }
+
+
+  /**
+   * writes an array of characters and a new-line, then optionally
+   * flushes the buffer.
+   * @see #write(char [])
+   *
+   * @param ca the array of characters to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(char[] ca, boolean flush) {
+    write(ca);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes the start of an array of characters and a new-line, then
+   * optionally flushes the buffer.
+   * @see #write(char[], int)
+   *
+   * @param ca the array of characters
+   * @param len the number of characters to be logged, starting with
+   * the first character
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(char[] ca, int len, boolean flush) {
+    write(ca, len);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes an array of bytes and a new-line, then optionally flushes the
+   * buffer.
+   * @see #write(byte[])
+   *
+   * @param b the array of bytes to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(byte[] b, boolean flush) {
+    write(b);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes a string and a new-line, then optionally flushes the buffer.
+   *
+   * @param s the string to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(String s, boolean flush) {
+    write(s);
+    writelnWithFlush(flush);
+  }
+
+  public static void writeln(String s, long l) {
+    write(s);
+    writeln(l);
+  }
+
+
+  /**
+   * writes a word, in hexadecimal, and a new-line, then optionally
+   * flushes the buffer.
+   * @see #write(Word)
+   *
+   * @param w the word to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(Word w, boolean flush) {
+    write(w);
+    writelnWithFlush(flush);
+  }
+
+
+  /**
+   * writes an address, in hexademical, and a new-line, then optionally
+   * flushes the buffer.
+   * @see #write(Address)
+   *
+   * @param a the address to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(Address a, boolean flush) {
+    write(a);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes an object reference, in hexademical, and a new-line, then
+   * optionally flushes the buffer.
+   * @see #write(ObjectReference)
+   *
+   * @param o the object reference to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(ObjectReference o, boolean flush) {
+    write(o);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes an offset, in hexademical, and a new-line, then optionally
+   * flushes the buffer.
+   * @see #write(Offset)
+   *
+   * @param o the offset to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(Offset o, boolean flush) {
+    write(o);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes an extent, in hexademical, and a new-line, then optionally
+   * flushes the buffer.
+   * @see #write(Extent)
+   *
+   * @param e the extent to be logged
+   * @param flush if <code>true</code> then flushes the buffer
+   */
+  public static void writeln(Extent e, boolean flush) {
+    write(e);
+    writelnWithFlush(flush);
+  }
+
+  /**
+   * writes a string followed by a Address
+   * @see #write(String)
+   * @see #write(Address)
+   *
+   * @param s the string to be logged
+   * @param a the Address to be logged
+   */
+  public static void writeln(String s, Address a) {
+    write(s);
+    writeln(a);
+  }
+
+  /**
+   * Log a thread identifier at the start of the next message flushed.
+   */
+  public static void prependThreadId() {
+    getLog().setThreadIdFlag();
+  }
+
+  /**
+   * flushes the buffer.  The buffered effected of writes since the last
+   * flush will be logged in one block without output from other
+   * thread's logging interleaving.
+   */
+  public static void flush() {
+    getLog().flushBuffer();
+  }
+
+  /**
+   * writes a new-line and optionally flushes the buffer
+   *
+   * @param flush if <code>true</code> the buffer is flushed
+   */
+  private static void writelnWithFlush(boolean flush) {
+    add(NEW_LINE_CHAR);
+    if (flush) {
+      flush();
+    }
+  }
+
+  /**
+   * writes a <code>long</code> in hexadecimal
+   *
+   * @param w the Word to be logged
+   * @param bytes the number of bytes from the long to be logged.  If
+   * less than 8 then the least significant bytes are logged and some
+   * of the most significant bytes are ignored.
+   */
+  private static void writeHex(Word w, int bytes) {
+    int hexDigits = bytes * (1 << LOG_HEX_DIGITS_IN_BYTE);
+    int nextDigit;
+
+    write(HEX_PREFIX);
+
+    for (int digitNumber = hexDigits - 1; digitNumber >= 0; digitNumber--) {
+      nextDigit = w.rshl(digitNumber << LOG_BITS_IN_HEX_DIGIT).toInt() & 0xf;
+      char nextChar = hexDigitCharacter[nextDigit];
+      add(nextChar);
+    }
+  }
+
+  /**
+   * adds a character to the buffer
+   *
+   * @param c the character to add
+   */
+  private static void add(char c) {
+    getLog().addToBuffer(c);
+  }
+
+  /**
+   * adds a string to the buffer
+   *
+   * @param s the string to add
+   */
+  private static void add(String s) {
+    getLog().addToBuffer(s);
+  }
+
+  private static Log getLog() {
+    if (VM.assertions.runningVM()) {
+      return VM.activePlan.log();
+    } else {
+      return log;
+    }
+  }
+
+  /**
+   * adds a character to the buffer
+   *
+   * @param c the character to add
+   */
+  private void addToBuffer(char c) {
+    if (bufferIndex < MESSAGE_BUFFER_SIZE) {
+      buffer[bufferIndex++] = c;
+    } else {
+      overflow = true;
+      overflowLastChar = c;
+    }
+  }
+
+  /**
+   * adds a string to the buffer
+   *
+   * @param s the string to add
+   */
+  private void addToBuffer(String s) {
+    if (bufferIndex < MESSAGE_BUFFER_SIZE) {
+      bufferIndex += VM.strings.copyStringToChars(s, buffer, bufferIndex, MESSAGE_BUFFER_SIZE + 1);
+      if (bufferIndex == MESSAGE_BUFFER_SIZE + 1) {
+        overflow = true;
+        // We don't bother setting OVERFLOW_LAST_CHAR, since we don't have an
+        // MMTk method that lets us peek into a string. Anyway, it's just a
+        // convenience to get the newline right.
+        buffer[MESSAGE_BUFFER_SIZE] = OVERFLOW_MESSAGE_FIRST_CHAR;
+        bufferIndex--;
+      }
+    } else {
+      overflow = true;
+    }
+  }
+
+  /**
+   * flushes the buffer
+   */
+  private void flushBuffer() {
+    int newlineAdjust = overflowLastChar == NEW_LINE_CHAR ? 0 : -1;
+    int totalMessageSize = overflow ? (MESSAGE_BUFFER_SIZE + OVERFLOW_SIZE + newlineAdjust) : bufferIndex;
+    if (threadIdFlag) {
+      VM.strings.writeThreadId(buffer, totalMessageSize);
+    } else {
+      VM.strings.write(buffer, totalMessageSize);
+    }
+    threadIdFlag = false;
+    overflow = false;
+    overflowLastChar = '\0';
+    bufferIndex = 0;
+  }
+
+  /**
+   * sets the flag so that a thread identifier will be included before
+   * the logged message
+   */
+  private void setThreadIdFlag() {
+    threadIdFlag = true;
+  }
+
+  /**
+   * gets the buffer for building string representations of integers.
+   * There is one of these buffers for each Log instance.
+   */
+  private static char[] getIntBuffer() {
+    return getLog().getTempBuffer();
+  }
+
+  /**
+   * gets the buffer for building string representations of integers.
+   */
+  private char[] getTempBuffer() {
+    return tempBuffer;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/Memory.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/Memory.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/Memory.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/Memory.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,216 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements basic memory copying, setting and clearing
+ * operations.
+ *
+ * NOTE: Most of the operations in this class are performed at teh
+ * granularity of a Java integer (ie 4-byte units)
+ *
+ * FIXME: Why can't these operations be performed at word-granularity?
+ */
+ at Uninterruptible
+public class Memory implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  /** zero operations greater than this size are done using the
+   * underlying OS implementation of zero() */
+  private static final int SMALL_REGION_THRESHOLD = 1<<8; // empirically chosen
+
+
+  /****************************************************************************
+   *
+   * Basic memory setting and zeroing operations
+   */
+
+  /**
+   * Zero a region of memory
+   *
+   * @param start The start of the region to be zeroed (must be 4-byte aligned)
+   * @param bytes The number of bytes to be zeroed (must be 4-byte aligned)
+   */
+  @Inline
+  public static void zero(Address start, Extent bytes) {
+    if (VM.VERIFY_ASSERTIONS) {
+      assertAligned(start);
+      assertAligned(bytes);
+    }
+    if (bytes.GT(Extent.fromIntZeroExtend(SMALL_REGION_THRESHOLD)))
+      VM.memory.zero(start, bytes);
+    else
+      zeroSmall(start, bytes);
+  }
+
+  /**
+   * Zero a small region of memory
+   *
+   * @param start The start of the region to be zeroed (must be 4-byte aligned)
+   * @param bytes The number of bytes to be zeroed (must be 4-byte aligned)
+   */
+  @Inline
+  public static void zeroSmall(Address start, Extent bytes) {
+    if (VM.VERIFY_ASSERTIONS) {
+      assertAligned(start);
+      assertAligned(bytes);
+    }
+    Address end = start.plus(bytes);
+    for (Address addr = start; addr.LT(end); addr = addr.plus(BYTES_IN_INT))
+      addr.store(0);
+  }
+
+  /**
+   * Set a region of memory
+   *
+   * @param start The start of the region to be zeroed (must be 4-byte aligned)
+   * @param bytes The number of bytes to be zeroed (must be 4-byte aligned)
+   * @param value The value to which the integers in the region should be set
+   */
+  @Inline
+  public static void set(Address start, int bytes, int value) {
+    if (VM.VERIFY_ASSERTIONS) {
+      assertAligned(start);
+      assertAligned(bytes);
+    }
+    Address end = start.plus(bytes);
+    for (Address addr = start; addr.LT(end); addr = addr.plus(BYTES_IN_INT))
+      addr.store(value);
+  }
+
+
+  /****************************************************************************
+   *
+   * Helper methods
+   */
+
+  /**
+   * Check that a memory range is zeroed
+   *
+   * @param start The start address of the range to be checked
+   * @param bytes The size of the region to be checked, in bytes
+   * @return True if the region is zeroed
+   */
+  @Inline
+  public static boolean IsZeroed(Address start, int bytes) {
+    return isSet(start, bytes, false, 0);
+  }
+
+  /**
+   * Assert that a memory range is zeroed.  An assertion failure will
+   * occur if the region is not zeroed.
+   *
+   * this is in the inline allocation sequence when
+   * VM.VERIFY_ASSERTIONS is true, it is carefully written to
+   * reduce the impact on code space.
+   *
+   * @param start The start address of the range to be checked
+   * @param bytes The size of the region to be checked, in bytes
+   */
+  @NoInline
+  public static void assertIsZeroed(Address start, int bytes) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isSet(start, bytes, true, 0));
+  }
+
+  /**
+   * Verbosely check and return true if a memory range is set to some
+   * integer value
+   *
+   * @param start The start address of the range to be checked
+   * @param bytes The size of the region to be checked, in bytes
+   * @param value The value to which this region should be set
+   * @return True if the region has been correctly set
+   */
+  @Inline
+  public static boolean isSet(Address start, int bytes, int value) {
+    return isSet(start, bytes, true, value);
+  }
+
+  /**
+   * Assert appropriate alignment, triggering an assertion failure if
+   * the value does not satisify the alignment requirement of the
+   * memory operations.
+   *
+   * @param value The value to be tested
+   */
+  private static void assertAligned(int value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((value & (BYTES_IN_INT - 1)) == 0);
+  }
+
+  private static void assertAligned(Word value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(Word.fromIntSignExtend(BYTES_IN_INT-1)).isZero());
+  }
+
+  private static void assertAligned(Extent value) {
+    assertAligned(value.toWord());
+  }
+
+  private static void assertAligned(Address value) {
+    assertAligned(value.toWord());
+  }
+
+  /**
+   * Test whether a memory range is set to a given integer value
+   *
+   * @param start The address to start checking at
+   * @param bytes The size of the region to check, in bytes
+   * @param verbose If true, produce verbose output
+   * @param value The value to which the memory should be set
+   */
+  @NoInline
+  private static boolean isSet(Address start, int bytes, boolean verbose,
+      int value)
+    /* Inlining this loop into the uninterruptible code can
+     *  cause/encourage the GCP into moving a get_obj_tib into the
+     * interruptible region where the tib is being installed via an
+     * int_store
+   */ {
+    if (VM.VERIFY_ASSERTIONS) assertAligned(bytes);
+    for (int i = 0; i < bytes; i += BYTES_IN_INT)
+      if (start.loadInt(Offset.fromIntSignExtend(i)) != value) {
+        if (verbose) {
+          Log.prependThreadId();
+          Log.write("VM range does not contain only value ");
+          Log.writeln(value);
+          Log.write("Non-zero range: "); Log.write(start);
+          Log.write(" .. "); Log.writeln(start.plus(bytes));
+          Log.write("First bad value at "); Log.writeln(start.plus(i));
+          dumpMemory(start, 0, bytes);
+        }
+        return false;
+      }
+    return true;
+  }
+
+  /**
+   * Dump the contents of memory around a given address
+   *
+   * @param addr The address around which the memory should be dumped
+   * @param beforeBytes The number of bytes before the address to be
+   * included in the dump
+   * @param afterBytes The number of bytes after the address to be
+   * included in the dump
+   */
+  public static void dumpMemory(Address addr, int beforeBytes, int afterBytes) {
+    VM.memory.dumpMemory(addr, beforeBytes, afterBytes);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/SimpleHashtable.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/SimpleHashtable.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/SimpleHashtable.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/SimpleHashtable.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,232 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.policy.RawPageSpace;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements a simple hashtable. It is intended for use
+ * in sanity checking or debugging, not high-performance algorithms.<p>
+ *
+ * This class is not thread safe.
+ */
+ at Uninterruptible public abstract class SimpleHashtable implements Constants {
+  /** The number of low order bits to ignore */
+  private static final int HASH_SHIFT = 3;
+
+  /** Offset to the key */
+  private static final Offset KEY_OFFSET = Offset.zero();
+
+  /** Offset to the data */
+  private static final Offset DATA_OFFSET = Offset.fromIntSignExtend(BYTES_IN_WORD);
+
+  /** The size of each entry in the table */
+  private final Extent entrySize;
+
+  /** The mask to use to get the hash code */
+  private final Word mask;
+
+  /** The start address of the data table */
+  private Address base;
+
+  /** The full size of the table */
+  private final Extent size;
+
+  /** The space to use for allocating the data structure */
+  private final RawPageSpace space;
+
+  /** Is this table valid (created) */
+  private boolean valid;
+
+  /**
+   * Create a new data table of a specified size.
+   *
+   * @param rps The space to acquire the data structure from.
+   * @param logSize The log of the number of table entries.
+   * @param es The size of each entry.
+   */
+  protected SimpleHashtable(RawPageSpace rps, int logSize, Extent es) {
+    mask = Word.fromIntZeroExtend((1 << logSize) - 1);
+    entrySize = es.plus(BYTES_IN_WORD);
+    size = Extent.fromIntZeroExtend((1 << logSize) * entrySize.toInt());
+    base = Address.zero();
+    space = rps;
+    valid = false;
+  }
+
+  /**
+   * Create a (zeroed) table.
+   */
+  public final void acquireTable() {
+    base = space.acquire(Conversions.bytesToPages(size));
+    VM.memory.zero(base, size);
+    valid = true;
+  }
+
+  /**
+   * Drop the table (after collection).
+   */
+  public final void releaseTable() {
+    space.release(base);
+    valid = false;
+  }
+
+  /**
+   * @return True if this table has backing data and is ready for use.
+   */
+  public final boolean isValid() {
+    return valid;
+  }
+
+  /**
+   * Retrieve a pointer to the entry for the given object, or zero if one
+   * does not exist, unless create is passed.<p>
+   *
+   * If create is true, the return is guaranteed to be non-null.
+   *
+   * @param key The key used to lookup.
+   * @param create Create a new entry if not found.
+   * @return A pointer to the reference or null.
+   */
+  @Inline
+  public final Address getEntry(Word key, boolean create) {
+    int startIndex = computeHash(key);
+    int index = startIndex;
+    Word curAddress;
+    Address entry;
+    do {
+      entry = getEntry(index);
+      curAddress = entry.loadWord(KEY_OFFSET);
+      index = (index + 1) & mask.toInt();
+    } while(curAddress.NE(key) &&
+            !curAddress.isZero() &&
+            index != startIndex);
+
+    if (index == startIndex) {
+      VM.assertions.fail("No room left in table!");
+    }
+
+    if (curAddress.isZero()) {
+      if (!create) return Address.zero();
+      entry.store(key, KEY_OFFSET);
+    }
+
+    return entry;
+  }
+
+  /**
+   * Compute the hashtable index for a given object.
+   *
+   * @param key The key.
+   * @return The index.
+   */
+  @Inline
+  private int computeHash(Word key) {
+    return key.rshl(HASH_SHIFT).and(mask).toInt();
+  }
+
+  /**
+   * Return the address of a specified entry in the table.
+   *
+   * @param index The index of the entry.
+   * @return An address to the entry.
+   */
+  @Inline
+  private Address getEntry(int index) {
+    return base.plus(Extent.fromIntZeroExtend(index * entrySize.toInt()));
+  }
+
+  /**
+   * Does the passed object have an entry in the table?
+   *
+   * @param key The key to find an entry for
+   * @return True if there is an entry for that object.
+   */
+  public final boolean contains(Word key) {
+    return !getEntry(key, false).isZero();
+  }
+
+  /**
+   * @return The first non-zero element in the table, or null if
+   * the table is empty.
+   */
+  public final Address getFirst() {
+    return getNext(base.minus(entrySize));
+  }
+
+  /**
+   * The next element in the table after the passed entry, or
+   * null if it is the last entry.
+   *
+   * @param curr The object to look for the next entry from.
+   * @return The next entry or null.
+   */
+  public final Address getNext(Address curr) {
+    Address entry = curr.plus(entrySize);
+    while (entry.LT(base.plus(size))) {
+      if (!entry.loadWord().isZero()) return entry;
+      entry = entry.plus(entrySize);
+    }
+    return Address.zero();
+  }
+
+  /**
+   * Given an address of an entry, return a pointer to the payload.
+   *
+   * @param entry The entry
+   * @return The object reference.
+   */
+  public static Address getPayloadAddress(Address entry) {
+    return entry.plus(DATA_OFFSET);
+  }
+
+  /**
+   * Given a key, return a pointer to the payload.
+   *
+   * @param key The key
+   * @return The object reference.
+   */
+  public final Address getPayloadAddress(Word key) {
+    Address entry = getEntry(key, false);
+    if (entry.isZero()) return Address.zero();
+
+    return entry.plus(DATA_OFFSET);
+  }
+
+
+  /**
+   * Return the key for a given entry.
+   *
+   * @param entry The entry.
+   * @return The key.
+   */
+  public static Word getKey(Address entry) {
+    return entry.loadWord(KEY_OFFSET);
+  }
+
+  /**
+   * Update the key for a given entry. This operation is not
+   * safe without rehashing
+   *
+   * @param entry The entry to update.
+   * @param key The new key.
+   */
+  public static void replaceKey(Address entry, Word key) {
+    entry.store(key, KEY_OFFSET);
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/Synchronize.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/Synchronize.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/Synchronize.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/Synchronize.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,22 @@
+/*
+ *  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.mmtk.utility;
+
+import org.vmmagic.pragma.*;
+
+/*
+ */
+ at Uninterruptible public class Synchronize{
+
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/TraceGenerator.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/TraceGenerator.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/TraceGenerator.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/TraceGenerator.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,410 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.plan.semispace.gctrace.GCTrace;
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.deque.*;
+import org.mmtk.utility.options.Options;
+import org.mmtk.utility.options.TraceRate;
+
+import org.mmtk.vm.VM;
+import org.mmtk.vm.Collection;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * Class that supports scanning Objects and Arrays for references
+ * during tracing, handling those references, and computing death times
+ */
+ at Uninterruptible public final class TraceGenerator
+  implements Constants, TracingConstants {
+
+
+  /***********************************************************************
+   *
+   * Class variables
+   */
+
+  /* Type of lifetime analysis to be used */
+  public static final boolean MERLIN_ANALYSIS = true;
+
+  /* include the notion of build-time allocation to our list of allocators */
+  private static final int ALLOC_BOOT = GCTrace.ALLOCATORS;
+  private static final int ALLOCATORS = ALLOC_BOOT + 1;
+
+  /* Fields for tracing */
+  private static SortTODSharedDeque tracePool; // Buffers to hold raw trace
+  private static TraceBuffer trace;
+  private static boolean traceBusy; // If we are building the trace
+  private static Word lastGC; // Last time GC was performed
+  private static ObjectReferenceArray objectLinks; // Lists of active objs
+
+  /* Fields needed for Merlin lifetime analysis */
+  private static SortTODSharedDeque workListPool; // Holds objs to process
+  private static SortTODObjectReferenceStack worklist; // Objs to process
+  private static Word agePropagate; // Death time propagating
+
+  static {
+    traceBusy = false;
+    lastGC = Word.fromIntZeroExtend(4);
+    Options.traceRate = new TraceRate();
+  }
+
+
+  /***********************************************************************
+   *
+   * Public analysis methods
+   */
+
+  /**
+   * This is called at "build-time" and passes the necessary build image
+   * objects to the trace processor.
+   *
+   * @param worklist_ The dequeue that serves as the worklist for
+   * death time propagation
+   * @param trace_ The dequeue used to store and then output the trace
+   */
+  @Interruptible
+  public static void init(SortTODSharedDeque worklist_,
+                                SortTODSharedDeque trace_) {
+    /* Objects are only needed for merlin tracing */
+    if (MERLIN_ANALYSIS) {
+      workListPool = worklist_;
+      worklist = new SortTODObjectReferenceStack(workListPool);
+    }
+
+    /* Trace objects */
+    tracePool = trace_;
+    trace = new TraceBuffer(tracePool);
+    objectLinks = ObjectReferenceArray.create(Space.MAX_SPACES);
+  }
+
+  /**
+   * This is called immediately before Jikes terminates.  It will perform
+   * any death time processing that the analysis requires and then output
+   * any remaining information in the trace buffer.
+   *
+   * @param value The integer value for the reason Jikes is terminating
+   */
+  public static void notifyExit(int value) {
+    if (MERLIN_ANALYSIS)
+      findDeaths();
+    trace.process();
+  }
+
+  /**
+   * Add a newly allocated object into the linked list of objects in a region.
+   * This is typically called after each object allocation.
+   *
+   * @param ref The address of the object to be added to the linked list
+   * @param linkSpace The region to which the object should be added
+   */
+  public static void addTraceObject(ObjectReference ref, int linkSpace) {
+    VM.traceInterface.setLink(ref, objectLinks.get(linkSpace));
+    objectLinks.set(linkSpace, ref);
+  }
+
+  /**
+   * Do the work necessary following each garbage collection. This HAS to be
+   * called after EACH collection.
+   */
+  public static void postCollection() {
+    /* Find and output the object deaths */
+    traceBusy = true;
+    findDeaths();
+    traceBusy = false;
+    trace.process();
+  }
+
+
+  /***********************************************************************
+   *
+   * Trace generation code
+   */
+
+  /**
+   * Add the information in the bootImage to the trace.  This should be
+   * called before any allocations and pointer updates have occured.
+   *
+   * @param bootStart The address at which the bootimage starts
+   */
+  public static void boot(Address bootStart) {
+    Word nextOID = VM.traceInterface.getOID();
+    ObjectReference trav = VM.traceInterface.getBootImageLink().plus(bootStart.toWord().toOffset()).toObjectReference();
+    objectLinks.set(ALLOC_BOOT, trav);
+    /* Loop through all the objects within boot image */
+    while (!trav.isNull()) {
+      ObjectReference next = VM.traceInterface.getLink(trav);
+      Word thisOID = VM.traceInterface.getOID(trav);
+      /* Add the boot image object to the trace. */
+      trace.push(TRACE_BOOT_ALLOC);
+      trace.push(thisOID);
+      trace.push(nextOID.minus(thisOID).lsh(LOG_BYTES_IN_ADDRESS));
+      nextOID = thisOID;
+      /* Move to the next object & adjust for starting address of
+         the bootImage */
+      if (!next.isNull()) {
+        next = next.toAddress().plus(bootStart.toWord().toOffset()).toObjectReference();
+        VM.traceInterface.setLink(trav, next);
+      }
+      trav = next;
+    }
+  }
+
+  /**
+   * Do any tracing work required at each a pointer store operation.  This
+   * will add the pointer store to the trace buffer and, when Merlin lifetime
+   * analysis is being used, performs the necessary timestamping.
+   *
+   * @param isScalar If this is a pointer store to a scalar object
+   * @param src The address of the source object
+   * @param slot The address within <code>src</code> into which
+   * <code>tgt</code> will be stored
+   * @param tgt The target of the pointer store
+   */
+  @NoInline
+  public static void processPointerUpdate(boolean isScalar,
+                                          ObjectReference src,
+                                          Address slot, ObjectReference tgt) {
+    // The trace can be busy only if this is a pointer update as a result of
+    // the garbage collection needed by tracing. For the moment, we will
+    // not report these updates.
+    if (!traceBusy) {
+      /* Process the old target potentially becoming unreachable when needed. */
+      if (MERLIN_ANALYSIS) {
+        ObjectReference oldTgt = slot.loadObjectReference();
+        if (!oldTgt.isNull())
+          VM.traceInterface.updateDeathTime(oldTgt);
+      }
+
+      traceBusy = true;
+      /* Add the pointer store to the trace */
+      Offset traceOffset = VM.traceInterface.adjustSlotOffset(isScalar, src, slot);
+      if (isScalar)
+        trace.push(TRACE_FIELD_SET);
+      else
+        trace.push(TRACE_ARRAY_SET);
+      trace.push(VM.traceInterface.getOID(src));
+      trace.push(traceOffset.toWord());
+      if (tgt.isNull())
+        trace.push(Word.zero());
+      else
+        trace.push(VM.traceInterface.getOID(tgt));
+      traceBusy = false;
+    }
+  }
+
+  /**
+   * Do any tracing work required at each object allocation. This will add the
+   * object allocation to the trace buffer, triggers the necessary collection
+   * work at exact allocations, and output the data in the trace buffer.
+   *
+   * @param ref The address of the object just allocated.
+   * @param typeRef the type reference for the instance being created
+   * @param bytes The size of the object being allocated
+   */
+  @LogicallyUninterruptible
+  @NoInline
+  public static void traceAlloc(boolean isImmortal, ObjectReference ref,
+      ObjectReference typeRef, int bytes) {
+    boolean gcAllowed = VM.traceInterface.gcEnabled() && Plan.isInitialized() && !Plan.gcInProgress();
+    /* Test if it is time/possible for an exact allocation. */
+    Word oid = VM.traceInterface.getOID(ref);
+    Word allocType;
+    if (gcAllowed && (oid.GE(lastGC.plus(Word.fromIntZeroExtend(Options.traceRate.getValue())))))
+      allocType = TRACE_EXACT_ALLOC;
+    else {
+      allocType = TRACE_ALLOC;
+    }
+    /* Add the allocation into the trace. */
+    traceBusy = true;
+    /* When legally permissible, add the record to the trace buffer */
+    if (MERLIN_ANALYSIS) {
+       Address fp = (TraceBuffer.OMIT_ALLOCS) ? Address.zero() : VM.traceInterface.skipOwnFramesAndDump(typeRef);
+
+       if (isImmortal && allocType.EQ(TRACE_EXACT_ALLOC))
+         trace.push(TRACE_EXACT_IMMORTAL_ALLOC);
+       else if (isImmortal)
+         trace.push(TRACE_IMMORTAL_ALLOC);
+       else
+         trace.push(allocType);
+       trace.push(VM.traceInterface.getOID(ref));
+       trace.push(Word.fromIntZeroExtend(bytes - VM.traceInterface.getHeaderSize()));
+       trace.push(fp.toWord());
+       trace.push(Word.zero()); /* Magic.getThreadId() */
+       trace.push(TRACE_TIB_SET);
+       trace.push(VM.traceInterface.getOID(ref));
+       trace.push(VM.traceInterface.getOID(typeRef));
+    }
+    /* Perform the necessary work for death times. */
+    if (allocType.EQ(TRACE_EXACT_ALLOC)) {
+      if (MERLIN_ANALYSIS) {
+        lastGC = VM.traceInterface.getOID(ref);
+        VM.traceInterface.updateTime(lastGC);
+        VM.collection.triggerCollection(Collection.INTERNAL_GC_TRIGGER);
+      } else {
+        VM.collection.triggerCollection(Collection.RESOURCE_GC_TRIGGER);
+        lastGC = VM.traceInterface.getOID(ref);
+      }
+    }
+    /* Add the allocation record to the buffer if we have not yet done so. */
+    if (!MERLIN_ANALYSIS) {
+       Address fp = (TraceBuffer.OMIT_ALLOCS) ? Address.zero() : VM.traceInterface.skipOwnFramesAndDump(typeRef);
+       if (isImmortal && allocType.EQ(TRACE_EXACT_ALLOC))
+         trace.push(TRACE_EXACT_IMMORTAL_ALLOC);
+       else if (isImmortal)
+         trace.push(TRACE_IMMORTAL_ALLOC);
+       else
+         trace.push(allocType);
+       trace.push(VM.traceInterface.getOID(ref));
+       trace.push(Word.fromIntZeroExtend(bytes - VM.traceInterface.getHeaderSize()));
+       trace.push(fp.toWord());
+       trace.push(Word.zero()); /* Magic.getThreadId() */
+       trace.push(TRACE_TIB_SET);
+       trace.push(VM.traceInterface.getOID(ref));
+       trace.push(VM.traceInterface.getOID(typeRef));
+    }
+    trace.process();
+    traceBusy = false;
+  }
+
+  /***********************************************************************
+   *
+   * Merlin lifetime analysis methods
+   */
+
+  /**
+   * This computes and adds to the trace buffer the unreachable time for
+   * all of the objects that are _provably_ unreachable.  This method
+   * should be called after garbage collection (but before the space has
+   * been reclaimed) and at program termination.
+   */
+  private static void findDeaths() {
+    /* Only the merlin analysis needs to compute death times */
+    if (MERLIN_ANALYSIS) {
+      /* Start with an empty stack. */
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(worklist.isEmpty());
+      /* Scan the linked list of objects within each region */
+      for (int allocator = 0; allocator < ALLOCATORS; allocator++) {
+        ObjectReference thisRef = objectLinks.get(allocator);
+        /* Start at the top of each linked list */
+        while (!thisRef.isNull()) {
+          /* Add the unreachable objects onto the worklist. */
+          if (!getTraceLocal().isReachable(thisRef))
+            worklist.push(thisRef);
+          thisRef = VM.traceInterface.getLink(thisRef);
+        }
+      }
+      /* Sort the objects on the worklist by their timestamp */
+      if (!worklist.isEmpty())
+        worklist.sort();
+      /* Now compute the death times. */
+      computeTransitiveClosure();
+    }
+    /* Output the death times for each object */
+    for (int allocator = 0; allocator < ALLOCATORS; allocator++) {
+      ObjectReference thisRef = objectLinks.get(allocator);
+      ObjectReference prevRef = ObjectReference.nullReference(); // the last live object seen
+      while (!thisRef.isNull()) {
+        ObjectReference nextRef = VM.traceInterface.getLink(thisRef);
+        /* Maintain reachable objects on the linked list of allocated objects */
+        if (getTraceLocal().isReachable(thisRef)) {
+          thisRef = getTraceLocal().getForwardedReference(thisRef);
+          VM.traceInterface.setLink(thisRef, prevRef);
+          prevRef = thisRef;
+        } else {
+          /* For brute force lifetime analysis, objects become
+             unreachable "now" */
+          Word deadTime;
+          if (MERLIN_ANALYSIS)
+            deadTime = VM.traceInterface.getDeathTime(thisRef);
+          else
+            deadTime = lastGC;
+          /* Add the death record to the trace for unreachable objects. */
+          trace.push(TRACE_DEATH);
+          trace.push(VM.traceInterface.getOID(thisRef));
+          trace.push(deadTime);
+        }
+        thisRef = nextRef;
+      }
+      /* Purge the list of unreachable objects... */
+      objectLinks.set(allocator, prevRef);
+    }
+  }
+
+  /**
+   * This method is called for each root-referenced object at every Merlin
+   * root enumeration.  The method will update the death time of the parameter
+   * to the current trace time.
+   *
+   * @param obj The root-referenced object
+   */
+  public static void rootEnumerate(ObjectReference obj) {
+    VM.traceInterface.updateDeathTime(obj);
+  }
+
+  /**
+   * This propagates the death time being computed to the object passed as an
+   * address. If we find the unreachable time for the parameter, it will be
+   * pushed on to the processing stack.
+   *
+   * @param ref The address of the object to examine
+   */
+  public static void propagateDeathTime(ObjectReference ref) {
+    /* If this death time is more accurate, set it. */
+    if (VM.traceInterface.getDeathTime(ref).LT(agePropagate)) {
+      /* If we should add the object for further processing. */
+      if (!getTraceLocal().isReachable(ref)) {
+        VM.traceInterface.setDeathTime(ref, agePropagate);
+        worklist.push(ref);
+      } else {
+        VM.traceInterface.setDeathTime(getTraceLocal().getForwardedReference(ref), agePropagate);
+      }
+    }
+  }
+
+  /**
+   * This finds all object death times by computing the (limited)
+   * transitive closure of the dead objects.  Death times are computed
+   * as the latest reaching death time to an object.
+   */
+  private static void computeTransitiveClosure() {
+     if (!worklist.isEmpty()) {
+       /* The latest time an object can die. */
+       agePropagate = Word.max();
+       /* Process through the entire buffer. */
+       ObjectReference ref = worklist.pop();
+       while (!ref.isNull()) {
+         Word currentAge = VM.traceInterface.getDeathTime(ref);
+         /* This is a cheap and simple test to process objects only once. */
+         if (currentAge.LE(agePropagate)) {
+           /* Set the "new" dead age. */
+           agePropagate = currentAge;
+           /* Scan the object, pushing the survivors */
+           VM.scanning.scanObject(getTraceLocal(), ref);
+         }
+         /* Get the next object to process */
+         ref = worklist.pop();
+       }
+     }
+  }
+
+  private static TraceLocal getTraceLocal() {
+    return VM.activePlan.collector().getCurrentTrace();
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/TracingConstants.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/TracingConstants.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/TracingConstants.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/TracingConstants.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,41 @@
+/*
+ *  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.mmtk.utility;
+
+import org.vmmagic.unboxed.*;
+
+/**
+ * The constants needed when storing events and then generating the trace.
+ */
+public interface TracingConstants {
+  Word TRACE_EXACT_ALLOC = Word.zero();
+  Word TRACE_BOOT_ALLOC = Word.one().lsh(0);
+  Word TRACE_ALLOC = Word.one().lsh(1);
+  Word TRACE_DEATH = Word.one().lsh(2);
+  Word TRACE_FIELD_SET = Word.one().lsh(3);
+  Word TRACE_ARRAY_SET = Word.one().lsh(4);
+  Word TRACE_TIB_SET = Word.one().lsh(5);
+  Word TRACE_STATIC_SET = Word.one().lsh(6);
+  Word TRACE_BOOTSTART = Word.one().lsh(7);
+  Word TRACE_BOOTEND = Word.one().lsh(8);
+  Word TRACE_GCSTART = Word.one().lsh(9);
+  Word TRACE_GCEND = Word.one().lsh(10);
+  Word TRACE_GCROOT = Word.one().lsh(11);
+  Word TRACE_GCBAR = Word.one().lsh(12);
+  Word TRACE_THREAD_SWITCH = Word.one().lsh(13);
+  Word TRACE_STACKDELTA = Word.one().lsh(14);
+  Word TRACE_ROOTPTR = Word.one().lsh(15);
+  Word TRACE_EXACT_IMMORTAL_ALLOC = Word.one().lsh(16);
+  Word TRACE_IMMORTAL_ALLOC = Word.one().lsh(17);
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/Treadmill.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/Treadmill.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/Treadmill.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/Treadmill.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,187 @@
+/*
+ *  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.mmtk.utility;
+
+import org.mmtk.utility.gcspy.drivers.TreadmillDriver;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * FIXME The DoublyLinkedList class, upon which this depends, must be
+ * re-written as it makes the assumption that the implementation
+ * language (Java) and the language being implemented are the same.
+ * This is true in the case of Jikes RVM, but it is not true for any
+ * VM implementing a language other than Java.
+ *
+ * Each instance of this class is a doubly-linked list, in which
+ * each item or node is a piece of memory.  The first two words of each node
+ * contains the forward and backward links.  The third word contains
+ * the treadmill.  The remaining portion is the payload.
+ *
+ * The treadmill object itself must not be moved.
+ *
+ * Access to the instances may be synchronized depending on the constructor argument.
+ */
+ at Uninterruptible
+public final class Treadmill implements Constants {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private DoublyLinkedList fromSpace;
+  private DoublyLinkedList toSpace;
+  private DoublyLinkedList collectNursery;
+  private DoublyLinkedList allocNursery;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   */
+  public Treadmill(int granularity, boolean shared) {
+    fromSpace = new DoublyLinkedList(granularity, shared);
+    toSpace = new DoublyLinkedList(granularity, shared);
+    allocNursery = new DoublyLinkedList(granularity, shared);
+    collectNursery = new DoublyLinkedList(granularity, shared);
+  }
+
+  /**
+   * Add a node to the treadmill. This is usually performed on allocation.
+   */
+  @Inline
+  public void addToTreadmill(Address node, boolean nursery) {
+    if (nursery)
+      allocNursery.add(node);
+    else
+      toSpace.add(node);
+  }
+
+  /**
+   * Remove a node from the nursery list.
+   */
+  @Inline
+  public Address popNursery() {
+    return collectNursery.pop();
+  }
+
+  /**
+   * Remove a node from the mature list.
+   */
+  @Inline
+  public Address pop() {
+    return fromSpace.pop();
+  }
+
+  /**
+   * Copy a node (during gc tracing).
+   */
+  @Inline
+  public void copy(Address node, boolean isInNursery) {
+    if (isInNursery) {
+      collectNursery.remove(node);
+    } else {
+      fromSpace.remove(node);
+    }
+    toSpace.add(node);
+  }
+
+  /**
+   * Is the to-space empty?
+   */
+  @Inline
+  public boolean toSpaceEmpty() {
+    return toSpace.isEmpty();
+  }
+
+  /**
+   * Is the from-space empty?
+   */
+  @Inline
+  public boolean fromSpaceEmpty() {
+    return fromSpace.isEmpty();
+  }
+
+  /**
+   * Is the nursery empty?
+   */
+  @Inline
+  public boolean nurseryEmpty() {
+    return collectNursery.isEmpty();
+  }
+
+  /**
+   * Flip the roles of the spaces in preparation for a collection.
+   */
+  public void flip(boolean fullHeap) {
+    DoublyLinkedList tmp = allocNursery;
+    allocNursery = collectNursery;
+    collectNursery = tmp;
+    if (fullHeap) {
+      tmp = fromSpace;
+      fromSpace = toSpace;
+      toSpace = tmp;
+    }
+  }
+
+  /****************************************************************************
+   *
+   * Misc header manipulation
+   */
+
+  @Inline
+  public static int headerSize() {
+    return DoublyLinkedList.headerSize();
+  }
+
+  @Inline
+  public static Address nodeToPayload(Address payload) {
+    return DoublyLinkedList.nodeToPayload(payload);
+  }
+
+  @Inline
+  public static Address midPayloadToNode(Address payload) {
+    return DoublyLinkedList.midPayloadToNode(payload);
+  }
+
+  /****************************************************************************
+   *
+   * GCSpy
+   */
+
+  /**
+   * Gather data for GCSpy from the nursery
+   * @param event the gc event
+   * @param tmDriver the GCSpy space driver
+   */
+  public void gcspyGatherData(int event, TreadmillDriver tmDriver) {
+    this.allocNursery.gcspyGatherData(tmDriver);
+  }
+
+  /**
+   * Gather data for GCSpy
+   * @param event the gc event
+   * @param tmDriver the GCSpy space driver
+   * @param tospace gather from tospace?
+   */
+  public void gcspyGatherData(int event, TreadmillDriver tmDriver, boolean tospace) {
+    if (tospace)
+      toSpace.gcspyGatherData(tmDriver);
+    else
+      fromSpace.gcspyGatherData(tmDriver);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/Allocator.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/Allocator.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/Allocator.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/Allocator.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,263 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.*;
+import org.mmtk.utility.statistics.*;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This abstract base class provides the basis for processor-local
+ * allocation.  The key functionality provided is the retry mechanism
+ * that is necessary to correctly handle the fact that a "slow-path"
+ * allocation can cause a GC which violate the uninterruptability assumption.
+ * This results in the thread being moved to a different processor so that
+ * the allocator object it is using is not actually the one for the processor
+ * it is running on.
+ *
+ * This class also includes functionality to assist allocators with
+ * ensuring that requests are aligned according to requests.
+ *
+ * Failing to handle this properly will lead to very hard to trace bugs
+ * where the allocation that caused a GC or allocations immediately following
+ * GC are run incorrectly.
+ */
+ at Uninterruptible public abstract class Allocator implements Constants {
+
+  /**
+   * Return the space this allocator is currently bound to.
+   *
+   * @return The Space.
+   */
+  protected abstract Space getSpace();
+
+  /**
+   * Aligns up an allocation request. The allocation request accepts a
+   * region, that must be at least particle aligned, an alignment
+   * request (some power of two number of particles) and an offset (a
+   * number of particles). There is also a knownAlignment parameter to
+   * allow a more optimised check when the particular allocator in use
+   * always aligns at a coarser grain than individual particles, such
+   * as some free lists.
+   *
+   * @param region The region to align up.
+   * @param alignment The requested alignment
+   * @param offset The offset from the alignment
+   * @param knownAlignment The statically known minimum alignment.
+   * @return The aligned up address.
+   */
+  @Inline
+  public static Address alignAllocation(Address region, int alignment, int offset, int knownAlignment, boolean fillAlignmentGap) {
+    if (VM.VERIFY_ASSERTIONS) {
+      VM.assertions._assert(knownAlignment >= MIN_ALIGNMENT);
+      VM.assertions._assert(MIN_ALIGNMENT >= BYTES_IN_INT);
+      VM.assertions._assert(!(fillAlignmentGap && region.isZero()));
+      VM.assertions._assert(alignment <= MAX_ALIGNMENT);
+      VM.assertions._assert(offset >= 0);
+      VM.assertions._assert(region.toWord().and(Word.fromIntSignExtend(MIN_ALIGNMENT-1)).isZero());
+      VM.assertions._assert((alignment & (MIN_ALIGNMENT - 1)) == 0);
+      VM.assertions._assert((offset & (MIN_ALIGNMENT - 1)) == 0);
+    }
+
+    // No alignment ever required.
+    if (alignment <= knownAlignment || MAX_ALIGNMENT <= MIN_ALIGNMENT)
+      return region;
+
+    // May require an alignment
+    Word mask = Word.fromIntSignExtend(alignment - 1);
+    Word negOff = Word.fromIntSignExtend(-offset);
+    Offset delta = negOff.minus(region.toWord()).and(mask).toOffset();
+
+    if (fillAlignmentGap && ALIGNMENT_VALUE != 0) {
+      if ((MAX_ALIGNMENT - MIN_ALIGNMENT) == BYTES_IN_WORD) {
+        // At most a single hole
+        if (delta.toInt() == (BYTES_IN_WORD)) {
+          region.store(Word.fromIntSignExtend(ALIGNMENT_VALUE));
+          region = region.plus(delta);
+        return region;
+        }
+      } else {
+        while (delta.toInt() >= (BYTES_IN_WORD)) {
+          region.store(Word.fromIntSignExtend(ALIGNMENT_VALUE));
+          region = region.plus(BYTES_IN_WORD);
+          delta = delta.minus(BYTES_IN_WORD);
+        }
+      }
+    }
+
+    return region.plus(delta);
+  }
+
+  /**
+   * Fill the specified region with the alignment value.
+   *
+   * @param start The start of the region.
+   * @param end A pointer past the end of the region.
+   */
+  @Inline
+  public static void fillAlignmentGap(Address start, Address end) {
+    if ((MAX_ALIGNMENT - MIN_ALIGNMENT) == BYTES_IN_INT) {
+      // At most a single hole
+      if (!end.diff(start).isZero()) {
+        start.store(ALIGNMENT_VALUE);
+      }
+    } else {
+      while (start.LT(end)) {
+        start.store(ALIGNMENT_VALUE);
+        start = start.plus(BYTES_IN_INT);
+      }
+    }
+  }
+
+  /**
+   * Aligns up an allocation request. The allocation request accepts a
+   * region, that must be at least particle aligned, an alignment
+   * request (some power of two number of particles) and an offset (a
+   * number of particles).
+   *
+   * @param region The region to align up.
+   * @param alignment The requested alignment
+   * @param offset The offset from the alignment
+   * @return The aligned up address.
+   */
+  @Inline
+  public static Address alignAllocation(Address region, int alignment, int offset) {
+    return alignAllocation(region, alignment, offset, MIN_ALIGNMENT, true);
+  }
+
+  /**
+   * Aligns up an allocation request. The allocation request accepts a
+   * region, that must be at least particle aligned, an alignment
+   * request (some power of two number of particles) and an offset (a
+   * number of particles).
+   *
+   * @param region The region to align up.
+   * @param alignment The requested alignment
+   * @param offset The offset from the alignment
+   * @return The aligned up address.
+   */
+  @Inline
+  public static Address alignAllocationNoFill(Address region, int alignment, int offset) {
+    return alignAllocation(region, alignment, offset, MIN_ALIGNMENT, false);
+  }
+
+  /**
+   * This method calculates the minimum size that will guarantee the allocation
+   * of a specified number of bytes at the specified alignment.
+   *
+   * @param size The number of bytes (not aligned).
+   * @param alignment The requested alignment (some factor of 2).
+   */
+  @Inline
+  public static int getMaximumAlignedSize(int size, int alignment) {
+    return getMaximumAlignedSize(size, alignment, MIN_ALIGNMENT);
+  }
+
+  /**
+   * This method calculates the minimum size that will guarantee the allocation
+   * of a specified number of bytes at the specified alignment.
+   *
+   * @param size The number of bytes (not aligned).
+   * @param alignment The requested alignment (some factor of 2).
+   * @param knownAlignment The known minimum alignment. Specifically for use in
+   * allocators that enforce greater than particle alignment. It is a <b>precondition</b>
+   * that size is aligned to knownAlignment, and that knownAlignment >= MIN_ALGINMENT.
+   */
+  @Inline
+  public static int getMaximumAlignedSize(int size, int alignment, int knownAlignment) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(size == Conversions.roundDown(size, knownAlignment));
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(knownAlignment >= MIN_ALIGNMENT);
+
+    if (MAX_ALIGNMENT <= MIN_ALIGNMENT || alignment <= knownAlignment) {
+      return size;
+    } else {
+      return size + alignment - knownAlignment;
+    }
+  }
+
+  /**
+   * Single slow path allocation attempt. This is called by allocSlow.
+   *
+   * @param bytes The size of the allocation request
+   * @param alignment The required alignment
+   * @param offset The alignment offset
+   * @return The start address of the region, or zero if allocation fails
+   */
+  protected abstract Address allocSlowOnce(int bytes, int alignment, int offset);
+
+  /**
+   * <b>Out-of-line</b> slow path allocation. This method forces slow path
+   * allocation to be out of line (typically desirable, but not when the
+   * calling context is already explicitly out-of-line).
+   *
+   * @param bytes The size of the allocation request
+   * @param alignment The required alignment
+   * @param offset The alignment offset
+   * @return The start address of the region, or zero if allocation fails
+   */
+  @NoInline
+  public final Address allocSlow(int bytes, int alignment, int offset) {
+    return allocSlowInline(bytes, alignment, offset);
+  }
+
+  /**
+   * <b>Inline</b> slow path allocation. This method attempts allocSlowOnce
+   * several times, and allows collection to occur, and ensures that execution
+   * safely resumes by taking care of potential thread/mutator context affinity
+   * changes. All allocators should use this as the trampoline for slow
+   * path allocation.
+   *
+   * @param bytes The size of the allocation request
+   * @param alignment The required alignment
+   * @param offset The alignment offset
+   * @return The start address of the region, or zero if allocation fails
+   */
+  @Inline
+  public final Address allocSlowInline(int bytes, int alignment, int offset) {
+    int gcCountStart = Stats.gcCount();
+    Allocator current = this;
+    Space space = current.getSpace();
+    for (int i = 0; i < Plan.MAX_COLLECTION_ATTEMPTS; i++) {
+      Address result = current.allocSlowOnce(bytes, alignment, offset);
+      if (!result.isZero()) {
+        return result;
+      }
+      if (!Plan.gcInProgress()) {
+        /* This is in case a GC occurs, and our mutator context is stale.
+         * In some VMs the scheduler can change the affinity between the
+         * current thread and the mutator context. This is possible for
+         * VMs that dynamically multiplex Java threads onto multiple mutator
+         * contexts, */
+        current = VM.activePlan.mutator().getAllocatorFromSpace(space);
+      }
+    }
+    Log.write("GC Error: Allocator.allocSlow failed on request of ");
+    Log.write(bytes);
+    Log.write(" on space ");
+    Log.writeln(space.getName());
+    Log.write("gcCountStart = ");
+    Log.writeln(gcCountStart);
+    Log.write("gcCount (now) = ");
+    Log.writeln(Stats.gcCount());
+    Space.printUsageMB();
+    VM.assertions.fail("Allocation Failed!");
+    /* NOTREACHED */
+    return Address.zero();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BlockAllocator.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BlockAllocator.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BlockAllocator.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BlockAllocator.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,335 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.policy.Space;
+import org.mmtk.utility.*;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements "block" data structures of various sizes.<p>
+ *
+ * Blocks are a non-shared (thread-local) coarse-grained unit of
+ * storage. Blocks are available in power-of-two sizes.
+ *
+ * Virtual memory space is taken from a VM resource, and pages
+ * consumed by blocks are accounted for by a memory resource.
+ */
+ at Uninterruptible
+public final class BlockAllocator implements Constants {
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  // block freelist
+  public static final int LOG_MIN_BLOCK = 12; // 4K bytes
+  public static final int LOG_MAX_BLOCK = 15; // 32K bytes
+  public static final byte MAX_BLOCK_SIZE_CLASS = LOG_MAX_BLOCK - LOG_MIN_BLOCK;
+  public static final int BLOCK_SIZE_CLASSES = MAX_BLOCK_SIZE_CLASS + 1;
+
+  // metadata
+  private static final Offset NEXT_OFFSET = Offset.zero();
+  private static final Offset BMD_OFFSET = NEXT_OFFSET.plus(BYTES_IN_ADDRESS);
+  private static final Offset CSC_OFFSET = BMD_OFFSET.plus(1);
+  private static final Offset IU_OFFSET = CSC_OFFSET.plus(1);
+  private static final Offset FL_META_OFFSET = IU_OFFSET.plus(BYTES_IN_SHORT);
+  private static final byte BLOCK_SC_MASK = 0xf;             // lower 4 bits
+  private static final int BLOCK_PAGE_OFFSET_SHIFT = 4;      // higher 4 bits
+  private static final int MAX_BLOCK_PAGE_OFFSET = (1<<4)-1; // 4 bits
+  private static final int LOG_BYTES_IN_BLOCK_META = LOG_BYTES_IN_ADDRESS + 2;
+  private static final int LOG_BYTE_COVERAGE = LOG_MIN_BLOCK - LOG_BYTES_IN_BLOCK_META;
+
+  public static final int META_DATA_BYTES_PER_REGION = 1 << (EmbeddedMetaData.LOG_BYTES_IN_REGION - LOG_BYTE_COVERAGE);
+  public static final Extent META_DATA_EXTENT = Extent.fromIntSignExtend(META_DATA_BYTES_PER_REGION);
+
+  /****************************************************************************
+   *
+   * Allocation & freeing
+   */
+
+  /**
+   * Allocate a block, returning the address of the first usable byte
+   * in the block.
+   *
+   * @param blockSizeClass The size class for the block to be allocated.
+   * @return The address of the first usable byte in the block, or
+   * zero on failure.
+   */
+  public static Address alloc(Space space, int blockSizeClass) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((blockSizeClass >= 0) && (blockSizeClass <= MAX_BLOCK_SIZE_CLASS));
+    int pages = pagesForSizeClass(blockSizeClass);
+    Address result = space.acquire(pages);
+    if (!result.isZero()) {
+      setBlkSizeMetaData(result, (byte) blockSizeClass);
+    }
+    return result;
+  }
+
+  /**
+   * Free a block.  If the block is a sub-page block and the page is
+   * not completely free, then the block is added to the free list.
+   * Otherwise the block is returned to the virtual memory resource.
+   *
+   * @param block The address of the block to be freed
+   */
+  public static void free(Space space, Address block) {
+    space.release(block);
+  }
+
+  /**
+   * Return the size in bytes of a block of a given size class
+   *
+   * @param blockSizeClass The size class in question
+   * @return The size in bytes of a block of this size class
+   */
+  @Inline
+  public static int blockSize(int blockSizeClass) {
+    return 1 << (LOG_MIN_BLOCK + blockSizeClass);
+  }
+
+  /**
+   * Return the number of pages required when allocating space for
+   *         this size class.
+   *
+   * @param blockSizeClass The size class in question
+   * @return The number of pages required when allocating a block (or
+   * blocks) of this size class.
+   */
+  @Inline
+  private static int pagesForSizeClass(int blockSizeClass) {
+    return 1 << (LOG_MIN_BLOCK + blockSizeClass - LOG_BYTES_IN_PAGE);
+  }
+
+  /****************************************************************************
+   *
+   * Block meta-data manipulation
+   */
+
+  /**
+   * Set the <i>block size class</i> meta data field for a given
+   * address (all blocks on a given page are homogeneous with respect
+   * to block size class).
+   *
+   * @param block The address of interest
+   * @param sc The value to which this field is to be set
+   */
+  @Inline
+  private static void setBlkSizeMetaData(Address block, byte sc) {
+    if (VM.VERIFY_ASSERTIONS) {
+      VM.assertions._assert(block.EQ(Conversions.pageAlign(block)));
+      VM.assertions._assert(pagesForSizeClass(sc) - 1  <= MAX_BLOCK_PAGE_OFFSET);
+    }
+    Address address = block;
+    for (int i = 0; i < pagesForSizeClass(sc); i++) {
+      byte value = (byte) ((i << BLOCK_PAGE_OFFSET_SHIFT) | sc);
+      getMetaAddress(address).store(value, BMD_OFFSET);
+      if (VM.VERIFY_ASSERTIONS) {
+        VM.assertions._assert(getBlkStart(address).EQ(block));
+        VM.assertions._assert(getBlkSizeClass(address) == sc);
+      }
+      address = address.plus(1<<VM.LOG_BYTES_IN_PAGE);
+    }
+  }
+
+  /**
+   * Get the <i>block size class</i> meta data field for a given page
+   * (all blocks on a given page are homogeneous with respect to block
+   * size class).
+   *
+   * @param address The address of interest
+   * @return The size class field for the block containing the given address
+   */
+  @Inline
+  private static byte getBlkSizeClass(Address address) {
+    address = Conversions.pageAlign(address);
+    byte rtn = (byte) (getMetaAddress(address).loadByte(BMD_OFFSET) & BLOCK_SC_MASK);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn >= 0 && rtn <= MAX_BLOCK_SIZE_CLASS);
+    return rtn;
+  }
+
+  /**
+   * Get the <i>address of the start of a block size class</i> a given page
+   * within the block.
+   *
+   * @param address The address of interest
+   * @return The address of the block containing the address
+   */
+  @Inline
+  public static Address getBlkStart(Address address) {
+    address = Conversions.pageAlign(address);
+    byte offset = (byte) (getMetaAddress(address).loadByte(BMD_OFFSET) >>> BLOCK_PAGE_OFFSET_SHIFT);
+    return address.minus(offset<<LOG_BYTES_IN_PAGE);
+  }
+
+  /**
+   * Set the <i>client size class</i> meta data field for a given
+   * address (all blocks on a given page are homogeneous with respect
+   * to block size class).
+   *
+   * @param block The address of interest
+   * @param sc The value to which this field is to be set
+   */
+  @Inline
+  public static void setAllClientSizeClass(Address block, int blocksc, byte sc) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(block.EQ(Conversions.pageAlign(block)));
+    Address address = block;
+    for (int i = 0; i < pagesForSizeClass(blocksc); i++) {
+      getMetaAddress(address).store(sc, CSC_OFFSET);
+      address = address.plus(1<<VM.LOG_BYTES_IN_PAGE);
+    }
+  }
+
+  /**
+   * Get the <i>client size class</i> meta data field for a given page
+   * (all blocks on a given page are homogeneous with respect to block
+   * size class).
+   *
+   * @param address The address of interest
+   * @return The size class field for the block containing the given address
+   */
+  @Inline
+  public static byte getClientSizeClass(Address address) {
+    address = Conversions.pageAlign(address);
+    byte rtn = getMetaAddress(address).loadByte(CSC_OFFSET);
+    return rtn;
+  }
+
+  /**
+   * Set the free list meta data field for a given address (this is
+   * per-block meta data that is stored along with the block metadata
+   * but not used by the block allocator).
+   *
+   * @param address The address of interest
+   * @param value The value to which this field is to be set
+   */
+  @Inline
+  public static void setFreeListMeta(Address address, Address value) {
+    getMetaAddress(address).plus(FL_META_OFFSET).store(value);
+  }
+
+  /**
+   * Get the free list meta data field for a given address (this is
+   * per-block meta data that is stored along with the block metadata
+   * but not used by the block allocator).
+   *
+   * @param address The address of interest
+   * @return The free list meta data field for the block containing
+   * the given address
+   */
+  @Inline
+  public static Address getFreeListMeta(Address address) {
+    return getMetaAddress(address).plus(FL_META_OFFSET).loadAddress();
+  }
+
+  /**
+   * Set the <i>prev</i> meta data field for a given address
+   *
+   * @param address The address of interest
+   * @param prev The value to which this field is to be set
+   */
+  @Inline
+  public static void setNext(Address address, Address prev) {
+    getMetaAddress(address, NEXT_OFFSET).store(prev);
+  }
+
+  /**
+   * Get the <i>prev</i> meta data field for a given address
+   *
+   * @param address The address of interest
+   * @return The prev field for the block containing the given address
+   */
+  @Inline
+  public static Address getNext(Address address) {
+    return getMetaAddress(address, NEXT_OFFSET).loadAddress();
+  }
+
+  /**
+   * Get the address of some metadata given the address for which the
+   * metadata is required and the offset into the metadata that is of
+   * interest.
+   *
+   * @param address The address for which the metadata is required
+   * @return The address of the specified meta data
+   */
+  @Inline
+  private static Address getMetaAddress(Address address) {
+    return getMetaAddress(address, Offset.zero());
+  }
+
+  /**
+   * Get the address of some metadata given the address for which the
+   * metadata is required and the offset into the metadata that is of
+   * interest.
+   *
+   * @param address The address for which the metadata is required
+   * @param offset The offset (in bytes) into the metadata block (eg
+   * for the prev pointer, or next pointer)
+   * @return The address of the specified meta data
+   */
+  @Inline
+  private static Address getMetaAddress(Address address, Offset offset) {
+    return EmbeddedMetaData.getMetaDataBase(address).plus(
+           EmbeddedMetaData.getMetaDataOffset(address, LOG_BYTE_COVERAGE, LOG_BYTES_IN_BLOCK_META)).plus(offset);
+  }
+
+  /****************************************************************************
+   *
+   * Block marking
+   */
+
+  /**
+   * Mark the metadata for this block.
+   *
+   * @param ref
+   */
+  @Inline
+  public static void markBlockMeta(ObjectReference ref) {
+    getMetaAddress(VM.objectModel.refToAddress(ref)).plus(FL_META_OFFSET).store(Word.one());
+  }
+
+  /**
+   * Mark the metadata for this block.
+   *
+   * @param block The block address
+   */
+  @Inline
+  public static void markBlockMeta(Address block) {
+    getMetaAddress(block).plus(FL_META_OFFSET).store(Word.one());
+  }
+
+  /**
+   * Return true if the metadata for this block was set.
+   *
+   * @param block The block address
+   * @return value of the meta data.
+   */
+  @Inline
+  public static boolean checkBlockMeta(Address block) {
+    return getMetaAddress(block).plus(FL_META_OFFSET).loadWord().EQ(Word.one());
+  }
+
+  /**
+   * Clear the metadata for this block
+   *
+   * @param block The block address
+   */
+  @Inline
+  public static void clearBlockMeta(Address block) {
+    getMetaAddress(block).plus(FL_META_OFFSET).store(Word.zero());
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BumpPointer.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BumpPointer.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BumpPointer.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/BumpPointer.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,459 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.policy.Space;
+import org.mmtk.utility.*;
+import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements a bump pointer allocator that allows linearly
+ * scanning through the allocated objects. In order to achieve this in the
+ * face of parallelism it maintains a header at a region (1 or more blocks)
+ * granularity.
+ *
+ * Intra-block allocation is fast, requiring only a load, addition comparison
+ * and store.  If a block boundary is encountered the allocator will
+ * request more memory (virtual and actual).
+ *
+ * In the current implementation the scanned objects maintain affinity
+ * with the thread that allocated the objects in the region. In the future
+ * it is anticipated that subclasses should be allowed to choose to improve
+ * load balancing during the parallel scan.
+ *
+ * Each region is laid out as follows:
+ *
+ *  +-------------+-------------+-------------+---------------
+ *  | Region  End | Next Region |  Data  End  | Data -->
+ * +-------------+-------------+-------------+---------------
+ *
+ * The minimum region size is 32768 bytes, so the 3 or 4 word overhead is
+ * less than 0.05% of all space.
+ *
+ * An intended enhancement is to facilitate a reallocation operation
+ * where a second cursor is maintained over earlier regions (and at the
+ * limit a lower location in the same region). This would be accompianied
+ * with an alternative slow path that would allow reuse of empty regions.
+ *
+ * This class relies on the supporting virtual machine implementing the
+ * getNextObject and related operations.
+ */
+ at Uninterruptible public class BumpPointer extends Allocator
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  // Block size defines slow path periodicity.
+  private static final int LOG_DEFAULT_STEP_SIZE = 30; // 1G: let the external slow path dominate
+  private static final int STEP_SIZE = 1<<(SUPPORT_CARD_SCANNING ? LOG_CARD_BYTES : LOG_DEFAULT_STEP_SIZE);
+  protected static final int LOG_BLOCK_SIZE = LOG_BYTES_IN_PAGE + 3;
+  protected static final Word BLOCK_MASK = Word.one().lsh(LOG_BLOCK_SIZE).minus(Word.one());
+
+  // Offsets into header
+  protected static final Offset REGION_LIMIT_OFFSET = Offset.zero();
+  protected static final Offset NEXT_REGION_OFFSET = REGION_LIMIT_OFFSET.plus(BYTES_IN_ADDRESS);
+  protected static final Offset DATA_END_OFFSET = NEXT_REGION_OFFSET.plus(BYTES_IN_ADDRESS);
+
+  // Data must start particle-aligned.
+  protected static final Offset DATA_START_OFFSET = alignAllocationNoFill(
+      Address.zero().plus(DATA_END_OFFSET.plus(BYTES_IN_ADDRESS)),
+      MIN_ALIGNMENT, 0).toWord().toOffset();
+  protected static final Offset MAX_DATA_START_OFFSET = alignAllocationNoFill(
+      Address.zero().plus(DATA_END_OFFSET.plus(BYTES_IN_ADDRESS)),
+      MAX_ALIGNMENT, 0).toWord().toOffset();
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  protected Address cursor; // insertion point
+  private Address internalLimit; // current internal slow-path sentinal for bump pointer
+  private Address limit; // current external slow-path sentinal for bump pointer
+  protected Space space; // space this bump pointer is associated with
+  protected Address initialRegion; // first contiguous region
+  protected final boolean allowScanning; // linear scanning is permitted if true
+  protected Address region; // current contiguous region
+
+
+  /**
+   * Constructor.
+   *
+   * @param space The space to bump point into.
+   * @param allowScanning Allow linear scanning of this region of memory.
+   */
+  protected BumpPointer(Space space, boolean allowScanning) {
+    this.space = space;
+    this.allowScanning = allowScanning;
+    reset();
+  }
+
+  /**
+   * Reset the allocator. Note that this does not reset the space.
+   * This is must be done by the caller.
+   */
+  public final void reset() {
+    cursor = Address.zero();
+    limit = Address.zero();
+    internalLimit = Address.zero();
+    initialRegion = Address.zero();
+    region = Address.zero();
+  }
+
+  /**
+   * Re-associate this bump pointer with a different space. Also
+   * reset the bump pointer so that it will use the new space
+   * on the next call to <code>alloc</code>.
+   *
+   * @param space The space to associate the bump pointer with.
+   */
+  public final void rebind(Space space) {
+    reset();
+    this.space = space;
+  }
+
+  /**
+   * Allocate space for a new object.  This is frequently executed code and
+   * the coding is deliberaetly sensitive to the optimizing compiler.
+   * After changing this, always check the IR/MC that is generated.
+   *
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment
+   * @param offset The offset from the alignment
+   * @return The address of the first byte of the allocated region
+   */
+  @Inline
+  public final Address alloc(int bytes, int align, int offset) {
+    Address start = alignAllocationNoFill(cursor, align, offset);
+    Address end = start.plus(bytes);
+    if (end.GT(internalLimit))
+      return allocSlow(start, end, align, offset);
+    fillAlignmentGap(cursor, start);
+    cursor = end;
+    return start;
+  }
+
+ /**
+  * Internal allocation slow path.  This is called whenever the bump
+  * pointer reaches the internal limit.  The code is forced out of
+  * line.  If required we perform an external slow path take, which
+  * we inline into this method since this is already out of line.
+  *
+  * @param start The start address for the pending allocation
+ * @param end The end address for the pending allocation
+ * @param align The requested alignment
+ * @param offset The offset from the alignment
+  * @return The address of the first byte of the allocated region
+  */
+  @NoInline
+  private Address allocSlow(Address start, Address end, int align,
+      int offset) {
+    Address rtn = null;
+    Address card = null;
+    if (SUPPORT_CARD_SCANNING)
+      card = getCard(start.plus(CARD_MASK)); // round up
+    if (end.GT(limit)) { /* external slow path */
+      rtn = allocSlowInline(end.diff(start).toInt(), align, offset);
+      if (SUPPORT_CARD_SCANNING && card.NE(getCard(rtn.plus(CARD_MASK))))
+        card = getCard(rtn); // round down
+    } else {             /* internal slow path */
+      while (internalLimit.LE(end))
+        internalLimit = internalLimit.plus(STEP_SIZE);
+      if (internalLimit.GT(limit))
+        internalLimit = limit;
+      fillAlignmentGap(cursor, start);
+      cursor = end;
+      rtn = start;
+    }
+    if (SUPPORT_CARD_SCANNING && !rtn.isZero())
+      createCardAnchor(card, rtn, end.diff(start).toInt());
+    return rtn;
+  }
+
+  /**
+   * Given an allocation which starts a new card, create a record of
+   * where the start of the object is relative to the start of the
+   * card.
+   *
+   * @param card An address that lies within the card to be marked
+   * @param start The address of an object which creates a new card.
+   * @param bytes The size of the pending allocation in bytes (used for debugging)
+   */
+  private void createCardAnchor(Address card, Address start, int bytes) {
+    if (VM.VERIFY_ASSERTIONS) {
+      VM.assertions._assert(allowScanning);
+      VM.assertions._assert(card.EQ(getCard(card)));
+      VM.assertions._assert(start.diff(card).sLE(MAX_DATA_START_OFFSET));
+      VM.assertions._assert(start.diff(card).toInt() >= -CARD_MASK);
+    }
+    while (bytes > 0) {
+      int offset = start.diff(card).toInt();
+      getCardMetaData(card).store(offset);
+      card = card.plus(1 << LOG_CARD_BYTES);
+      bytes -= (1 << LOG_CARD_BYTES);
+    }
+  }
+
+  /**
+   * Return the start of the card corresponding to a given address.
+   *
+   * @param address The address for which the card start is required
+   * @return The start of the card containing the address
+   */
+  private static Address getCard(Address address) {
+    return address.toWord().and(Word.fromIntSignExtend(CARD_MASK).not()).toAddress();
+  }
+
+  /**
+   * Return the address of the metadata for a card, given the address of the card.
+   * @param card The address of some card
+   * @return The address of the metadata associated with that card
+   */
+  private static Address getCardMetaData(Address card) {
+    Address metadata = EmbeddedMetaData.getMetaDataBase(card);
+    return metadata.plus(EmbeddedMetaData.getMetaDataOffset(card, LOG_CARD_BYTES-LOG_CARD_META_SIZE, LOG_CARD_META_SIZE));
+  }
+
+  /**
+   * External allocation slow path (called by superclass when slow path is
+   * actually taken.  This is necessary (rather than a direct call
+   * from the fast path) because of the possibility of a thread switch
+   * and corresponding re-association of bump pointers to kernel
+   * threads.
+   *
+   * @param bytes The number of bytes allocated
+   * @param offset The offset from the alignment
+   * @param align The requested alignment
+   * @return The address of the first byte of the allocated region or
+   * zero on failure
+   */
+  protected final Address allocSlowOnce(int bytes, int align, int offset) {
+    /* Check we have been bound to a space */
+    if (space == null) {
+      VM.assertions.fail("Allocation on unbound bump pointer.");
+    }
+
+    /* Check if we already have a block to use */
+    if (allowScanning && !region.isZero()) {
+      Address nextRegion = region.loadAddress(NEXT_REGION_OFFSET);
+      if (!nextRegion.isZero()) {
+        return consumeNextRegion(nextRegion, bytes, align, offset);
+      }
+    }
+
+    /* Acquire space, block aligned, that can accommodate the request */
+    Extent blockSize = Word.fromIntZeroExtend(bytes).plus(BLOCK_MASK)
+                       .and(BLOCK_MASK.not()).toExtent();
+    Address start = space.acquire(Conversions.bytesToPages(blockSize));
+
+    if (start.isZero()) return start; // failed allocation
+
+    if (!allowScanning) { // simple allocator
+      if (start.NE(limit)) cursor = start;  // discontiguous
+      updateLimit(start.plus(blockSize), start, bytes);
+    } else                // scannable allocator
+      updateMetaData(start, blockSize, bytes);
+    return alloc(bytes, align, offset);
+  }
+
+  /**
+   * Update the limit pointer.  As a side effect update the internal limit
+   * pointer appropriately.
+   *
+   * @param newLimit The new value for the limit pointer
+   * @param start The start of the region to be allocated into
+   * @param bytes The size of the pending allocation (if any).
+   */
+  @Inline
+  protected final void updateLimit(Address newLimit, Address start, int bytes) {
+    limit = newLimit;
+    internalLimit = start.plus(STEP_SIZE);
+    if (internalLimit.GT(limit))
+      internalLimit = limit;
+    else {
+      while (internalLimit.LT(cursor.plus(bytes)))
+        internalLimit = internalLimit.plus(STEP_SIZE);
+      if (VM.VERIFY_ASSERTIONS)
+        VM.assertions._assert(internalLimit.LE(limit));
+    }
+  }
+
+  /**
+   * A bump pointer chuck/region has been consumed but the contiguous region
+   * is available, so consume it and then return the address of the start
+   * of a memory region satisfying the outstanding allocation request.  This
+   * is relevant when re-using memory, as in a mark-compact collector.
+   *
+   * @param nextRegion The region to be consumed
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment
+   * @param offset The offset from the alignment
+   * @return The address of the first byte of the allocated region or
+   * zero on failure
+   */
+  private Address consumeNextRegion(Address nextRegion, int bytes, int align,
+        int offset) {
+    region.plus(DATA_END_OFFSET).store(cursor);
+    region = nextRegion;
+    cursor = nextRegion.plus(DATA_START_OFFSET);
+    updateLimit(nextRegion.loadAddress(REGION_LIMIT_OFFSET), nextRegion, bytes);
+    nextRegion.store(Address.zero(), DATA_END_OFFSET);
+    VM.memory.zero(cursor, limit.diff(cursor).toWord().toExtent());
+    reusePages(Conversions.bytesToPages(limit.diff(region)));
+
+    return alloc(bytes, align, offset);
+  }
+
+  /**
+   * Update the metadata to reflect the addition of a new region.
+   *
+   * @param start The start of the new region
+   * @param size The size of the new region (rounded up to block-alignment)
+   */
+  @Inline
+  private void updateMetaData(Address start, Extent size, int bytes) {
+    if (initialRegion.isZero()) {
+      /* this is the first allocation */
+      initialRegion = start;
+      region = start;
+      cursor = region.plus(DATA_START_OFFSET);
+    } else if (limit.NE(start) ||
+               region.diff(start.plus(size)).toWord().toExtent().GT(maximumRegionSize())) {
+      /* non contiguous or over-size, initialize new region */
+      region.plus(NEXT_REGION_OFFSET).store(start);
+      region.plus(DATA_END_OFFSET).store(cursor);
+      region = start;
+      cursor = start.plus(DATA_START_OFFSET);
+    }
+    updateLimit(start.plus(size), start, bytes);
+    region.plus(REGION_LIMIT_OFFSET).store(limit);
+  }
+
+  /**
+   * Gather data for GCspy. <p>
+   * This method calls the drivers linear scanner to scan through
+   * the objects allocated by this bump pointer.
+   *
+   * @param driver The GCspy driver for this space.
+   */
+  public void gcspyGatherData(LinearSpaceDriver driver) {
+    //driver.setRange(space.getStart(), cursor);
+    driver.setRange(space.getStart(), limit);
+    this.linearScan(driver.getScanner());
+  }
+
+  /**
+   * Gather data for GCspy. <p>
+   * This method calls the drivers linear scanner to scan through
+   * the objects allocated by this bump pointer.
+   *
+   * @param driver The GCspy driver for this space.
+   * @param scanSpace The space to scan
+   */
+  public void gcspyGatherData(LinearSpaceDriver driver, Space scanSpace) {
+    //TODO can scanSpace ever be different to this.space?
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(scanSpace == space, "scanSpace != space");
+
+    //driver.setRange(scanSpace.getStart(), cursor);
+    Address start = scanSpace.getStart();
+    driver.setRange(start, limit);
+
+    if (false) {
+      Log.write("\nBumpPointer.gcspyGatherData set Range "); Log.write(scanSpace.getStart());
+      Log.write(" to "); Log.writeln(limit);
+      Log.write("BumpPointergcspyGatherData scan from "); Log.writeln(initialRegion);
+    }
+
+    linearScan(driver.getScanner());
+  }
+
+
+  /**
+   * Perform a linear scan through the objects allocated by this bump pointer.
+   *
+   * @param scanner The scan object to delegate scanning to.
+   */
+  @Inline
+  public final void linearScan(LinearScan scanner) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(allowScanning);
+    /* Has this allocator ever allocated anything? */
+    if (initialRegion.isZero()) return;
+
+    /* Loop through active regions or until the last region */
+    Address start = initialRegion;
+    while (!start.isZero()) {
+      scanRegion(scanner, start); // Scan this region
+      start = start.plus(NEXT_REGION_OFFSET).loadAddress(); // Move on to next
+    }
+  }
+
+  /**
+   * Perform a linear scan through a single contiguous region
+   *
+   * @param scanner The scan object to delegate to.
+   * @param start The start of this region
+   */
+  @Inline
+  private void scanRegion(LinearScan scanner, Address start) {
+    /* Get the end of this region */
+    Address dataEnd = start.plus(DATA_END_OFFSET).loadAddress();
+
+    /* dataEnd = zero represents the current region. */
+    Address currentLimit = (dataEnd.isZero() ? cursor : dataEnd);
+    ObjectReference current =
+      VM.objectModel.getObjectFromStartAddress(start.plus(DATA_START_OFFSET));
+
+    while (VM.objectModel.refToAddress(current).LT(currentLimit) && !current.isNull()) {
+      ObjectReference next = VM.objectModel.getNextObject(current);
+      scanner.scan(current); // Scan this object.
+      current = next;
+    }
+  }
+
+  /**
+   * Some pages are about to be re-used to satisfy a slow path request.
+   * @param pages The number of pages.
+   */
+  protected void reusePages(int pages) {
+    VM.assertions.fail("Subclasses that reuse regions must override this method.");
+  }
+
+  /**
+   * Maximum size of a single region. Important for children that implement
+   * load balancing or increments based on region size.
+   * @return the maximum region size
+   */
+  protected Extent maximumRegionSize() { return Extent.max(); }
+
+  /** @return the current cursor value */
+  public final Address getCursor() { return cursor; }
+  /** @return the space associated with this bump pointer */
+  public final Space getSpace() { return space; }
+
+  /**
+   * Print out the status of the allocator (for debugging)
+   */
+  public final void show() {
+    Log.write("cursor = "); Log.write(cursor);
+    if (allowScanning) {
+      Log.write(" region = "); Log.write(region);
+    }
+    Log.write(" limit = "); Log.writeln(limit);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/DumpLinearScan.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/DumpLinearScan.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/DumpLinearScan.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/DumpLinearScan.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,38 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.vm.VM;
+import org.mmtk.utility.Log;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Simple linear scan to dump object information.
+ */
+ at Uninterruptible
+public final class DumpLinearScan extends LinearScan {
+  /**
+   * Scan an object.
+   *
+   * @param object The object to scan
+   */
+  @Inline
+  public void scan(ObjectReference object) {
+    Log.write("[");
+    Log.write(object.toAddress());
+    Log.write("], SIZE = ");
+    Log.writeln(VM.objectModel.getCurrentSize(object));
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/EmbeddedMetaData.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/EmbeddedMetaData.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/EmbeddedMetaData.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/EmbeddedMetaData.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,74 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This plan implements constants and access methods for meta data
+ * that is embeded in allocation spaces (rather than kept on the
+ * side).  The basic idea is that meta data be embeded at a very
+ * coarse power of two granularity for fast access, minimal wastage
+ * and by making the regions coarse, the contiguous meta-data will be
+ * relatively large and thus the probability of L1 conflict misses
+ * will be reduced (as compared with embedding meta-data at the start
+ * of each page which will cause those few cache lines corresponding
+ * to the start of each page to be heavily conflicted).
+ */
+ at Uninterruptible public final class EmbeddedMetaData implements Constants {
+
+  /* The (log of the) size of each region of meta data management */
+  public static final int LOG_BYTES_IN_REGION = 22;
+  public static final int BYTES_IN_REGION = 1 << LOG_BYTES_IN_REGION;
+  private static final Word REGION_MASK = Word.fromIntSignExtend(BYTES_IN_REGION - 1);
+  public static final int LOG_PAGES_IN_REGION = LOG_BYTES_IN_REGION - LOG_BYTES_IN_PAGE;
+  public static final int PAGES_IN_REGION = 1 << LOG_PAGES_IN_REGION;
+
+  /**
+   * Given an address, return the begining of the meta data for the
+   * region containing the address.  This is a fast operation because
+   * it only involves masking out low order bits.
+   *
+   * @param address The address whose meta data is sought.
+   * @return The address of the start of the meta data for the meta
+   * region in which the address is located.
+   */
+  @Inline
+  public static Address getMetaDataBase(Address address) {
+    return address.toWord().and(REGION_MASK.not()).toAddress();
+  }
+
+  /**
+   * Given an address, the density (coverage) of a meta data type, and
+   * the granularity (alignment) of the meta data, return the offset
+   * into the meta data the address.
+   *
+   * @param address The address whose meta data offset is sought.
+   * @param logCoverage The log base two of the coverage of the meta
+   * data in question. For example, a value of 4 would indicate a
+   * coverage of 16; one metadata byte for every 16 bytes of data.
+   * @param logAlign The log base two of the aligment or granularity
+   * of the meta-data (it may be arranged in bytes, words, double
+   * words etc).
+   * @return The offset into the meta-data for this region, given the
+   * specified address and coverage and aligment requirements.
+   */
+  public static Extent getMetaDataOffset(Address address,
+                                                  int logCoverage,
+                                                  int logAlign) {
+    return address.toWord().and(REGION_MASK).rshl(logCoverage+logAlign).lsh(logAlign).toExtent();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/ImmixAllocator.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/ImmixAllocator.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/ImmixAllocator.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/ImmixAllocator.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,331 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.policy.Space;
+import org.mmtk.policy.immix.Block;
+import org.mmtk.policy.immix.Chunk;
+import org.mmtk.policy.immix.Line;
+import org.mmtk.policy.immix.ImmixSpace;
+import static org.mmtk.policy.immix.ImmixConstants.*;
+
+import org.mmtk.utility.Constants;
+import org.mmtk.utility.Log;
+import org.mmtk.utility.options.Options;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ *
+ */
+ at Uninterruptible
+public class ImmixAllocator extends Allocator implements Constants {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  protected final ImmixSpace space;    /* space this allocator is associated with */
+  private final boolean hot;
+  private final boolean copy;
+
+  private Address cursor;               /* bump pointer */
+  private Address limit;                /* limit for bump pointer */
+  private Address largeCursor;          /* bump pointer for large objects */
+  private Address largeLimit;           /* limit for bump pointer for large objects */
+  private boolean requestForLarge;      /* is the current request for large or small? */
+  private boolean straddle;             /* did the last allocation straddle a line? */
+  private int lineUseCount;             /* approximation to bytes allocated (measured at 99% accurate)  07/10/30 */
+  private Address markTable;
+  private Address recyclableBlock;
+  private int line;
+  private boolean recyclableExhausted;
+
+  /**
+   * Constructor.
+   *
+   * @param space The space to bump point into.
+   * @param hot TODO
+   * @param copy TODO
+   */
+  public ImmixAllocator(ImmixSpace space, boolean hot, boolean copy) {
+    this.space = space;
+    this.hot = hot;
+    this.copy = copy;
+    reset();
+  }
+
+  /**
+   * Reset the allocator. Note that this does not reset the space.
+   */
+  public void reset() {
+    cursor = Address.zero();
+    limit = Address.zero();
+    largeCursor = Address.zero();
+    largeLimit = Address.zero();
+    markTable = Address.zero();
+    recyclableBlock = Address.zero();
+    requestForLarge = false;
+    recyclableExhausted = false;
+    line = LINES_IN_BLOCK;
+    lineUseCount = 0;
+  }
+
+  /*****************************************************************************
+   *
+   * Public interface
+   */
+
+  /**
+   * Allocate space for a new object.  This is frequently executed code and
+   * the coding is deliberaetly sensitive to the optimizing compiler.
+   * After changing this, always check the IR/MC that is generated.
+   *
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment
+   * @param offset The offset from the alignment
+   * @return The address of the first byte of the allocated region
+   */
+  @Inline
+  public final Address alloc(int bytes, int align, int offset) {
+    /* establish how much we need */
+    Address start = alignAllocationNoFill(cursor, align, offset);
+    Address end = start.plus(bytes);
+
+    /* check whether we've exceeded the limit */
+    if (end.GT(limit)) {
+      if (bytes > BYTES_IN_LINE)
+        return overflowAlloc(bytes, align, offset);
+      else
+        return allocSlowHot(bytes, align, offset);
+    }
+
+    /* sufficient memory is available, so we can finish performing the allocation */
+    fillAlignmentGap(cursor, start);
+    cursor = end;
+
+    return start;
+  }
+
+  /**
+   * Allocate space for a new object.  This is frequently executed code and
+   * the coding is deliberaetly sensitive to the optimizing compiler.
+   * After changing this, always check the IR/MC that is generated.
+   *
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment
+   * @param offset The offset from the alignment
+   * @return The address of the first byte of the allocated region
+   */
+  public final Address overflowAlloc(int bytes, int align, int offset) {
+    /* establish how much we need */
+    Address start = alignAllocationNoFill(largeCursor, align, offset);
+    Address end = start.plus(bytes);
+
+    /* check whether we've exceeded the limit */
+    if (end.GT(largeLimit)) {
+      requestForLarge = true;
+      Address rtn =  allocSlowInline(bytes, align, offset);
+      requestForLarge = false;
+      return rtn;
+    }
+
+    /* sufficient memory is available, so we can finish performing the allocation */
+    fillAlignmentGap(largeCursor, start);
+    largeCursor = end;
+
+    return start;
+  }
+
+  @Inline
+  public final boolean getLastAllocLineStraddle() {
+    return straddle;
+  }
+
+  /**
+   * External allocation slow path (called by superclass when slow path is
+   * actually taken.  This is necessary (rather than a direct call
+   * from the fast path) because of the possibility of a thread switch
+   * and corresponding re-association of bump pointers to kernel
+   * threads.
+   *
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment
+   * @param offset The offset from the alignment
+   * @return The address of the first byte of the allocated region or
+   * zero on failure
+   */
+  protected final Address allocSlowOnce(int bytes, int align, int offset) {
+    boolean success = false;
+    while (!success) {
+      Address ptr = space.getSpace(hot, copy, lineUseCount);
+
+      if (ptr.isZero()) {
+        lineUseCount = 0;
+        return ptr; // failed allocation --- we will need to GC
+      }
+
+      /* we have been given a clean block */
+      success = true;
+      lineUseCount = LINES_IN_BLOCK;
+      if (VM.VERIFY_ASSERTIONS)
+        VM.assertions._assert(Block.isAligned(ptr));
+      zeroBlock(ptr);
+      if (requestForLarge) {
+        largeCursor = ptr;
+        largeLimit = ptr.plus(BYTES_IN_BLOCK);
+      } else {
+        cursor = ptr;
+        limit = ptr.plus(BYTES_IN_BLOCK);
+      }
+    }
+    return alloc(bytes, align, offset);
+  }
+
+  /****************************************************************************
+   *
+   * Bump allocation
+   */
+
+  /**
+   * Internal allocation slow path.  This is called whenever the bump
+   * pointer reaches the internal limit.  The code is forced out of
+   * line.  If required we perform an external slow path take, which
+   * we inline into this method since this is already out of line.
+   *
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment
+   * @param offset The offset from the alignment
+   * @return The address of the first byte of the allocated region
+   */
+  @NoInline
+  private Address allocSlowHot(int bytes, int align, int offset) {
+    if (acquireRecyclableLines(bytes, align, offset))
+      return alloc(bytes, align, offset);
+    else
+      return allocSlowInline(bytes, align, offset);
+  }
+
+  private boolean acquireRecyclableLines(int bytes, int align, int offset) {
+    while (line < LINES_IN_BLOCK || acquireRecyclableBlock()) {
+      line = space.getNextAvailableLine(markTable, line);
+      if (line < LINES_IN_BLOCK) {
+        int endLine = space.getNextUnavailableLine(markTable, line);
+        cursor = recyclableBlock.plus(Extent.fromIntSignExtend(line<<LOG_BYTES_IN_LINE));
+        limit = recyclableBlock.plus(Extent.fromIntSignExtend(endLine<<LOG_BYTES_IN_LINE));
+        if (SANITY_CHECK_LINE_MARKS) {
+          Address tmp = cursor;
+          while (tmp.LT(limit)) {
+            if (tmp.loadByte() != (byte) 0) {
+              Log.write("cursor: "); Log.writeln(cursor);
+              Log.write(" limit: "); Log.writeln(limit);
+              Log.write("current: "); Log.write(tmp);
+              Log.write("  value: "); Log.write(tmp.loadByte());
+              Log.write("   line: "); Log.write(line);
+              Log.write("endline: "); Log.write(endLine);
+              Log.write("  chunk: "); Log.write(Chunk.align(cursor));
+              Log.write("     hw: "); Log.write(Chunk.getHighWater(Chunk.align(cursor)));
+              Log.writeln(" values: ");
+              Address tmp2 = cursor;
+              while(tmp2.LT(limit)) { Log.write(tmp2.loadByte()); Log.write(" ");}
+              Log.writeln();
+            }
+            VM.assertions._assert(tmp.loadByte() == (byte) 0);
+            tmp = tmp.plus(1);
+          }
+        }
+        if (VM.VERIFY_ASSERTIONS && bytes <= BYTES_IN_LINE) {
+          Address start = alignAllocationNoFill(cursor, align, offset);
+          Address end = start.plus(bytes);
+          VM.assertions._assert(end.LE(limit));
+        }
+        VM.memory.zero(cursor, limit.diff(cursor).toWord().toExtent());
+        if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+          Log.write("Z["); Log.write(cursor); Log.write("->"); Log.write(limit); Log.writeln("]");
+        }
+
+        line = endLine;
+        if (VM.VERIFY_ASSERTIONS && copy) VM.assertions._assert(!Block.isDefragSource(cursor));
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private boolean acquireRecyclableBlock() {
+    boolean rtn;
+    rtn = acquireRecyclableBlockAddressOrder();
+    if (rtn) {
+      markTable = Line.getBlockMarkTable(recyclableBlock);
+      line = 0;
+    }
+    return rtn;
+  }
+
+  @Inline
+  private boolean acquireRecyclableBlockAddressOrder() {
+    if (recyclableExhausted) {
+      if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+        Log.writeln("[no recyclable available]");
+      }
+      return false;
+    }
+    int markState = 0;
+    boolean usable = false;
+    while (!usable) {
+      Address next = recyclableBlock.plus(BYTES_IN_BLOCK);
+      if (recyclableBlock.isZero() || ImmixSpace.isRecycleAllocChunkAligned(next)) {
+        recyclableBlock = space.acquireReusableBlocks();
+        if (recyclableBlock.isZero()) {
+          recyclableExhausted = true;
+          if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() >= 9) {
+            Log.writeln("[recyclable exhausted]");
+          }
+          line = LINES_IN_BLOCK;
+          return false;
+        }
+      } else {
+        recyclableBlock = next;
+      }
+      markState = Block.getBlockMarkState(recyclableBlock);
+      usable = (markState > 0 && markState <= ImmixSpace.getReusuableMarkStateThreshold(copy));
+      if (copy && Block.isDefragSource(recyclableBlock))
+        usable = false;
+    }
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Block.isUnused(recyclableBlock));
+    Block.setBlockAsReused(recyclableBlock);
+
+    lineUseCount += (LINES_IN_BLOCK-markState);
+    return true; // found something good
+  }
+
+  private void zeroBlock(Address block) {
+    // FIXME: efficiency check here!
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(block.toWord().and(Word.fromIntSignExtend(BYTES_IN_BLOCK-1)).isZero());
+    VM.memory.zero(block, Extent.fromIntZeroExtend(BYTES_IN_BLOCK));
+   }
+
+  /** @return the space associated with this squish allocator */
+  public final Space getSpace() { return space; }
+
+  /**
+   * Print out the status of the allocator (for debugging)
+   */
+  public final void show() {
+    Log.write("cursor = "); Log.write(cursor);
+    Log.write(" limit = "); Log.writeln(limit);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LargeObjectAllocator.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LargeObjectAllocator.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LargeObjectAllocator.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LargeObjectAllocator.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,113 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.policy.BaseLargeObjectSpace;
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This abstract class implements core functionality for a generic
+ * large object allocator. The shared VMResource used by each instance
+ * is the point of global synchronization, and synchronization only
+ * occurs at the granularity of aquiring (and releasing) chunks of
+ * memory from the VMResource.  Subclasses may require finer grained
+ * synchronization during a marking phase, for example.<p>
+ *
+ * This is a first cut implementation, with plenty of room for
+ * improvement...
+ */
+ at Uninterruptible
+public abstract class LargeObjectAllocator extends Allocator implements Constants {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  protected final BaseLargeObjectSpace space;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param space The space with which this large object allocator
+   * will be associated.
+   */
+  public LargeObjectAllocator(BaseLargeObjectSpace space) {
+    this.space = space;
+  }
+
+  /**
+   * Return the space this allocator is currently bound to.
+   *
+   * @return The Space.
+   */
+  protected final BaseLargeObjectSpace getSpace() {
+    return this.space;
+  }
+
+  /****************************************************************************
+   *
+   * Allocation
+   */
+
+  /**
+   * Allocate space for an object
+   *
+   * @param bytes The number of bytes allocated
+   * @param align The requested alignment.
+   * @param offset The alignment offset.
+   * @return The address of the first byte of the allocated cell Will
+   * not return zero.
+   */
+  @NoInline
+  public final Address alloc(int bytes, int align, int offset) {
+    Address cell = allocSlow(bytes, align, offset);
+    return alignAllocation(cell, align, offset);
+  }
+
+  /**
+   * Allocate a large object.  Large objects are directly allocted and
+   * freed in page-grained units via the vm resource.  This routine
+   * returned zeroed memory.
+   *
+   * @param bytes The required size of this space in bytes.
+   * @param offset The alignment offset.
+   * @param align The requested alignment.
+   * @return The address of the start of the newly allocated region at
+   * least <code>bytes</code> bytes in size.
+   */
+  protected final Address allocSlowOnce(int bytes, int align, int offset) {
+    int header = space.getHeaderSize();
+    int maxbytes = getMaximumAlignedSize(bytes + header, align);
+    int pages = (maxbytes + BYTES_IN_PAGE - 1) >> LOG_BYTES_IN_PAGE;
+    Address sp = space.acquire(pages);
+    if (sp.isZero()) return sp;
+    Address cell = sp.plus(header);
+    return cell;
+  }
+
+  /****************************************************************************
+   *
+   * Miscellaneous
+   */
+  public void show() {
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LinearScan.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LinearScan.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LinearScan.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/LinearScan.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,30 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Callbacks from BumpPointer during a linear scan are dispatched through
+ * a subclass of this object.
+ */
+ at Uninterruptible
+public abstract class LinearScan {
+  /**
+   * Scan an object.
+   *
+   * @param object The object to scan
+   */
+  public abstract void scan(ObjectReference object);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeList.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeList.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeList.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeList.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,119 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.policy.SegregatedFreeListSpace;
+import org.mmtk.utility.*;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This abstract class implements the fast past for a segregated free list.
+ */
+ at Uninterruptible
+public abstract class SegregatedFreeList<S extends SegregatedFreeListSpace> extends Allocator implements Constants {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  /** The space */
+  protected final S space;
+
+  /** The current free lists for the size classes */
+  protected final AddressArray freeList;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param space The space with which this allocator will be associated
+   */
+  public SegregatedFreeList(S space) {
+    this.space = space;
+    this.freeList = AddressArray.create(sizeClassCount());
+  }
+
+  /**
+   * Return the space this allocator is currently bound to.
+   *
+   * @return The Space.
+   */
+  protected final S getSpace() {
+    return this.space;
+  }
+
+  /****************************************************************************
+   *
+   * Allocation
+   */
+
+  /**
+   * Allocate <code>bytes</code> contiguous bytes of zeroed memory.<p>
+   *
+   * This code implements the fast path, and on failure delegates to the slow path.
+   *
+   * @param bytes The size of the object to occupy this space, in bytes.
+   * @param align The requested alignment.
+   * @param offset The alignment offset.
+   * @return The address of the first word or zero on failure
+   */
+  @Inline
+  public final Address alloc(int bytes, int align, int offset) {
+    int alignedBytes = getMaximumAlignedSize(bytes, align);
+    int sizeClass = getSizeClass(alignedBytes);
+    Address cell = freeList.get(sizeClass);
+    if (!cell.isZero()) {
+      freeList.set(sizeClass, cell.loadAddress());
+      /* Clear the free list link */
+      cell.store(Address.zero());
+      if (alignedBytes != bytes) {
+        /* Ensure aligned as requested. */
+        cell = alignAllocation(cell, align, offset);
+      }
+      return cell;
+    }
+    return allocSlow(bytes, align, offset);
+  }
+
+  /**
+   * The number of distinct size classes.
+   *
+   * NOTE: For optimal performance this call must be implemented in a way
+   * it can be inlined and optimized within the allocation sequence.
+   */
+  @Inline
+  private int sizeClassCount() {
+    return SegregatedFreeListSpace.sizeClassCount();
+  }
+
+  /**
+   * Get the size class for a given number of bytes.
+   *
+   * NOTE: For optimal performance this call must be implemented in a way
+   * it can be inlined and optimized within the allocation sequence.
+   *
+   * @param bytes The number of bytes required to accommodate the object
+   * @return The size class capable of accommodating the allocation request.
+   */
+  @Inline
+  private int getSizeClass(int bytes) {
+    return space.getSizeClass(bytes);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeListLocal.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeListLocal.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeListLocal.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/alloc/SegregatedFreeListLocal.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,162 @@
+/*
+ *  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.mmtk.utility.alloc;
+
+import org.mmtk.policy.SegregatedFreeListSpace;
+import org.mmtk.utility.*;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This abstract class implements a simple segregated free list.<p>
+ *
+ * See: Wilson, Johnstone, Neely and Boles "Dynamic Storage
+ * Allocation: A Survey and Critical Review", IWMM 1995, for an
+ * overview of free list allocation and the various implementation
+ * strategies, including segregated free lists.<p>
+ *
+ * We maintain a number of size classes, each size class having a free
+ * list of available objects of that size (the list may be empty).  We
+ * call the storage elements "cells".  Cells reside within chunks of
+ * memory called "blocks".  All cells in a given block are of the same
+ * size (i.e. blocks are homogeneous with respect to size class).
+ * Each block maintains its own free list (free cells within that
+ * block).  For each size class a list of blocks is maintained, one of
+ * which will serve the role of the current free list.  When the free
+ * list on the current block is exhausted, the next block for that
+ * size class becomes the current block and its free list is used.  If
+ * there are no more blocks the a new block is allocated.<p>
+ */
+ at Uninterruptible
+public abstract class SegregatedFreeListLocal<S extends SegregatedFreeListSpace> extends SegregatedFreeList<S>
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  protected final AddressArray currentBlock;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param space The space with which this allocator will be associated
+   */
+  public SegregatedFreeListLocal(S space) {
+    super(space);
+    this.currentBlock = AddressArray.create(space.sizeClassCount());
+  }
+
+  /****************************************************************************
+   *
+   * Allocation
+   */
+
+  /**
+   * Allocate <code>bytes</code> contiguous bytes of non-zeroed
+   * memory.  First check if the fast path works.  This is needed
+   * since this method may be called in the context when the fast
+   * version was NOT just called.  If this fails, it will try finding
+   * another block with a non-empty free list, or allocating a new
+   * block.<p>
+   *
+   * This code should be relatively infrequently executed, so it is
+   * forced out of line to reduce pressure on the compilation of the
+   * core alloc routine.<p>
+   *
+   * Precondition: None
+   *
+   * Postconditions: A new cell has been allocated (not zeroed), and
+   * the block containing the cell has been placed on the appropriate
+   * free list data structures.  The free list itself is not updated
+   * (the caller must do so).<p>
+   *
+   * @param bytes The size of the object to occupy this space, in bytes.
+   * @param offset The alignment offset.
+   * @param align The requested alignment.
+   * @return The address of the first word or zero on failure.
+   */
+  @NoInline
+  public final Address allocSlowOnce(int bytes, int align, int offset) {
+    // Did a collection occur and provide a free cell?
+    bytes = getMaximumAlignedSize(bytes, align);
+    int sizeClass = space.getSizeClass(bytes);
+    Address cell = freeList.get(sizeClass);
+
+    if (cell.isZero()) {
+      Address block = currentBlock.get(sizeClass);
+      if (!block.isZero()) {
+        // Return the block if we currently own one
+        space.returnConsumedBlock(block, sizeClass);
+        currentBlock.set(sizeClass, Address.zero());
+      }
+
+      // Get a new block for allocation, if returned, it is guaranteed to have a free cell
+      block = space.getAllocationBlock(sizeClass, freeList);
+
+      if (!block.isZero()) {
+        // We have a new current block and free list.
+        currentBlock.set(sizeClass, block);
+        cell = freeList.get(sizeClass);
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!cell.isZero());
+      } else {
+        // Allocation Failure
+        return Address.zero();
+      }
+    }
+
+    freeList.set(sizeClass, cell.loadAddress());
+    /* Clear the free list link */
+    cell.store(Address.zero());
+    return alignAllocation(cell, align, offset);
+  }
+
+  /****************************************************************************
+   *
+   * Preserving (saving & restoring) free lists
+   */
+
+  /**
+   * Zero all of the current free list pointers, and refresh the
+   * <code>currentBlock</code> values, so instead of the free list
+   * pointing to free cells, it points to the block containing the
+   * free cells.  Then the free lists for each cell can be
+   * reestablished during GC.  If the free lists are being preserved
+   * on a per-block basis (eager mark-sweep and reference counting),
+   * then free lists are remembered for each block.
+   */
+  public final void flush() {
+    for (int sizeClass = 0; sizeClass < space.sizeClassCount(); sizeClass++) {
+      Address block = currentBlock.get(sizeClass);
+      if (!block.isZero()) {
+        Address cell = freeList.get(sizeClass);
+        space.returnBlock(block, sizeClass, cell);
+        currentBlock.set(sizeClass, Address.zero());
+        freeList.set(sizeClass, Address.zero());
+      }
+    }
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,120 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of addresses
+ */
+ at Uninterruptible public class AddressDeque extends LocalDeque
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+  public final String name;
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this queue will append
+   * its buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  public AddressDeque(String n, SharedDeque queue) {
+    super(queue);
+    name = n;
+  }
+
+  /**
+   * Insert an address into the address queue.
+   *
+   * @param addr the address to be inserted into the address queue
+   */
+  @Inline
+  public final void insert(Address addr) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr.isZero());
+    checkTailInsert(1);
+    uncheckedTailInsert(addr);
+  }
+
+  /**
+   * Insert an address into the address queue, force this out of line
+   * ("OOL"), in some circumstnaces it is too expensive to have the
+   * insert inlined, so this call is made.
+   *
+   * @param addr the address to be inserted into the address queue
+   */
+  @NoInline
+  public final void insertOOL(Address addr) {
+    insert(addr);
+  }
+
+  /**
+   * Push an address onto the address queue.
+   *
+   * @param addr the address to be pushed onto the address queue
+   */
+  @Inline
+  public final void push(Address addr) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr.isZero());
+    checkHeadInsert(1);
+    uncheckedHeadInsert(addr);
+  }
+
+  /**
+   * Push an address onto the address queue, force this out of line
+   * ("OOL"), in some circumstnaces it is too expensive to have the
+   * push inlined, so this call is made.
+   *
+   * @param addr the address to be pushed onto the address queue
+   */
+  @NoInline
+  public final void pushOOL(Address addr) {
+    push(addr);
+  }
+
+  /**
+   * Pop an address from the address queue, return zero if the queue
+   * is empty.
+   *
+   * @return The next address in the address queue, or zero if the
+   * queue is empty
+   */
+  @Inline
+  public final Address pop() {
+    if (checkDequeue(1)) {
+      return uncheckedDequeue();
+    } else {
+      return Address.zero();
+    }
+  }
+
+  @Inline
+  public final boolean isEmpty() {
+    return !checkDequeue(1);
+  }
+
+  @Inline
+  public final boolean isNonEmpty() {
+    return checkDequeue(1);
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressPairDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressPairDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressPairDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressPairDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,98 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of
+ * address pairs
+ */
+ at Uninterruptible public class AddressPairDeque extends LocalDeque implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this queue will append
+   * its buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  public AddressPairDeque(SharedDeque queue) {
+    super(queue);
+  }
+
+  /**
+   * Insert an address pair into the address queue.
+   *
+   * @param addr1 the first address to be inserted into the address queue
+   * @param addr2 the second address to be inserted into the address queue
+   */
+  public final void insert(Address addr1, Address addr2) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr1.isZero());
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr2.isZero());
+    checkTailInsert(2);
+    uncheckedTailInsert(addr1);
+    uncheckedTailInsert(addr2);
+  }
+
+  /**
+   * Push an address pair onto the address queue.
+   *
+   * @param addr1 the first value to be pushed onto the address queue
+   * @param addr2 the second value to be pushed onto the address queue
+   */
+  public final void push(Address addr1, Address addr2) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr1.isZero());
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr2.isZero());
+    checkHeadInsert(2);
+    uncheckedHeadInsert(addr2);
+    uncheckedHeadInsert(addr1);
+  }
+
+  /**
+   * Pop the first address in a pair from the address queue, return
+   * zero if the queue is empty.
+   *
+   * @return The next address in the address queue, or zero if the
+   * queue is empty
+   */
+  public final Address pop1() {
+    if (checkDequeue(2))
+      return uncheckedDequeue();
+    else
+      return Address.zero();
+  }
+
+  /**
+   * Pop the second address in a pair from the address queue.
+   *
+   * @return The next address in the address queue
+   */
+  public final Address pop2() {
+    return uncheckedDequeue();
+  }
+
+  public final boolean isEmpty() {
+    return !checkDequeue(2);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressTripleDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressTripleDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressTripleDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/AddressTripleDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,111 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.Uninterruptible;
+
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of
+ * address triples
+ */
+ at Uninterruptible public class AddressTripleDeque extends LocalDeque implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this queue will append its
+   * buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  AddressTripleDeque(SharedDeque queue) {
+    super(queue);
+  }
+
+  /**
+   * Insert an address triple into the address queue.
+   *
+   * @param addr1 the first address to be inserted into the address queue
+   * @param addr2 the second address to be inserted into the address queue
+   * @param addr3 the third address to be inserted into the address queue
+   */
+  public final void insert(Address addr1, Address addr2,
+                           Address addr3) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr1.isZero());
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr2.isZero());
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr3.isZero());
+    checkTailInsert(3);
+    uncheckedTailInsert(addr1);
+    uncheckedTailInsert(addr2);
+    uncheckedTailInsert(addr3);
+  }
+  /**
+   * Push an address pair onto the address queue.
+   *
+   * @param addr1 the first value to be pushed onto the address queue
+   * @param addr2 the second value to be pushed onto the address queue
+   * @param addr3 the third address to be pushed onto the address queue
+   */
+  public final void push(Address addr1, Address addr2, Address addr3) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr1.isZero());
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr2.isZero());
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr3.isZero());
+    checkHeadInsert(3);
+    uncheckedHeadInsert(addr3);
+    uncheckedHeadInsert(addr2);
+    uncheckedHeadInsert(addr1);
+  }
+
+  /**
+   * Pop the first address in a triple from the address queue, return
+   * zero if the queue is empty.
+   *
+   * @return The next address in the address queue, or zero if the
+   * queue is empty
+   */
+  public final Address pop1() {
+    if (checkDequeue(3))
+      return uncheckedDequeue();
+    else
+      return Address.zero();
+  }
+
+  /**
+   * Pop the second address in a triple from the address queue.
+   *
+   * @return The next address in the address queue
+   */
+  public final Address pop2() {
+    return uncheckedDequeue();
+  }
+
+
+  /**
+   * Pop the third address in a triple from the address queue.
+   *
+   * @return The next address in the address queue
+   */
+  public final Address pop3() {
+    return uncheckedDequeue();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/Deque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/Deque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/Deque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/Deque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,79 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Class that defines a doubly-linked double-ended queue (deque). The
+ * double-linking increases the space demands slightly, but makes it far
+ * more efficient to dequeue buffers and, for example, enables sorting of
+ * its contents.
+ */
+ at Uninterruptible class Deque implements Constants {
+
+  /****************************************************************************
+   *
+   * Protected instance methods
+   *
+   * protected int enqueued;
+   */
+
+  @Inline
+  protected final Offset bufferOffset(Address buf) {
+    return buf.toWord().and(BUFFER_MASK).toOffset();
+  }
+  @Inline
+  protected final Address bufferStart(Address buf) {
+    return buf.toWord().and(BUFFER_MASK.not()).toAddress();
+  }
+  @Inline
+  protected final Address bufferEnd(Address buf) {
+    return bufferStart(buf).plus(USABLE_BUFFER_BYTES);
+  }
+  @Inline
+  protected final Address bufferFirst(Address buf) {
+    return bufferStart(buf);
+  }
+  @Inline
+  protected final Address bufferLast(Address buf, int arity) {
+    return bufferStart(buf).plus(bufferLastOffset(arity));
+  }
+  @Inline
+  protected final Address bufferLast(Address buf) {
+    return bufferLast(buf, 1);
+  }
+  @Inline
+  protected final Offset bufferLastOffset(int arity) {
+    return Offset.fromIntZeroExtend(USABLE_BUFFER_BYTES - BYTES_IN_ADDRESS -
+        (USABLE_BUFFER_BYTES % (arity << LOG_BYTES_IN_ADDRESS)));
+  }
+
+  /****************************************************************************
+   *
+   * Private and protected static final fields (aka constants)
+   */
+  protected static final int LOG_PAGES_PER_BUFFER = 0;
+  protected static final int PAGES_PER_BUFFER = 1 << LOG_PAGES_PER_BUFFER;
+  private static final int LOG_BUFFER_SIZE = (LOG_BYTES_IN_PAGE + LOG_PAGES_PER_BUFFER);
+  protected static final int BUFFER_SIZE = 1 << LOG_BUFFER_SIZE;
+  protected static final Word BUFFER_MASK = Word.one().lsh(LOG_BUFFER_SIZE).minus(Word.one());
+  protected static final int NEXT_FIELD_OFFSET = BYTES_IN_ADDRESS;
+  protected static final int META_DATA_SIZE = 2 * BYTES_IN_ADDRESS;
+  protected static final int USABLE_BUFFER_BYTES = BUFFER_SIZE - META_DATA_SIZE;
+  protected static final Address TAIL_INITIAL_VALUE = Address.zero();
+  protected static final Address HEAD_INITIAL_VALUE = Address.zero();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,158 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Note this may perform poorly when being used as a FIFO structure with
+ * insertHead and pop operations operating on the same buffer.  This
+ * only uses the fields inherited from <code>LocalQueue</code>, but adds
+ * the ability for entries to be added to the head of the deque and popped
+ * from the rear.
+ */
+ at Uninterruptible public class LocalDeque extends LocalQueue
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared deque to which this local deque will append
+   * its buffers (when full or flushed).
+   */
+  LocalDeque(SharedDeque queue) {
+    super(queue);
+  }
+
+  /**
+   * Flush the buffer to the shared deque (this will make any entries
+   * in the buffer visible to any other consumer associated with the
+   * shared deque).
+   */
+  @Override
+  public final void flushLocal() {
+    super.flushLocal();
+    if (head.NE(Deque.HEAD_INITIAL_VALUE)) {
+      closeAndInsertHead(queue.getArity());
+      head = Deque.HEAD_INITIAL_VALUE;
+    }
+  }
+
+  /****************************************************************************
+   *
+   * Protected instance methods
+   */
+
+  /**
+   * Check whether there is space in the buffer for a pending insert.
+   * If there is not sufficient space, allocate a new buffer
+   * (dispatching the full buffer to the shared deque if not null).
+   *
+   * @param arity The arity of the values stored in this deque: the
+   * buffer must contain enough space for this many words.
+   */
+  @Inline
+  protected final void checkHeadInsert(int arity) {
+    if (bufferOffset(head).EQ(bufferSentinel(arity)) ||
+        head.EQ(HEAD_INITIAL_VALUE))
+      headOverflow(arity);
+    else if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(head).sLE(bufferLastOffset(arity)));
+  }
+
+  /**
+   * Insert a value at the front of the deque (and buffer).  This is
+   * <i>unchecked</i>.  The caller must first call
+   * <code>checkHeadInsert()</code> to ensure the buffer can accommodate
+   * the insertion.
+   *
+   * @param value the value to be inserted.
+   */
+  @Inline
+  protected final void uncheckedHeadInsert(Address value) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(head).sLT(bufferSentinel(queue.getArity())));
+    head.store(value);
+    head = head.plus(BYTES_IN_ADDRESS);
+    // if (Interface.VerifyAssertions) enqueued++;
+  }
+
+  /****************************************************************************
+   *
+   * Private instance methods and fields
+   */
+
+  /**
+   * Buffer space has been exhausted, allocate a new buffer and enqueue
+   * the existing buffer (if any).
+   *
+   * @param arity The arity of this buffer (used for sanity test only).
+   */
+  private void headOverflow(int arity) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
+    if (head.NE(Deque.HEAD_INITIAL_VALUE))
+      closeAndInsertHead(arity);
+
+    head = queue.alloc();
+    Plan.checkForAsyncCollection(); // possible side-effect of alloc()
+  }
+
+  /**
+   * Close the head buffer and enqueue it at the front of the
+   * shared buffer deque.
+   *
+   *  @param arity The arity of this buffer.
+   */
+  @Inline
+  private void closeAndInsertHead(int arity) {
+    queue.enqueue(head, arity, false);
+  }
+
+  /**
+   * The tail is empty (or null), and the shared deque has no buffers
+   * available.  If the head has sufficient entries, consume the head.
+   * Otherwise try wait on the shared deque until either all other
+   * clients of the reach exhaustion or a buffer becomes
+   * available.
+   *
+   * @param arity The arity of this buffer
+   * @return True if the consumer has eaten all of the entries
+   */
+  @SuppressWarnings("unused")
+  private boolean tailStarved(int arity) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
+    // entries in tail, so consume tail
+    if (!bufferOffset(head).isZero()) {
+      tailBufferEnd = head;
+      tail = bufferStart(tailBufferEnd);
+      head = Deque.HEAD_INITIAL_VALUE;
+      return false;
+    }
+
+    // Wait for another entry to materialize...
+    tailBufferEnd = queue.dequeueAndWait(arity, true);
+    tail = bufferStart(tail);
+
+    // return true if a) there is not a tail buffer or b) it is empty
+    return (tail.EQ(Deque.TAIL_INITIAL_VALUE) || tail.EQ(tailBufferEnd));
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalQueue.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalQueue.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalQueue.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalQueue.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,158 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements a local (<i>unsynchronized</i>) queue.
+ * A queue is strictly FIFO.<p>
+ *
+ * Each instance stores word-sized values into a local buffer.  When
+ * the buffer is full, or if the <code>flushLocal()</code> method is
+ * called, the buffer enqueued at the tail of a
+ * <code>SharedDeque</code>.
+ *
+ * The implementation is intended to be as efficient as possible, in
+ * time and space, and is the basis for the <code>TraceBuffer</code> used by
+ * heap trace generation. Each instance adds a single field to those inherited
+ * from the SSB: a bump pointer.
+ *
+ * Preconditions: Buffers are always aligned on buffer-size address
+ * boundaries.<p>
+ *
+ * Invariants: Buffers are filled such that tuples (of the specified
+ * arity) are packed to the low end of the buffer.  Thus buffer
+ * underflows will always arise when then cursor is buffer-size aligned.
+ */
+ at Uninterruptible class LocalQueue extends LocalSSB implements Constants {
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this local ssb will append
+   * its buffers (when full or flushed).
+   */
+  LocalQueue(SharedDeque queue) {
+    super(queue);
+  }
+
+ /****************************************************************************
+   *
+   * Protected instance methods and fields
+   */
+  @Entrypoint
+  protected Address head; // the start of the buffer
+
+  /**
+   * Reset the local buffer (throwing away any local entries).
+   */
+  public void resetLocal() {
+    super.resetLocal();
+    head = Deque.HEAD_INITIAL_VALUE;
+  }
+
+  /**
+   * Check whether there are values in the buffer for a pending dequeue.
+   * If there is not data, grab the first buffer on the shared queue
+   * (after freeing the buffer).
+   *
+   * @param arity The arity of the values stored in this queue: the
+   * buffer must contain enough space for this many words.
+   */
+  @Inline
+  protected final boolean checkDequeue(int arity) {
+    if (bufferOffset(head).isZero()) {
+      return dequeueUnderflow(arity);
+    } else {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(head).sGE(Word.fromIntZeroExtend(arity).lsh(LOG_BYTES_IN_ADDRESS).toOffset()));
+      return true;
+    }
+  }
+
+  /**
+   * Dequeue a value from the buffer.  This is <i>unchecked</i>.  The
+   * caller must first call <code>checkDequeue()</code> to ensure the
+   * buffer has and entry to be removed.
+   *
+   * @return The first entry on the queue.
+   */
+  @Inline
+  protected final Address uncheckedDequeue(){
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(head).sGE(Offset.fromIntZeroExtend(BYTES_IN_ADDRESS)));
+    head = head.minus(BYTES_IN_ADDRESS);
+    return head.loadAddress();
+  }
+
+  /**
+   * The head is empty (or null), and the shared queue has no buffers
+   * available.  If the tail has sufficient entries, consume the tail.
+   * Otherwise try wait on the global queue until either all other
+   * clients of the queue reach exhaustion or a buffer becomes
+   * available.
+   *
+   * @param arity The arity of this buffer
+   * @return True if the consumer has eaten all the entries
+   */
+  protected final boolean headStarved(int arity) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
+
+    // If the tail has entries...
+    if (tail.NE(tailBufferEnd)) {
+      head = normalizeTail(arity).plus(BYTES_IN_ADDRESS);
+      tail = Deque.TAIL_INITIAL_VALUE;
+      tailBufferEnd = Deque.TAIL_INITIAL_VALUE;
+      // Return that we acquired more entries
+      return false;
+    }
+    // Wait for another entry to materialize...
+    head = queue.dequeueAndWait(arity);
+    // return true if a) there is a head buffer, and b) it is non-empty
+    return (head.EQ(Deque.HEAD_INITIAL_VALUE) || bufferOffset(head).isZero());
+  }
+
+  /****************************************************************************
+   *
+   * Private instance methods
+   */
+
+  /**
+   * There are not sufficient entries in the head buffer for a pending
+   * dequeue.  Acquire a new head buffer.  If the shared queue has no
+   * buffers available, consume the tail if necessary.  Return false
+   * if entries cannot be acquired.
+   *
+   * @param arity The arity of this buffer (used for sanity test only).
+   * @return True if there the head buffer has been successfully
+   * replenished.
+   */
+  @NoInline
+  private boolean dequeueUnderflow(int arity) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
+    do {
+      if (head.NE(Deque.HEAD_INITIAL_VALUE))
+        queue.free(head);
+      head = queue.dequeue(arity);
+    } while (head.NE(Deque.HEAD_INITIAL_VALUE) && bufferOffset(head).isZero());
+
+    if (head.EQ(Deque.HEAD_INITIAL_VALUE))
+      return !headStarved(arity);
+
+    return true;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalSSB.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalSSB.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalSSB.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/LocalSSB.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,214 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements a local (<i>unsynchronized</i>) sequential
+ * store buffer.  An SSB is strictly FIFO (although this class does
+ * not implement dequeuing).<p>
+ *
+ * Each instance stores word-sized values into a local buffer.  When
+ * the buffer is full, or if the <code>flushLocal()</code> method is
+ * called, the buffer enqueued at the tail of a
+ * <code>SharedDeque</code>.  This class provides no mechanism for
+ * dequeing.<p>
+ *
+ * The implementation is intended to be as efficient as possible, in
+ * time and space, as it is used in critical code such as the GC work
+ * queue and the write buffer used by many "remembering"
+ * collectors. Each instance has just two fields: a bump pointer and a
+ * pointer to the <code>SharedDeque</code><p>
+ *
+ * Preconditions: Buffers are always aligned on buffer-size address
+ * boundaries.<p>
+ *
+ * Invariants: Buffers are filled such that tuples (of the specified
+ * arity) are packed to the low end of the buffer.  Thus buffer
+ * overflows on inserts and pops (underflow actually) will always arise
+ * when then cursor is buffer-size aligned.
+ */
+ at Uninterruptible class LocalSSB extends Deque implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this local ssb will append
+   * its buffers (when full or flushed).
+   */
+  LocalSSB(SharedDeque queue) {
+    this.queue = queue;
+    resetLocal();
+  }
+
+  /**
+   * Flush the buffer and add it to the shared queue (this will
+   * make any entries in the buffer visible to any consumer associated
+   * with the shared queue).
+   */
+  public void flushLocal() {
+    if (tail.NE(Deque.TAIL_INITIAL_VALUE)) {
+      closeAndEnqueueTail(queue.getArity());
+      tail = Deque.TAIL_INITIAL_VALUE;
+      tailBufferEnd = Deque.TAIL_INITIAL_VALUE;
+    }
+  }
+
+  public void reset() {
+    resetLocal();
+  }
+
+ /****************************************************************************
+   *
+   * Protected instance methods and fields
+   */
+  @Entrypoint
+  protected Address tail; // the location in the buffer
+  protected Address tailBufferEnd; // the end of the buffer
+  protected final SharedDeque queue; // the shared queue
+
+  /**
+   * Reset the local buffer (throwing away any local entries).
+   */
+  public void resetLocal() {
+    tail = Deque.TAIL_INITIAL_VALUE;
+    tailBufferEnd = Deque.TAIL_INITIAL_VALUE;
+  }
+
+  /**
+   * Check whether there is space in the buffer for a pending insert.
+   * If there is not sufficient space, allocate a new buffer
+   * (dispatching the full buffer to the shared queue if not null).
+   *
+   * @param arity The arity of the values stored in this SSB: the
+   * buffer must contain enough space for this many words.
+   */
+  @Inline(value=Inline.When.AssertionsDisabled)
+  protected final void checkTailInsert(int arity) {
+    if (bufferOffset(tail).isZero())
+      tailOverflow(arity);
+    else if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(tail).sGE(Word.fromIntZeroExtend(arity).lsh(LOG_BYTES_IN_ADDRESS).toOffset()));
+  }
+
+  /**
+   * Insert a value into the buffer.  This is <i>unchecked</i>.  The
+   * caller must first call <code>checkInsert()</code> to ensure the
+   * buffer can accommodate the insertion.
+   *
+   * @param value the value to be inserted.
+   */
+  @Inline(value=Inline.When.AssertionsDisabled)
+  protected final void uncheckedTailInsert(Address value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(tail).sGE(Offset.fromIntZeroExtend(BYTES_IN_ADDRESS)));
+    tail = tail.minus(BYTES_IN_ADDRESS);
+    tail.store(value);
+    // if (Interface.VerifyAssertions) enqueued++;
+  }
+
+  /**
+   * In the case where a buffer must be flushed before being
+   * filled (either to the queue or to the head), the entries must be
+   * slid to the base of the buffer in order to preserve the invariant
+   * that all non-tail buffers will have entries starting at the base
+   * (which allows a simple test against the base to be used when
+   * popping entries).  This is <i>expensive</i>, so should be
+   * avoided.
+   *
+   * @param arity The arity of the buffer in question
+   * @return The last slot in the normalized buffer that contains an entry
+   */
+  protected final Address normalizeTail(int arity) {
+    Address src = tail;
+    Address tgt = bufferFirst(tail);
+    Address last = tgt.plus(bufferLastOffset(arity).minus(bufferOffset(tail)));
+    while (tgt.LE(last)) {
+      tgt.store(src.loadAddress());
+      src = src.plus(BYTES_IN_ADDRESS);
+      tgt = tgt.plus(BYTES_IN_ADDRESS);
+    }
+    return last;
+  }
+
+  /**
+   * Return the sentinel offset for a buffer of a given arity.  This is used
+   * both to compute the address at the end of the buffer.
+   *
+   * @param arity The arity of this buffer
+   * @return The sentinel offset value for a buffer of the given arity.
+   */
+  @Inline
+  protected final Offset bufferSentinel(int arity) {
+    return bufferLastOffset(arity).plus(BYTES_IN_ADDRESS);
+  }
+
+  /****************************************************************************
+   *
+   * Private instance methods
+   */
+
+  /**
+   * Buffer space has been exhausted, allocate a new buffer and enqueue
+   * the existing buffer (if any).
+   *
+   * @param arity The arity of this buffer (used for sanity test only).
+   */
+  private void tailOverflow(int arity) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
+    if (tail.NE(Deque.TAIL_INITIAL_VALUE)) {
+      closeAndEnqueueTail(arity);
+    }
+    tail = queue.alloc().plus(bufferSentinel(arity));
+    tailBufferEnd = tail;
+    Plan.checkForAsyncCollection(); // possible side-effect of alloc()
+  }
+
+  /**
+   * Close the tail buffer (normalizing if necessary), and enqueue it
+   * at the tail of the shared buffer queue.
+   *
+   *  @param arity The arity of this buffer.
+   */
+  @NoInline
+  private void closeAndEnqueueTail(int arity) {
+    Address last;
+    if (!bufferOffset(tail).isZero()) {
+      // prematurely closed
+      last = normalizeTail(arity);
+    } else {
+      // a full tail buffer
+      last = tailBufferEnd.minus(BYTES_IN_ADDRESS);
+    }
+    queue.enqueue(last.plus(BYTES_IN_ADDRESS), arity, true);
+  }
+
+  /**
+   * Return true if this SSB is locally empty
+   *
+   * @return true if this SSB is locally empty
+   */
+  public final boolean isFlushed() {
+    return tail.EQ(Deque.TAIL_INITIAL_VALUE);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceBuffer.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceBuffer.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceBuffer.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceBuffer.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,128 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.plan.TransitiveClosure;
+import org.mmtk.utility.Constants;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class is a combination of a Deque and a TraceStep, designed to include
+ * intelligent processing of child references as objects are scanned.
+ *
+ * @see org.mmtk.plan.TransitiveClosure
+ */
+ at Uninterruptible
+public abstract class ObjectReferenceBuffer extends TransitiveClosure implements Constants {
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private final ObjectReferenceDeque values;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name of the underlying deque.
+   * @param queue The shared deque that is used.
+   */
+  public ObjectReferenceBuffer(String name, SharedDeque queue) {
+    values = new ObjectReferenceDeque(name, queue);
+  }
+
+  /**
+   * Trace an edge during GC.
+   *
+   * @param source The source of the reference.
+   * @param slot The location containing the object reference.
+   */
+  @Inline
+  public final void processEdge(ObjectReference source, Address slot) {
+    ObjectReference object = VM.activePlan.global().loadObjectReference(slot);
+    process(object);
+  }
+
+  /**
+   * This is the method that ensures
+   *
+   * @param object The object to process.
+   */
+  protected abstract void process(ObjectReference object);
+
+  /**
+   * Process each of the child objects for the passed object.
+   *
+   * @param object The object to process the children of.
+   */
+  @Inline
+  public final void processChildren(ObjectReference object) {
+    VM.scanning.scanObject(this, object);
+  }
+
+  /**
+   * Pushes an object onto the queue, forcing an inlined sequence.
+   *
+   * @param object The object to push.
+   */
+  @Inline
+  public final void push(ObjectReference object) {
+    values.push(object);
+  }
+
+  /**
+   * Pushes an object onto the queue, forcing an out of line sequence.
+   *
+   * @param object The object to push.
+   */
+  @Inline
+  public final void pushOOL(ObjectReference object) {
+    values.pushOOL(object);
+  }
+
+  /**
+   * Retrives an object.
+   *
+   * @return The object retrieved.
+   */
+  @Inline
+  public final ObjectReference pop() {
+    return values.pop();
+  }
+
+  @Inline
+  public final boolean isEmpty() {
+    return values.isEmpty();
+  }
+
+  /**
+   * Flushes all local state back to the shared queue.
+   */
+  public final void flushLocal() {
+    values.flushLocal();
+  }
+
+  /**
+   * Return true if this buffer is locally empty
+   */
+  public final boolean isFlushed() {
+    return values.isFlushed();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/ObjectReferenceDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,109 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of
+ * object references
+ */
+ at Uninterruptible public class ObjectReferenceDeque extends LocalDeque
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+  public final String name;
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this queue will append
+   * its buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  public ObjectReferenceDeque(String n, SharedDeque queue) {
+    super(queue);
+    name = n;
+  }
+
+  /**
+   * Insert an object into the object queue.
+   *
+   * @param object the object to be inserted into the object queue
+   */
+  @Inline
+  public final void insert(ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!object.isNull());
+    checkTailInsert(1);
+    uncheckedTailInsert(object.toAddress());
+  }
+
+  /**
+   * Push an object onto the object queue.
+   *
+   * @param object the object to be pushed onto the object queue
+   */
+  @Inline
+  public final void push(ObjectReference object) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!object.isNull());
+    checkHeadInsert(1);
+    uncheckedHeadInsert(object.toAddress());
+  }
+
+  /**
+   * Push an object onto the object queue, force this out of line
+   * ("OOL"), in some circumstnaces it is too expensive to have the
+   * push inlined, so this call is made.
+   *
+   * @param object the object to be pushed onto the object queue
+   */
+  @NoInline
+  public final void pushOOL(ObjectReference object) {
+    push(object);
+  }
+
+  /**
+   * Pop an object from the object queue, return zero if the queue
+   * is empty.
+   *
+   * @return The next object in the object queue, or zero if the
+   * queue is empty
+   */
+  @Inline
+  public final ObjectReference pop() {
+    if (checkDequeue(1)) {
+      return uncheckedDequeue().toObjectReference();
+    } else {
+      return ObjectReference.nullReference();
+    }
+  }
+
+  @Inline
+  public final boolean isEmpty() {
+    return !checkDequeue(1);
+  }
+
+  @Inline
+  public final boolean isNonEmpty() {
+    return checkDequeue(1);
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SharedDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SharedDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SharedDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SharedDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,497 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.policy.RawPageSpace;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Constants;
+import org.mmtk.utility.Log;
+import org.mmtk.vm.Lock;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.Entrypoint;
+import org.vmmagic.pragma.Inline;
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Address;
+import org.vmmagic.unboxed.Offset;
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of buffers
+ * for shared use.  The data can be added to and removed from either end
+ * of the deque.
+ */
+ at Uninterruptible
+public class SharedDeque extends Deque implements Constants {
+  private static final boolean DISABLE_WAITING = true;
+  private static final Offset NEXT_OFFSET = Offset.zero();
+  private static final Offset PREV_OFFSET = Offset.fromIntSignExtend(BYTES_IN_ADDRESS);
+
+  private static final boolean TRACE = false;
+  private static final boolean TRACE_DETAIL = false;
+  private static final boolean TRACE_BLOCKERS = false;
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   */
+  public SharedDeque(String name, RawPageSpace rps, int arity) {
+    this.rps = rps;
+    this.arity = arity;
+    this.name = name;
+    lock = VM.newLock("SharedDeque");
+    clearCompletionFlag();
+    head = HEAD_INITIAL_VALUE;
+    tail = TAIL_INITIAL_VALUE;
+  }
+
+  /** Get the arity (words per entry) of this queue */
+  @Inline
+  final int getArity() { return arity; }
+
+  /**
+   * Enqueue a block on the head or tail of the shared queue
+   *
+   * @param buf
+   * @param arity
+   * @param toTail
+   */
+  final void enqueue(Address buf, int arity, boolean toTail) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == this.arity);
+    lock();
+    if (toTail) {
+      // Add to the tail of the queue
+      setNext(buf, Address.zero());
+      if (tail.EQ(TAIL_INITIAL_VALUE))
+        head = buf;
+      else
+        setNext(tail, buf);
+      setPrev(buf, tail);
+      tail = buf;
+    } else {
+      // Add to the head of the queue
+      setPrev(buf, Address.zero());
+      if (head.EQ(HEAD_INITIAL_VALUE))
+        tail = buf;
+      else
+        setPrev(head, buf);
+      setNext(buf, head);
+      head = buf;
+    }
+    bufsenqueued++;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(checkDequeLength(bufsenqueued));
+    unlock();
+  }
+
+  public final void clearDeque(int arity) {
+    Address buf = dequeue(arity);
+    while (!buf.isZero()) {
+      free(bufferStart(buf));
+      buf = dequeue(arity);
+    }
+    setCompletionFlag();
+  }
+
+  @Inline
+  final Address dequeue(int arity) {
+    return dequeue(arity, false);
+  }
+
+  final Address dequeue(int arity, boolean fromTail) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == this.arity);
+    return dequeue(false, fromTail);
+  }
+
+  @Inline
+  final Address dequeueAndWait(int arity) {
+    return dequeueAndWait(arity, false);
+  }
+
+  final Address dequeueAndWait(int arity, boolean fromTail) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == this.arity);
+    Address buf = dequeue(false, fromTail);
+    if (buf.isZero() && (!complete())) {
+      buf = dequeue(true, fromTail);  // Wait inside dequeue
+    }
+    return buf;
+  }
+
+  /**
+   * Prepare for parallel processing. All active GC threads will
+   * participate, and pop operations will block until all work
+   * is complete.
+   */
+  public final void prepare() {
+    if (DISABLE_WAITING) {
+      prepareNonBlocking();
+    } else {
+      /* This should be the normal mode of operation once performance is fixed */
+      prepare(VM.collection.activeGCThreads());
+    }
+  }
+
+  /**
+   * Prepare for processing where pop operations on the deques
+   * will never block.
+   */
+  public final void prepareNonBlocking() {
+    prepare(1);
+  }
+
+  /**
+   * Prepare for parallel processing where a specific number
+   * of threads take part.
+   *
+   * @param consumers # threads taking part.
+   */
+  private void prepare(int consumers) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(numConsumersWaiting == 0);
+    setNumConsumers(consumers);
+    clearCompletionFlag();
+  }
+
+  public final void reset() {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(numConsumersWaiting == 0);
+    clearCompletionFlag();
+    setNumConsumersWaiting(0);
+    assertExhausted();
+  }
+
+  public final void assertExhausted() {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(head.isZero() && tail.isZero());
+  }
+
+  @Inline
+  final Address alloc() {
+    Address rtn = rps.acquire(PAGES_PER_BUFFER);
+    if (rtn.isZero()) {
+      Space.printUsageMB();
+      VM.assertions.fail("Failed to allocate space for queue.  Is metadata virtual memory exhausted?");
+    }
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn.EQ(bufferStart(rtn)));
+    return rtn;
+  }
+
+  @Inline
+  final void free(Address buf) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(buf.EQ(bufferStart(buf)) && !buf.isZero());
+    rps.release(buf);
+  }
+
+  @Inline
+  public final int enqueuedPages() {
+    return (int) (bufsenqueued * PAGES_PER_BUFFER);
+  }
+
+  /****************************************************************************
+   *
+   * Private instance methods and fields
+   */
+
+  /** The name of this shared deque - for diagnostics */
+  private final String name;
+
+  /** Raw page space from which to allocate */
+  private RawPageSpace rps;
+
+  /** Number of words per entry */
+  private final int arity;
+
+  /** Completion flag - set when all consumers have arrived at the barrier */
+  @Entrypoint
+  private volatile int completionFlag;
+
+  /** # active threads - processing is complete when # waiting == this */
+  @Entrypoint
+  private volatile int numConsumers;
+
+  /** # threads waiting */
+  @Entrypoint
+  private volatile int numConsumersWaiting;
+
+  /** Head of the shared deque */
+  @Entrypoint
+  protected volatile Address head;
+
+  /** Tail of the shared deque */
+  @Entrypoint
+  protected volatile Address tail;
+  @Entrypoint
+  private volatile int bufsenqueued;
+  private Lock lock;
+
+  private static final long WARN_PERIOD = (long)(2*1E9);
+  private static final long TIMEOUT_PERIOD = 10 * WARN_PERIOD;
+
+  /**
+   * Dequeue a block from the shared pool.  If 'waiting' is true, and the
+   * queue is empty, wait for either a new block to show up or all the
+   * other consumers to join us.
+   *
+   * @param waiting
+   * @param fromTail
+   * @return the Address of the block
+   */
+  private Address dequeue(boolean waiting, boolean fromTail) {
+    lock();
+    Address rtn = ((fromTail) ? tail : head);
+    if (rtn.isZero()) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tail.isZero() && head.isZero());
+      // no buffers available
+      if (waiting) {
+        int ordinal = TRACE ? 0 : VM.activePlan.collector().getId();
+        setNumConsumersWaiting(numConsumersWaiting + 1);
+        while (rtn.isZero()) {
+          if (numConsumersWaiting == numConsumers)
+            setCompletionFlag();
+          if (TRACE) {
+            Log.write("-- ("); Log.write(ordinal);
+            Log.write(") joining wait queue of SharedDeque(");
+            Log.write(name); Log.write(") ");
+            Log.write(numConsumersWaiting); Log.write("/");
+            Log.write(numConsumers);
+            Log.write(" consumers waiting");
+            if (complete()) Log.write(" WAIT COMPLETE");
+            Log.writeln();
+            if (TRACE_BLOCKERS)
+              VM.assertions.dumpStack();
+          }
+          unlock();
+          // Spin and wait
+          spinWait(fromTail);
+
+          if (complete()) {
+            if (TRACE) {
+              Log.write("-- ("); Log.write(ordinal); Log.writeln(") EXITING");
+            }
+            lock();
+            setNumConsumersWaiting(numConsumersWaiting - 1);
+            unlock();
+            return Address.zero();
+          }
+          lock();
+          // Re-get the list head/tail while holding the lock
+          rtn = ((fromTail) ? tail : head);
+        }
+        setNumConsumersWaiting(numConsumersWaiting - 1);
+        if (TRACE) {
+          Log.write("-- ("); Log.write(ordinal); Log.write(") resuming work ");
+          Log.write(" n="); Log.writeln(numConsumersWaiting);
+        }
+      } else {
+        unlock();
+        return Address.zero();
+      }
+    }
+    if (fromTail) {
+      // dequeue the tail buffer
+      setTail(getPrev(tail));
+      if (head.EQ(rtn)) {
+        setHead(Address.zero());
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tail.isZero());
+      } else {
+        setNext(tail, Address.zero());
+      }
+    } else {
+      // dequeue the head buffer
+      setHead(getNext(head));
+      if (tail.EQ(rtn)) {
+        setTail(Address.zero());
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(head.isZero());
+      } else {
+        setPrev(head, Address.zero());
+      }
+    }
+    bufsenqueued--;
+    unlock();
+    return rtn;
+  }
+
+  /**
+   * Spinwait for GC work to arrive
+   *
+   * @param fromTail Check the head or the tail ?
+   */
+  private void spinWait(boolean fromTail) {
+    long startNano = 0;
+    long lastElapsedNano = 0;
+    while (true) {
+      long startCycles = VM.statistics.cycles();
+      long endCycles = startCycles + ((long) 1e9); // a few hundred milliseconds more or less.
+      long nowCycles;
+      do {
+        VM.memory.isync();
+        Address rtn = ((fromTail) ? tail : head);
+        if (!rtn.isZero() || complete()) return;
+        nowCycles = VM.statistics.cycles();
+      } while (startCycles < nowCycles && nowCycles < endCycles); /* check against both ends to guard against CPU migration */
+
+      /*
+       * According to the cycle counter, we've been spinning for a while.
+       * Time to check nanoTime and see if we should print a warning and/or fail.
+       * We lock the deque while doing this to avoid interleaved messages from multiple threads.
+       */
+      lock();
+      if (startNano == 0) {
+        startNano = VM.statistics.nanoTime();
+      } else {
+        long nowNano = VM.statistics.nanoTime();
+        long elapsedNano = nowNano - startNano;
+        if (elapsedNano - lastElapsedNano > WARN_PERIOD) {
+          Log.write("GC Warning: SharedDeque("); Log.write(name);
+          Log.write(") wait has reached "); Log.write(VM.statistics.nanosToSecs(elapsedNano));
+          Log.write(", "); Log.write(numConsumersWaiting); Log.write("/");
+          Log.write(numConsumers); Log.writeln(" threads waiting");
+          lastElapsedNano = elapsedNano;
+        }
+        if (elapsedNano > TIMEOUT_PERIOD) {
+          unlock();   // To allow other GC threads to die in turn
+          VM.assertions.fail("GC Error: SharedDeque Timeout");
+        }
+      }
+      unlock();
+    }
+  }
+
+  /**
+   * Set the "next" pointer in a buffer forming the linked buffer chain.
+   *
+   * @param buf The buffer whose next field is to be set.
+   * @param next The reference to which next should point.
+   */
+  private static void setNext(Address buf, Address next) {
+    buf.store(next, NEXT_OFFSET);
+  }
+
+  /**
+   * Get the "next" pointer in a buffer forming the linked buffer chain.
+   *
+   * @param buf The buffer whose next field is to be returned.
+   * @return The next field for this buffer.
+   */
+  protected final Address getNext(Address buf) {
+    return buf.loadAddress(NEXT_OFFSET);
+  }
+
+  /**
+   * Set the "prev" pointer in a buffer forming the linked buffer chain.
+   *
+   * @param buf The buffer whose next field is to be set.
+   * @param prev The reference to which prev should point.
+   */
+  private void setPrev(Address buf, Address prev) {
+    buf.store(prev, PREV_OFFSET);
+  }
+
+  /**
+   * Get the "next" pointer in a buffer forming the linked buffer chain.
+   *
+   * @param buf The buffer whose next field is to be returned.
+   * @return The next field for this buffer.
+   */
+  protected final Address getPrev(Address buf) {
+    return buf.loadAddress(PREV_OFFSET);
+  }
+
+  /**
+   * Check the number of buffers in the work queue (for debugging
+   * purposes).
+   *
+   * @param length The number of buffers believed to be in the queue.
+   * @return True if the length of the queue matches length.
+   */
+  private boolean checkDequeLength(int length) {
+    Address top = head;
+    int l = 0;
+    while (!top.isZero() && l <= length) {
+      top = getNext(top);
+      l++;
+    }
+    return l == length;
+  }
+
+  /**
+   * Lock this shared queue.  We use one simple low-level lock to
+   * synchronize access to the shared queue of buffers.
+   */
+  private void lock() {
+    lock.acquire();
+  }
+
+  /**
+   * Release the lock.  We use one simple low-level lock to synchronize
+   * access to the shared queue of buffers.
+   */
+  private void unlock() {
+    lock.release();
+  }
+
+  /**
+   * Is the current round of processing complete ?
+   */
+  private boolean complete() {
+    return completionFlag == 1;
+  }
+
+  /**
+   * Set the completion flag.
+   */
+  @Inline
+  private void setCompletionFlag() {
+    if (TRACE_DETAIL) {
+      Log.writeln("# setCompletionFlag: ");
+    }
+    completionFlag = 1;
+  }
+
+  /**
+   * Clear the completion flag.
+   */
+  @Inline
+  private void clearCompletionFlag() {
+    if (TRACE_DETAIL) {
+      Log.writeln("# clearCompletionFlag: ");
+    }
+    completionFlag = 0;
+  }
+
+  @Inline
+  private void setNumConsumers(int newNumConsumers) {
+    if (TRACE_DETAIL) {
+      Log.write("# Num consumers "); Log.writeln(newNumConsumers);
+    }
+    numConsumers = newNumConsumers;
+  }
+
+  @Inline
+  private void setNumConsumersWaiting(int newNCW) {
+    if (TRACE_DETAIL) {
+      Log.write("# Num consumers waiting "); Log.writeln(newNCW);
+    }
+    numConsumersWaiting = newNCW;
+  }
+
+  @Inline
+  private void setHead(Address newHead) {
+    head = newHead;
+    VM.memory.sync();
+  }
+
+  @Inline
+  private void setTail(Address newTail) {
+    tail = newTail;
+    VM.memory.sync();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortSharedDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortSharedDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortSharedDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortSharedDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,372 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.policy.RawPageSpace;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of buffers
+ * for shared use.  The data can be added to and removed from either end
+ * of the deque. This class is based upon the SharedQueue class.  The sorting
+ * routines were modified from code written by Narendran Sachindran and
+ * Matthew Hertz for GCTk.
+ */
+ at Uninterruptible public abstract class SortSharedDeque extends SharedDeque {
+
+
+  private static final int BYTES_PUSHED = BYTES_IN_ADDRESS * 5;
+  private static final int MAX_STACK_SIZE = BYTES_PUSHED * 64;
+  private static final Offset INSERTION_SORT_LIMIT = Offset.fromIntSignExtend(80);
+
+  /***********************************************************************
+   *
+   * Class variables
+   */
+
+  /**
+   * Constructor
+   *
+   * @param rps The space from which the instance should obtain buffers.
+   */
+  public SortSharedDeque(String name, RawPageSpace rps, int arity) {
+    super(name, rps, arity);
+    stackBase = AddressArray.create(MAX_STACK_SIZE);
+    stackLoc = 0;
+  }
+
+  /***********************************************************************
+   *
+   * Sorting methods, utilities, and instance variables
+   */
+
+
+  /**
+   * Return the sorting key for the object passed as a parameter.
+   *
+   * @param obj The address of the object whose key is wanted
+   * @return The value of the sorting key for this object
+   */
+  protected abstract Word getKey(Address obj);
+
+  private static final Word mask16 = Word.fromIntZeroExtend(0xffff0000);
+  private static final Word mask8 = Word.fromIntZeroExtend(0x0000ff00);
+  private static final Word mask4 = Word.fromIntZeroExtend(0x000000f0);
+  private static final Word mask2 = Word.fromIntZeroExtend(0x0000000c);
+  private static final Word mask1 = Word.fromIntZeroExtend(0x00000002);
+
+  /**
+   * Find the highest bit that is set in a longword and return a mask
+   * with only that bit set.
+   *
+   * @param addr Value for which the mask needs to be found
+   * @return The highest bit set in the parameter
+   */
+  private static Word getBitMask(Word addr) {
+    int shift = 0;
+    if (!addr.and(mask16).isZero()) {
+      addr = addr.rshl(16);
+      shift += 16;
+    }
+    if (!addr.and(mask8).isZero()) {
+      addr = addr.rshl(8);
+      shift += 8;
+    }
+    if (!addr.and(mask4).isZero()) {
+      addr = addr.rshl(4);
+      shift += 4;
+    }
+    if (!addr.and(mask2).isZero()) {
+      addr = addr.rshl(2);
+      shift += 2;
+    }
+    if (!addr.and(mask1).isZero()) {
+      shift += 1;
+    }
+    return (Word.one().lsh(shift));
+  }
+
+  /**
+   * Perform insertion sort within an intra-block address range.
+   *
+   *  @param begin Start address of the range to be sorted
+   *  @param end End address of the range to be sorted
+   */
+  private void insertionSort(Address begin, Address end) {
+    Address rPtr = begin.minus(BYTES_IN_ADDRESS);
+    Address lPtr;
+
+    while (rPtr.GE(end)) {
+      Address rSlot = rPtr.loadAddress();
+      Word rKey = getKey(rSlot);
+      lPtr = rPtr.plus(BYTES_IN_ADDRESS);
+      while (lPtr.LE(begin)) {
+        Address lSlot = lPtr.loadAddress();
+        Word lKey = getKey(lSlot);
+        if (lKey.GT(rKey)) {
+          lPtr.minus(BYTES_IN_ADDRESS).store(lSlot);
+          lPtr = lPtr.plus(BYTES_IN_ADDRESS);
+        } else {
+          break;
+        }
+      }
+      lPtr.minus(BYTES_IN_ADDRESS).store(rSlot);
+      rPtr = rPtr.minus(BYTES_IN_ADDRESS);
+    }
+  }
+
+  /**
+   * Sort objects using radix exchange sort. An explicit stack is
+   *  maintained to avoid using recursion.
+   */
+  public void sort() {
+    Address startPtr, startLink, endPtr, endLink;
+    Word bitMask;
+    if (!head.EQ(HEAD_INITIAL_VALUE)) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tail.NE(TAIL_INITIAL_VALUE));
+      /* Obtain the bitmask for the first iteration and save the start &
+         end pointers and the bitmask on the stack */
+      initStack();
+      startPtr = popStack();
+      while (!startPtr.isZero()) {
+        startLink = popStack();
+        endPtr = popStack();
+        endLink = popStack();
+        bitMask = (popStack()).toWord();
+        if (startLink.NE(endLink)) {
+          partition(startPtr, startLink, endPtr, endLink, bitMask);
+        } else if (startPtr.GT(endPtr)) {
+          /* Use insertionSort for a limited number of objects within
+             a single block */
+          if (startPtr.diff(endPtr).sLT(INSERTION_SORT_LIMIT)) {
+            insertionSort(startPtr, endPtr);
+          } else {
+            partition(startPtr, startLink, endPtr, endLink, bitMask);
+          }
+        }
+        // Get the next set of data to sort
+        startPtr = popStack();
+      }
+    }
+    checkIfSorted();
+  }
+
+  /**
+   * Partition the slots in an address range based on the value in
+   * a particular bit. Place the start & end addresses of the two
+   * partitions & a bitmask per partition (which indicates the highest
+   * bit position at which the max & min of a partition differ) on the
+   * stack. This works just like the partition in quick sort, except
+   * that a bit value is being compared here
+   *
+   * @param startAddr The start address of the range to be sorted
+   * @param startLinkAddr The address where the start block has its next field
+   * @param endAddr The end address of the range to be sorted
+   * @param endLinkAddr The address where the end block has its next field
+   * @param bitMask The mask in which the bit to be commpared is set
+   */
+  private void partition(Address startAddr, Address startLinkAddr,
+                               Address endAddr, Address endLinkAddr,
+                               Word bitMask) {
+    Address travPtr = endAddr;
+    Address travLink = endLinkAddr;
+    Address stopPtr = startAddr;
+    Address stopLink = startLinkAddr;
+    Address travSlot, stopSlot;
+    Word travKey, stopKey;
+    Word lmax = Word.zero(), rmax = Word.zero();
+    Word lmin = Word.max(), rmin = Word.max();
+
+    while (true) {
+      /* Compute the address range within the current block to compute. */
+      Address endOfBlock = travLink;
+
+      /* Move the left pointer until the right pointer is reached
+         or an address with a 0 value in the bit position is found. */
+      while (true) {
+        travSlot = travPtr.loadAddress();
+        travKey = getKey(travSlot);
+
+        /* If we reach the end. */
+        if (travPtr.EQ(stopPtr))
+          break;
+        /* If we found a 0 in bit position, break. */
+        if (travKey.and(bitMask).isZero())
+          break;
+        if (travKey.GT(rmax))
+          rmax = travKey;
+        if (travKey.LT(rmin))
+          rmin = travKey;
+        /* Move to the next entry. */
+        travPtr = travPtr.plus(BYTES_IN_ADDRESS);
+        /* If at end of remset block, move to next block */
+        if (travPtr.EQ(endOfBlock)) {
+          travLink = getPrev(travPtr);
+          endOfBlock = travLink;
+          travPtr = bufferStart(endOfBlock);
+        }
+      }
+
+      /* Store the end of the block. */
+      endOfBlock = bufferStart(stopPtr);
+      /* Move the right pointer until the left pointer is reached
+         or an address with a 1 value in the bit position is found. */
+      while (true) {
+        stopSlot = stopPtr.loadAddress();
+        stopKey = getKey(stopSlot);
+        /* Found a 1 in bit position, break. */
+        if (!stopKey.and(bitMask).isZero())
+          break;
+        if (stopKey.GT(lmax))
+          lmax = stopKey;
+        if (stopKey.LT(lmin))
+          lmin = stopKey;
+        if (stopPtr.EQ(travPtr))
+          break;
+        /* Move to the next entry, which may be in the next block. */
+        if (stopPtr.EQ(endOfBlock)) {
+          stopLink = getNext(stopLink);
+          stopPtr = stopLink;
+          endOfBlock = bufferStart(stopPtr);
+        }
+        stopPtr = stopPtr.minus(BYTES_IN_ADDRESS);
+      }
+      if (stopPtr.EQ(travPtr))
+        break;
+      /* interchange the values pointed to by the left and right pointers */
+      travPtr.store(stopSlot);
+      stopPtr.store(travSlot);
+    }
+
+    /* If max value is not equal to the min value in the right partition,
+       (not all slots are identical) push the right partition on to the stack */
+    if (rmax.GT(rmin)) {
+      if (travPtr.EQ(bufferStart(travPtr))) {
+        stopLink = getNext(travLink);
+        stopPtr = stopLink;
+      } else {
+        stopLink = travLink;
+        stopPtr = travPtr;
+      }
+      pushOnStack(getBitMask(rmax.xor(rmin)).toAddress());
+      pushOnStack(endLinkAddr);
+      pushOnStack(endAddr);
+      pushOnStack(stopLink);
+      pushOnStack(stopPtr.minus(BYTES_IN_ADDRESS));
+    }
+    /* if max value is not equal to the min value in the left partition,
+       (not all slots are identical) push the left partition on to the stack */
+    if (lmax.GT(lmin)) {
+      pushOnStack(getBitMask(lmax.xor(lmin)).toAddress());
+      pushOnStack(travLink);
+      pushOnStack(travPtr);
+      pushOnStack(startLinkAddr);
+      pushOnStack(startAddr);
+    }
+  }
+
+  /*************************************************************************
+   *
+   * Sorting Stack management routines
+   */
+  private int stackLoc;
+  private AddressArray stackBase;
+
+  /*
+   * Allocate memory for the stack and intialize it with the first range
+   * to partition
+   */
+  private void initStack() {
+    stackLoc = 0;
+
+    Address endOfBlock = tail;
+    Address startPtr = bufferStart(endOfBlock);
+    Word min = Word.max();
+    Word max = Word.zero();
+    // Find the max. and min addresses in the object buffer
+    while (endOfBlock.NE(HEAD_INITIAL_VALUE)) {
+      startPtr = bufferStart(endOfBlock);
+      while (startPtr.LT(endOfBlock)) {
+        Address startSlot = startPtr.loadAddress();
+        Word startKey = getKey(startSlot);
+        if (startKey.GT(max))
+          max = startKey;
+        if (startKey.LT(min))
+          min = startKey;
+        startPtr = startPtr.plus(BYTES_IN_ADDRESS);
+      }
+      endOfBlock = getPrev(startPtr);
+    }
+
+    // If max and min are different (not all elements are equal), push the
+    // start, end and bitmask values on the stack
+    if (max.GT(min)) {
+      pushOnStack(getBitMask(max.xor(min)).toAddress());
+      pushOnStack(tail);
+      pushOnStack(bufferStart(tail));
+      pushOnStack(startPtr);
+      pushOnStack(startPtr.minus(BYTES_IN_ADDRESS));
+    }
+  }
+
+  /**
+   * Push an address on to the stack
+   *
+  * @param val The address to be pushed
+   */
+  private void pushOnStack(Address val) {
+    stackBase.set(stackLoc, val);
+    stackLoc++;
+  }
+
+  /**
+   * Pop an address from the stack
+   *
+   * @return The address at the top of the stack, or 0 if stack is empty
+   */
+  private Address popStack() {
+    if (stackLoc == 0)
+      return Address.zero();
+    stackLoc--;
+    return stackBase.get(stackLoc);
+  }
+
+  /**
+   * Debug routine, used to check if the object buffer is sorted correctly in
+   * decreasing final reference deletion time
+ */
+  private void checkIfSorted() {
+    if (VM.VERIFY_ASSERTIONS) {
+      Address buf, end;
+      Word prevKey = Word.max();
+      end = tail;
+      buf = bufferStart(end);
+      while (buf.NE(HEAD_INITIAL_VALUE)) {
+        // iterate through the block
+        while (buf.LT(end)) {
+          Address slot = buf.loadAddress();
+          Word key = getKey(slot);
+          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(key.LE(prevKey));
+          prevKey = key;
+          buf = buf.plus(BYTES_IN_ADDRESS);
+        }
+        end = getPrev(end);
+        buf = bufferStart(end);
+      }
+    }
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODAddressStack.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODAddressStack.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODAddressStack.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODAddressStack.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,91 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This supports <i>unsynchronized</i> pushing and popping of addresses.
+ * In addition, this can sort the entries currently on the shared stack.
+ */
+ at Uninterruptible public class SortTODAddressStack extends LocalDeque
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared stack to which this stack will append
+   * its buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  public SortTODAddressStack(SortTODSharedDeque queue) {
+    super(queue);
+  }
+
+  /**
+   * Sort the address on the shared stack.
+   */
+  public final void sort() {
+    flushLocal();
+    ((SortTODSharedDeque) queue).sort();
+  }
+
+  /**
+   * Push an address onto the address stack.
+   *
+   * @param addr the address to be pushed onto the address queue
+   */
+  @Inline
+  public final void push(Address addr) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr.isZero());
+    checkHeadInsert(1);
+    uncheckedHeadInsert(addr);
+  }
+
+  /**
+   * Pop an address from the address stack, return zero if the stack
+   * is empty.
+   *
+   * @return The next address in the address stack, or zero if the
+   * stack is empty
+   */
+  @Inline
+  public final Address pop() {
+    if (checkDequeue(1)) {
+      return uncheckedDequeue();
+    } else {
+      return Address.zero();
+    }
+  }
+
+  /**
+   * Check if the (local and shared) stacks are empty.
+   *
+   * @return True if there are no more entries on the local & shared stack,
+   *         false otherwise.
+   */
+  @Inline
+  public final boolean isEmpty() {
+    return !checkDequeue(1);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,93 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This supports <i>unsynchronized</i> pushing and popping of object
+ * references.  In addition, this can sort the entries currently on
+ * the shared stack.
+ */
+ at Uninterruptible public class SortTODObjectReferenceStack extends LocalDeque
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared stack to which this stack will append
+   * its buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  public SortTODObjectReferenceStack(SortTODSharedDeque queue) {
+    super(queue);
+  }
+
+  /**
+   * Sort the address on the shared stack.
+   */
+  public final void sort() {
+    flushLocal();
+    ((SortTODSharedDeque) queue).sort();
+  }
+
+  /**
+   * Push an address onto the address stack.
+   *
+   * @param object the object to be pushed onto the object queue
+   */
+  @Inline
+  public final void push(ObjectReference object) {
+    Address addr = object.toAddress();
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr.isZero());
+    checkHeadInsert(1);
+    uncheckedHeadInsert(addr);
+  }
+
+  /**
+   * Pop an address from the address stack, return zero if the stack
+   * is empty.
+   *
+   * @return The next address in the address stack, or zero if the
+   * stack is empty
+   */
+  @Inline
+  public final ObjectReference pop() {
+    if (checkDequeue(1)) {
+      return uncheckedDequeue().toObjectReference();
+    } else {
+      return ObjectReference.nullReference();
+    }
+  }
+
+  /**
+   * Check if the (local and shared) stacks are empty.
+   *
+   * @return True if there are no more entries on the local & shared stack,
+   *         false otherwise.
+   */
+  @Inline
+  public final boolean isEmpty() {
+    return !checkDequeue(1);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODSharedDeque.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODSharedDeque.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODSharedDeque.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/SortTODSharedDeque.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,47 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.policy.RawPageSpace;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This class specializes SortSharedQueue to sort objects according to
+ * their time of death (TOD).
+ */
+ at Uninterruptible
+public final class SortTODSharedDeque extends SortSharedDeque {
+
+  /**
+   * Constructor
+   *
+   * @param rps The space from which the instance should obtain buffers.
+   * @param arity The arity of the data to be enqueued
+   */
+  public SortTODSharedDeque(String name, RawPageSpace rps, int arity) {
+    super(name, rps, arity);
+  }
+
+  /**
+   * Return the sorting key for the object passed as a parameter.
+   *
+   * @param obj The address of the object whose key is wanted
+   * @return The value of the sorting key for this object
+   */
+  protected Word getKey(Address obj) {
+    return VM.traceInterface.getDeathTime(obj.toObjectReference());
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/TraceBuffer.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/TraceBuffer.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/TraceBuffer.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/TraceBuffer.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,235 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.TracingConstants;
+import org.mmtk.vm.VM;
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This supports <i>unsynchronized</i> enqueuing and dequeuing of tracing data
+ * and bulk processing of the buffer.
+ */
+ at Uninterruptible public class TraceBuffer extends LocalQueue
+  implements Constants, TracingConstants {
+
+  /***********************************************************************
+   *
+   * Class based constants
+   */
+  private static final Word TRACE_NEW_RECORD = Word.fromIntSignExtend(3);
+  private static final Word TRACE_ALLOC_SIZE = Word.fromIntSignExtend(5);
+//  private static final Word TRACE_ALLOC_NAME = Word.fromIntSignExtend(6);
+  private static final Word TRACE_ALLOC_FP = Word.fromIntSignExtend(7);
+  private static final Word TRACE_ALLOC_THREAD = Word.fromIntSignExtend(9);
+  private static final Word TRACE_TIB_VALUE = Word.fromIntSignExtend(10);
+  private static final Word TRACE_DEATH_TIME = Word.fromIntSignExtend(11);
+  private static final Word TRACE_FIELD_TARGET = Word.fromIntSignExtend(12);
+  private static final Word TRACE_ARRAY_TARGET = Word.fromIntSignExtend(13);
+  private static final Word TRACE_FIELD_SLOT = Word.fromIntSignExtend(14);
+  private static final Word TRACE_ARRAY_ELEMENT = Word.fromIntSignExtend(15);
+  private static final Word TRACE_STATIC_TARGET = Word.fromIntSignExtend(17);
+  private static final Word TRACE_BOOT_ALLOC_SIZE = Word.fromIntSignExtend(18);
+
+  /*
+   * Debugging and trace reducing constants
+   */
+  public static final boolean OMIT_ALLOCS=false;
+  public static final boolean OMIT_UPDATES=false;
+  public static final boolean OMIT_BOOTALLOCS=false;
+  public static final boolean OMIT_UNREACHABLES=false;
+  public static final boolean OMIT_OTHERS=false;
+  public static final boolean OMIT_OUTPUT=OMIT_ALLOCS && OMIT_UPDATES &&
+                                          OMIT_OTHERS;
+
+
+  /***********************************************************************
+   *
+   * Public methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param pool The shared queue to which this queue will append its
+   * buffers (when full or flushed) and from which it will aquire new
+   * buffers when it has exhausted its own.
+   */
+  public TraceBuffer(SharedDeque pool) {
+    super(pool);
+  }
+
+  /**
+   * Push word onto the tracing queue.
+   *
+   * @param i The data to be pushed onto the tracing queue
+   */
+  @Inline
+  public final void push(Word i) {
+    checkTailInsert(1);
+    uncheckedTailInsert(i.toAddress());
+  }
+
+  /**
+   * Process the data in the tracing buffer, output information as needed.
+   */
+  public final void process() {
+    Word traceState = TRACE_NEW_RECORD;
+    int entriesNotFlushed = 0;
+    boolean loggedRecord = false;
+    /* First we must flush any remaining data */
+    if (!OMIT_OUTPUT) Log.writeln();
+
+    /* Process through the entire buffer. */
+    while (checkDequeue(1)) {
+      /* For speed and efficiency, we will actually process the data buffer by
+         buffer and not by dequeue-ing each entry. */
+      while (!bufferOffset(head).isZero()) {
+        head = head.minus(BYTES_IN_ADDRESS);
+        Word val = head.loadWord();
+        if (traceState.EQ(TRACE_NEW_RECORD)) {
+          loggedRecord = false;
+          if (val.EQ(TRACE_GCSTART)) {
+            if (!OMIT_OTHERS) {
+              Log.write('G');
+              Log.write('C');
+              Log.writeln('B', true);
+            }
+          } else if (val.EQ(TRACE_GCEND)) {
+            if (!OMIT_OTHERS) {
+              Log.write('G');
+              Log.write('C');
+              Log.writeln('E', true);
+            }
+          } else {
+            traceState = val;
+          }
+        } else {
+          if (traceState.EQ(TRACE_EXACT_ALLOC) ||
+              traceState.EQ(TRACE_ALLOC)) {
+            if (!OMIT_ALLOCS) {
+              Log.write((traceState.EQ(TRACE_EXACT_ALLOC)) ? 'A' : 'a');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_ALLOC_SIZE;
+          } else if (traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC) ||
+                     traceState.EQ(TRACE_IMMORTAL_ALLOC)) {
+            if (!OMIT_ALLOCS) {
+              Log.write((traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC)) ? 'I' : 'i');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_ALLOC_SIZE;
+          } else if (traceState.EQ(TRACE_BOOT_ALLOC)) {
+            if (!OMIT_BOOTALLOCS) {
+              Log.write('B');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_BOOT_ALLOC_SIZE;
+          } else if (traceState.EQ(TRACE_DEATH)) {
+            if (!OMIT_UNREACHABLES) {
+              Log.write('D');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_DEATH_TIME;
+          } else if (traceState.EQ(TRACE_BOOT_ALLOC_SIZE)) {
+            if (!OMIT_BOOTALLOCS)
+              Log.write(val);
+            traceState = TRACE_NEW_RECORD;
+          } else if (traceState.EQ(TRACE_ALLOC_SIZE)) {
+            if (!OMIT_ALLOCS)
+              Log.write(val);
+            traceState = TRACE_ALLOC_FP;
+          } else if (traceState.EQ(TRACE_ALLOC_FP)) {
+            if (!OMIT_ALLOCS)
+              Log.write(val);
+            traceState = TRACE_ALLOC_THREAD;
+          } else if (traceState.EQ(TRACE_ALLOC_THREAD)) {
+            if (!OMIT_ALLOCS)
+              Log.write(val);
+            traceState = TRACE_NEW_RECORD;
+          } else if (traceState.EQ(TRACE_TIB_SET)) {
+            if (!OMIT_UPDATES) {
+              Log.write('T');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_TIB_VALUE;
+          } else if (traceState.EQ(TRACE_STATIC_SET)) {
+            if (!OMIT_UPDATES) {
+              Log.write('S');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_STATIC_TARGET;
+          } else if (traceState.EQ(TRACE_TIB_VALUE) ||
+                     traceState.EQ(TRACE_STATIC_TARGET)) {
+            if (!OMIT_UPDATES)
+              Log.write(val);
+            traceState = TRACE_NEW_RECORD;
+          } else if (traceState.EQ(TRACE_DEATH_TIME)) {
+            if (!OMIT_UNREACHABLES)
+              Log.write(val);
+            traceState = TRACE_NEW_RECORD;
+          } else if (traceState.EQ(TRACE_FIELD_SET) ||
+                     traceState.EQ(TRACE_ARRAY_SET)) {
+            if (!OMIT_UPDATES) {
+              Log.write('U');
+              Log.write(' ');
+              Log.write(val);
+              loggedRecord = true;
+            }
+            traceState = TRACE_FIELD_SLOT;
+          } else if (traceState.EQ(TRACE_FIELD_TARGET) ||
+                     traceState.EQ(TRACE_ARRAY_TARGET)) {
+            if (!OMIT_UPDATES)
+              Log.write(val);
+            traceState = TRACE_NEW_RECORD;
+          } else if (traceState.EQ(TRACE_FIELD_SLOT) ||
+                     traceState.EQ(TRACE_ARRAY_ELEMENT)) {
+            if (!OMIT_UPDATES)
+              Log.write(val);
+            traceState = TRACE_FIELD_TARGET;
+          } else {
+            VM.assertions.fail("Cannot understand directive!\n");
+          }
+          if (traceState.EQ(TRACE_NEW_RECORD) && loggedRecord) {
+            entriesNotFlushed++;
+            Log.writeln();
+          } else if (loggedRecord) {
+              Log.write(' ');
+          }
+        }
+        if (entriesNotFlushed == 10) {
+          if (!OMIT_OUTPUT)
+            Log.flush();
+          entriesNotFlushed = 0;
+        }
+      }
+    }
+    resetLocal();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/WriteBuffer.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/WriteBuffer.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/WriteBuffer.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/deque/WriteBuffer.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,51 @@
+/*
+ *  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.mmtk.utility.deque;
+
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This supports <i>unsynchronized</i> insertion of write buffer values.
+ */
+ at Uninterruptible public class WriteBuffer extends LocalSSB
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Public instance methods
+   */
+
+  /**
+   * Constructor
+   *
+   * @param queue The shared queue to which this local ssb will append
+   * its buffers (when full or flushed).
+   */
+  public WriteBuffer(SharedDeque queue) {
+    super(queue);
+  }
+
+  /**
+   * Insert a value to be remembered into the write buffer.
+   *
+   * @param addr the value to be inserted into the write buffer
+   */
+  @NoInline
+  public final void insert(Address addr) {
+    checkTailInsert(1);
+    uncheckedTailInsert(addr);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Color.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Color.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Color.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Color.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,100 @@
+/*
+ *  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.mmtk.utility.gcspy;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * Color.java
+ *
+ * Cut-down implementation of java.awt.Color sufficient to provide
+ * the server side (Stream) with colours
+ */
+ at Uninterruptible public class Color {
+
+  /**
+   * Some gcspy standard colours (taken from gcspy_color_db.c).
+   */
+  public static final Color Black     = new Color(0, 0, 0);
+  public static final Color Blue      = new Color(0, 0, 255);
+  public static final Color Cyan      = new Color(0, 255, 255);
+  public static final Color DarkGray  = new Color(64, 64, 64);
+  public static final Color Gray      = new Color(128, 128, 128);
+  public static final Color Green     = new Color(0, 255, 0);
+  public static final Color LightGray = new Color(192, 192, 192);
+  public static final Color Magenta   = new Color(255, 0, 255);
+  public static final Color MidGray   = new Color(160, 160, 160);
+  public static final Color NavyBlue  = new Color(0, 0, 150);
+  public static final Color OffWhite  = new Color(230, 230, 230);
+  public static final Color Orange    = new Color(255, 200, 0);
+  public static final Color Pink      = new Color(255, 175, 175);
+  public static final Color Red       = new Color(255, 0, 0);
+  public static final Color White     = new Color(255, 255, 255);
+  public static final Color Yellow    = new Color(255, 255, 0);
+
+  private short r; // red component
+  private short g; // green component
+  private short b; // blue component
+
+  /**
+   * Constructor for a simple RGB colour model.
+   *
+   * @param r red component
+   * @param g green component
+   * @param b blue component
+   */
+  public Color(short r, short g, short b) {
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert((0 <= r) && (r <= 255) &&
+                           (0 <= g) && (g <= 255) &&
+                           (0 <= b) && (b <= 255));
+    this.r = r;
+    this.g = g;
+    this.b = b;
+  }
+
+  /**
+   * Constructor for a simple RGB colour model.
+   *
+   * @param r red component
+   * @param g green component
+   * @param b blue component
+   */
+  private Color(int r, int g, int b) {
+    this((short) r, (short) g, (short) b);
+  }
+
+
+  /**
+   * Red component
+   *
+   * @return the red component
+   */
+  public short getRed() { return r; }
+
+  /**
+   * Green component
+   *
+   * @return the green component
+   */
+  public short getGreen() { return g; }
+
+  /**
+   * Blue component
+   *
+   * @return the blue component
+   */
+  public short getBlue() { return b; }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/GCspy.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/GCspy.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/GCspy.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/GCspy.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,95 @@
+/*
+ *  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.mmtk.utility.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.options.*;
+import org.mmtk.vm.VM;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.vm.gcspy.Util;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements collector-independent GCspy functionality to start
+ * the GCspy server.  It handles command-line parameters for port number,
+ * whether the VM should wait for a GCspy client to connect, and tile size.
+ * Most importantly, it calls the Plan's startGCspyServer method which
+ * creates a new ServerInterpreter, and adds events and space drivers.
+ */
+ at Uninterruptible public class GCspy {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  public static final Util util = VM.newGCspyUtil();
+  public static final ServerInterpreter server = VM.newGCspyServerInterpreter();
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  @Interruptible
+  public static void createOptions() {
+    Options.gcspyPort = new GCspyPort();
+    Options.gcspyWait = new GCspyWait();
+    Options.gcspyTileSize = new GCspyTileSize();
+  }
+
+  /**
+   * The boot method is called by the runtime immediately after
+   * command-line arguments are available.  Note that allocation must
+   * be supported prior to this point because the runtime
+   * infrastructure may require allocation in order to parse the
+   * command line arguments.
+   */
+  public static void postBoot() { }
+
+  /**
+   * Get the number of the port that GCspy communicates on
+   *
+   * @return the GCspy port number
+   */
+  public static int getGCspyPort() {
+    return Options.gcspyPort.getValue();
+  }
+
+  /**
+   * Should the VM wait for GCspy to connect?
+   *
+   * @return whether the VM should wait for the visualiser to connect
+   */
+  public static boolean getGCspyWait() {
+    return Options.gcspyWait.getValue();
+  }
+
+  /**
+   * Start the GCspy server.
+   * WARNING: allocates memory indirectly
+   */
+  @Interruptible
+  public static void startGCspyServer() {
+    int port = getGCspyPort();
+    Log.write("GCspy.startGCspyServer, port="); Log.write(port);
+    Log.write(", wait=");
+    Log.writeln(getGCspyWait());
+    if (port > 0) {
+      VM.activePlan.global().startGCspyServer(port, getGCspyWait());
+      //Log.writeln("gcspy thread booted");
+    }
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/LinearScan.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/LinearScan.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/LinearScan.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/LinearScan.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.mmtk.utility.gcspy;
+
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This class is only necessary because we cannot implement
+ * org.mmtk.utility.alloc.LinearScan as an interface since the invokeinterface
+ * bytecode is forbidden in uninterruptible code.
+ */
+ at Uninterruptible public class LinearScan extends org.mmtk.utility.alloc.LinearScan {
+
+  private final AbstractDriver driver;
+
+  /**
+   * Create a new scanner.
+   * @param d The GCspy driver that provides the callback.
+   */
+  public LinearScan(AbstractDriver d) { driver = d; }
+
+  /**
+   * Scan an object. The object reference is passed to the scan method of the
+   * GCspy driver registered with this scanner.
+   * @param obj The object to scan.
+   */
+  public void scan(ObjectReference obj) { driver.scan(obj);  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/StreamConstants.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/StreamConstants.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/StreamConstants.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/StreamConstants.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,60 @@
+/*
+ *  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.mmtk.utility.gcspy;
+
+/**
+ * This interface provides constants used by the GCspy framweork.
+ * These must correspond with values in gcspy_stream.h
+ * Presentation
+ * <table>
+      <tr><td>PRESENTATION_PLAIN</td>      <td>presented as is</td>
+      <tr><td>PRESENTATION_PLUS</td>       <td>as max+ if value exceeds max else as is</td>
+      <tr><td>PRESENTATION_MAX_VAR</td>    <td>ditto but takes max value from a specified stream</td>
+      <tr><td>PRESENTATION_PERCENT</td>    <td>as value (percent)</td>
+      <tr><td>PRESENTATION_PERCENT_VAR</td><td>ditto but takes max value from a specified stream</td>
+      <tr><td>PRESENTATION_ENUM </td>      <td>chooses from an enumeration</td>
+   </table>
+   Paint style
+   <table>
+      <tr><td>PAINT_STYLE_PLAIN</td>       <td>Paints as is</td>
+      <tr><td>PAINT_STYLE_ZERO</td>        <td>ditto but treats zero values specially</td>
+   </table>
+   Data types
+   <table>
+      <tr><td>BYTE_TYPE</td>  <td>stream of bytes</td>
+      <tr><td>SHORT_TYPE</td> <td>stream of shorts</td>
+      <tr><td>INT_TYPE</td>   <td>stream of ints</td>
+   </table>
+ * StreamConstants
+ */
+
+public interface StreamConstants {
+
+  int NAME_LEN = 40;
+  int PRESENTATION_PLAIN       = 0;
+  int PRESENTATION_PLUS        = 1;
+  int PRESENTATION_MAX_VAR     = 2;
+  int PRESENTATION_PERCENT     = 3;
+  int PRESENTATION_PERCENT_VAR = 4;
+  int PRESENTATION_ENUM        = 5;
+
+  int PAINT_STYLE_PLAIN = 0;
+  int PAINT_STYLE_ZERO  = 1;
+
+  int BYTE_TYPE  = 0;
+  int SHORT_TYPE = 1;
+  int INT_TYPE   = 2;
+
+  int ENUM_MAX_LEN = 20;
+  int ENUM_MAX_NUM = 5;
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Subspace.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Subspace.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Subspace.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/Subspace.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,236 @@
+/*
+ *  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.mmtk.utility.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.vm.gcspy.Util;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+
+
+/**
+ * This class is an abstraction of a contiguous region of a Space.  For
+ * example, a semispace collector might choose to model the heap as a
+ * single Space, but within that Space it could model each semispace by
+ * a Subspace.<p>
+ * Subspace provides a number of useful facilities to many drivers, and
+ * is useful even if the Space comprises just a single contiguous region.<p>
+ *
+ * A subspace keeps track of the start and end address of the region,
+ * the index of its first block, the size of the blocks in this space,
+ * and the number of blocks in this subspace.
+ */
+ at Uninterruptible public class Subspace {
+
+  private Address start_;       // The Subspace spans the address range [start_, end_)
+  private Address end_;
+  private int firstIndex_;      // The index of the block in which start_ lies
+  private int blockSize_;       // The block size
+  private int blockNum_;        // The number of blocks in this space
+
+  private static final boolean DEBUG = false;
+
+  /**
+   * Create a new subspace
+   *
+   * @param start The address of the start of the subspace
+   * @param end The address of the end of the subspace
+   * @param firstIndex The index of the first block of the subspace
+   * @param blockSize The size of blocks in this space
+   * @param blockNum The number of blocks in this subspace
+   */
+  public Subspace(Address start,
+                  Address end,
+                  int firstIndex,
+                  int blockSize,
+                  int blockNum) {
+    reset(start, end, firstIndex, blockSize, blockNum);
+  }
+
+
+  //------------------Methods to reset a subspace----------------------
+
+  /**
+   * Reset a subspace.
+   *
+   * @param start The address of the start of the subspace
+   * @param end The address of the end of the subspace
+   * @param firstIndex The index of the first block of the subspace
+   * @param blockSize The size of blocks in this subspace
+   * @param blockNum The number of blocks in this subspace
+   */
+  private void reset(Address start,
+                     Address end,
+                     int firstIndex,
+                     int blockSize,
+                     int blockNum) {
+    //TODO sanity check on addresses and block size and number
+    reset(start, end, firstIndex, blockNum);
+    blockSize_ = blockSize;
+
+    if (DEBUG) dump();
+  }
+
+  /**
+   * Reset a new subspace
+   *
+   * @param start The address of the start of the subspace
+   * @param end The address of the end of the subspace
+   * @param firstIndex The index of the first block of the subspace
+   * @param blockNum The number of blocks in this subspace
+   */
+  public void reset(Address start,
+                    Address end,
+                    int firstIndex,
+                    int blockNum) {
+    start_ = start;
+    end_ = end;
+    firstIndex_ = firstIndex;
+    blockNum_ = blockNum;
+  }
+
+  /**
+   * Reset a new subspace.
+   *
+   * @param start The address of the start of the subspace
+   * @param end The address of the end of the subspace
+   * @param blockNum The number of blocks in this subspace
+   */
+  public void reset(Address start, Address end, int blockNum) {
+    start_ = start;
+    end_ = end;
+    blockNum_ = blockNum;
+  }
+
+  /**
+   * Reset a new subspace.
+   *
+   * @param firstIndex The index of the first block of the subspace
+   * @param blockNum The number of blocks in this subspace
+   */
+  public void reset(int firstIndex, int blockNum) {
+    firstIndex_ = firstIndex;
+    blockNum_ = blockNum;
+  }
+
+
+  //----------------Facilities to query a subspace-----------------
+
+  /**
+   * Is an index in the range of this subspace?
+   *
+   * @param index The index of the block
+   * @return true if this block lies in this subspace
+   */
+  public boolean indexInRange(int index) {
+    return index >= firstIndex_ &&
+           index < firstIndex_ + blockNum_;
+  }
+
+  /**
+   * Is address in the range of this subspace?
+   *
+   * @param addr An address
+   * @return true if this address is in a block in this subspace
+   */
+  public boolean addressInRange(Address addr) {
+    return addr.GE(start_) && addr.LT(end_);
+  }
+
+
+  /**
+   * Get the block index from an address
+   *
+   * @param addr The address
+   * @return The index of the block holding this address
+   */
+  public int getIndex(Address addr) {
+    if (DEBUG) {
+      Log.write("start_ ", start_);
+      Log.write(" end_ ", end_);
+      Log.write(" blockSize_ ", blockSize_);
+      Log.write(" firstIndex_ ", firstIndex_);
+      Log.write(" + ", addr.diff(start_).toInt() / blockSize_);
+      Log.writeln(" addr ", addr);
+    }
+    return firstIndex_ + addr.diff(start_).toInt() / blockSize_;
+  }
+
+  /**
+   * Get the address of start of block from its index
+   *
+   * @param index The index of the block
+   * @return The address of the start of the block
+   */
+  public Address getAddress(int index) {
+    return start_.plus(index - firstIndex_ * blockSize_);
+  }
+
+  //--------------Accessors-------------------------
+
+  /**
+   * Get the start of the subspace
+   * @return The start of this subspace
+   */
+  public Address getStart() { return start_; }
+
+  /**
+   * Get the end of this subspace
+   * @return The address of the end of this subspace
+   */
+  public Address getEnd() { return end_; }
+
+  /**
+   * Get the first index of subspace
+   * @return the firstIndex of this subspace
+   */
+  public int getFirstIndex() { return firstIndex_; }
+
+  /**
+   * Get the blocksize for this subspace
+   * @return The size of a tile
+   */
+  public int getBlockSize() { return blockSize_; }
+
+  /**
+   * Get the number of tiles in this subspace
+   * @return The number of tiles in this subspace
+   */
+  public int getBlockNum() { return blockNum_; }
+
+  /**
+   * Calculate the space remaining in a block after this address
+   *
+   * @param addr the Address
+   * @return the remainder
+   */
+  public int spaceRemaining(Address addr) {
+    int nextIndex = getIndex(addr) + 1;
+    Address nextTile = start_.plus(blockSize_ * (nextIndex - firstIndex_));
+    return nextTile.diff(addr).toInt();
+  }
+
+  /**
+   * Dump a representation of the subspace
+   */
+  private void dump() {
+    Log.write("GCspy Subspace: ");
+    Util.dumpRange(start_, end_);
+    Log.writeln("\n  -- firstIndex=", firstIndex_);
+    Log.writeln("  -- blockNum=", blockNum_);
+  }
+}
+
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/AbstractDriver.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/AbstractDriver.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/AbstractDriver.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/AbstractDriver.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,502 @@
+/*
+ *  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.mmtk.utility.gcspy.drivers;
+
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Log;
+import org.mmtk.utility.gcspy.GCspy;
+import org.mmtk.utility.gcspy.Subspace;
+import org.mmtk.vm.gcspy.ServerSpace;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.vm.gcspy.Stream;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Abstract GCspy driver for MMTk collectors.
+ *
+ * This class implements for the MMTk a base driver for a GCspy space.
+ * All drivers for GCspy spaces should inherit from this class.
+ */
+ at Uninterruptible
+public abstract class AbstractDriver {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  // Controls used for tile presentation
+  /** The tile is used */
+  protected static final byte CONTROL_USED            =  1;
+  /** The tile is a background tile */
+  protected static final byte CONTROL_BACKGROUND      =  2;
+  /** The tile is unused */
+  protected static final byte CONTROL_UNUSED          =  4;
+  /** The tile is a separator */
+  protected static final byte CONTROL_SEPARATOR       =  8;
+  /** The tile is a link */
+  protected static final byte CONTROL_LINK            = 16;
+
+
+  private static final int MAX_STREAMS = 64;    // Max number of streams
+
+  private static final boolean DEBUG = false;
+  protected String myClass;                     // used in debugging messages
+
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  /** The owning GCspy server */
+  protected final ServerInterpreter server;
+  /** The name of the GCspy space driver */
+  protected final String name;
+  /** The GCspy space abstraction */
+  protected final ServerSpace serverSpace;
+  /** The MMTK space */
+  protected final Space mmtkSpace;
+  /** The GCspy space's block size */
+  protected int blockSize;
+  /** The maximum number of tiles in this GCspy space */
+  protected int maxTileNum;
+  /** This space's streams  */
+  protected Stream[] streams;
+  /**  control values for tiles in this space */
+  protected byte[] control;
+  /** Has this space changed? */
+  protected boolean changed = true;
+
+
+  /**
+   * Create a new driver for this collector.
+   *
+   * @param server The ServerInterpreter that owns this GCspy space.
+   * @param name The name of this driver.
+   * @param mmtkSpace The MMTk space represented by this driver.
+   * @param blockSize The tile size.
+   * @param mainSpace Is this the main space?
+   */
+  public AbstractDriver(ServerInterpreter server,
+                        String name,
+                        Space mmtkSpace,
+                        int blockSize,
+                        boolean mainSpace) {
+    this.server = server;
+    this.name = name;
+    this.mmtkSpace = mmtkSpace;
+    this.blockSize = blockSize;
+    myClass = getClass().getName();
+    maxTileNum = countTileNum(mmtkSpace.getExtent(), blockSize);
+    control = (byte[])GCspy.util.createDataArray(new byte[0], maxTileNum);
+    // to avoid allocation during GC we preallocate the streams array
+    streams = new Stream[MAX_STREAMS];
+    serverSpace = createServerSpace(server, name, maxTileNum, mainSpace);
+  }
+
+  /**
+   * Create a subspace for this space.
+   * Subspace provide useful facilities for contiguous spaces, even if
+   * a space contains only one.
+   * @param mmtkSpace The MMTk space
+   */
+  @Interruptible
+  protected Subspace createSubspace(Space mmtkSpace) {
+    Address start = mmtkSpace.getStart();
+    return new Subspace(start, start, 0, blockSize, 0);
+  }
+
+  /**
+   * Create a new GCspy ServerSpace and add it to the ServerInterpreter.
+   * @param server the GCspy ServerInterpreter.
+   * @param spaceName The name of this driver.
+   * @param maxTileNum the maximum number of tiles in this space.
+   * @param mainSpace Is this the main space?
+   */
+  @Interruptible
+  protected ServerSpace createServerSpace(ServerInterpreter server,
+                  String spaceName,
+                  int maxTileNum,
+                  boolean mainSpace) {
+    // Set the block label
+    String tmp = "Block Size: " + ((blockSize < 1024) ?
+                     blockSize + " bytes\n":
+                     (blockSize / 1024) + " Kbytes\n");
+
+    // Create a single GCspy Space
+    return VM.newGCspyServerSpace(server,           // the server
+                                  spaceName,        // space name
+                                  getDriverName(),  // driver (space) name
+                                  "Block ",         // space title
+                                  tmp,              // block info
+                                  maxTileNum,       // number of tiles
+                                  "UNUSED",         // the label for unused blocks
+                                  mainSpace);       // main space
+  }
+
+  /**
+   * Get the name of this driver type.
+   * @return The name of this driver.
+   */
+  protected abstract String getDriverName();
+
+  /**
+   * Get the maximum number of tiles in this space.
+   * @return the maximum number of tiles in the space.
+   */
+  public int getMaxTileNum() {
+    return maxTileNum;
+  }
+
+  /**
+   * The GCspy space managed by this driver.
+   * @return the GCspy server space.
+   */
+  public ServerSpace getServerSpace() { return serverSpace; }
+
+  /**
+   * Add a stream to the driver. This also sets the stream's id
+   * (unique for this space).
+   * @param stream The stream
+   * @exception IndexOutOfBoundsException if more than MAX_STREAMS are added
+   */
+  @Interruptible
+  public void addStream(Stream stream) {
+    int id = 0;
+    while (id < MAX_STREAMS) {
+      if (streams[id] == null) {
+        streams[id] = stream;
+        if (DEBUG) { Log.write("Adding stream with id="); Log.writeln(id); }
+        Address stream_ = serverSpace.addStream(id);
+        stream.setStream(id, stream_);
+        return;
+      }
+      id++;
+    }
+    throw new IndexOutOfBoundsException("Too many streams added to driver "+name);
+  }
+
+  /**
+   * Count number of tiles in an address range.
+   * @param start The start of the range.
+   * @param end The end of the range.
+   * @param tileSize The size of each tile.
+   * @return The number of tiles in this range.
+   */
+  protected int countTileNum(Address start, Address end, int tileSize) {
+    if (end.LE(start)) return 0;
+    int diff = end.diff(start).toInt();
+    return countTileNum(diff, tileSize);
+  }
+
+  /**
+   * Count number of tiles in an address range.
+   * @param extent The extent of the range.
+   * @param tileSize The size of each tile.
+   * @return The number of tiles in this range.
+   */
+  protected int countTileNum(Extent extent, int tileSize) {
+    int diff = extent.toInt();
+    return countTileNum(diff, tileSize);
+  }
+
+  private int countTileNum(int diff, int tileSize) {
+    int tiles = diff / tileSize;
+    if ((diff % tileSize) != 0)
+      ++tiles;
+    return tiles;
+  }
+
+  /**
+   * Indicate the limits of a space.
+   *
+   * @param start the Address of the start of the space.
+   * @param end the Address of the end of the space.
+   */
+  public void setRange(Address start, Address end) {}
+
+  /**
+   * Indicate the limits of a space.
+   *
+   * @param start the Address of the start of the space.
+   * @param extent the extent of the space.
+   */
+  public void setRange(Address start, Extent extent) {
+    setRange(start, start.plus(extent));
+  }
+
+  /**
+   * Setup the tile names in a subspace. Tile names are typically
+   * address ranges but may be anything (e.g. a size class if the
+   * space is a segregated free-list manager, or a class name if the
+   * space represents the class instances loaded).
+   *
+   * @param subspace the Subspace
+   * @param numTiles the number of tiles to name
+   */
+  protected void setTilenames(Subspace subspace, int numTiles) {
+    Address start = subspace.getStart();
+    int first = subspace.getFirstIndex();
+    int bs = subspace.getBlockSize();
+
+    for (int i = 0; i < numTiles; ++i) {
+      if (subspace.indexInRange(i))
+        serverSpace.setTilename(i, start.plus((i - first) * bs),
+                                start.plus((i + 1 - first) * bs));
+    }
+  }
+
+  /**
+   * The "typical" maximum number of objects in each tile.
+   * @param blockSize The size of a tile
+   * @return The maximum number of objects in a tile
+   */
+  public int maxObjectsPerBlock(int blockSize) {
+    // Maybe a misuse of ServerInterpreter but it's a convenient
+    // VM-dependent class
+    return blockSize / GCspy.server.computeHeaderSize();
+  }
+
+  /**
+   * Is the server connected to a GCspy client?
+   * @param event The current event
+   */
+  public boolean isConnected(int event) {
+    return server.isConnected(event);
+  }
+
+  /**
+   * Reset the statistics for a space.
+   * In this base driver, we simply note that the data has changed.
+   */
+  protected void resetData() { changed = true; }
+
+  /**
+   * Scan an object found at a location.
+   * Collectors typically call this method to update GCspy statistics.
+   * The driver may or may not accumulate values found, depending on
+   * the value of total.
+   * @param obj the reference to the object found
+   * @param total Whether to total the statistics
+   */
+  public void scan(ObjectReference obj, boolean total) {}
+
+  /**
+   * Scan an object found at a location.
+   * Collectors typically call this method to update GCspy statistics
+   * The driver will accumulate values found.
+   * @param obj the reference to the object found
+   */
+  public void scan(ObjectReference obj) { scan(obj, true); }
+
+  /**
+   * Scan an object found at a location.
+   * Collectors typically call this method to update GCspy statistics.
+   * The driver may or may not accumulate values found, depending on
+   * the value of total.
+   * @param obj the reference to the object found
+   * @param total Whether to total the statistics
+   */
+  public void scan(Address obj, boolean total) {}
+
+  /**
+   * Scan an object found at a location.
+   * Collectors typically call this method to update GCspy statistics
+   * The driver will accumulate values found.
+   * @param obj the reference to the object found
+   */
+  public void scan(Address obj) {}
+
+  /**
+   * Handle a direct reference from the immortal space.<p>
+   * This is an empty implementation. Subclasses may override this method
+   * to increment their <code>refFromImmortal</code> Stream.
+   *
+   * @param addr The Address
+   * @return true if the given Address is in this subspace. Always false here.
+   */
+  public boolean handleReferenceFromImmortalSpace(Address addr) {
+    return false;
+  }
+
+  /**
+   * Set space info.
+   * This simply reports the size of the current space.
+   * Drivers that want to send something more complex than
+   *  "Current Size: size\n"
+   * must override this method.
+   *
+   * @param size the size of the space
+   */
+  protected void setSpaceInfo(Offset size) {
+    //    - sprintf(tmp, "Current Size: %s\n", gcspy_formatSize(size));
+    Address tmp = GCspy.util.formatSize("Current Size: %s\n", 128, size.toInt());
+    serverSpace.spaceInfo(tmp);
+    GCspy.util.free(tmp);
+  }
+
+
+  /****************************************************************************
+   *
+   * Control values
+   */
+
+  /**
+   * Is a tile used?
+   * @param val the control value.
+   * @return true if the tile is used
+   */
+  protected static boolean controlIsUsed(byte val) {
+    return (val & CONTROL_USED) != 0;
+  }
+
+  /**
+   * Is a tile a background pseudo-tile?
+   * @param val the control value.
+   * @return true if the tile is a background tile
+   */
+  protected static boolean controlIsBackground(byte val) {
+    return (val & CONTROL_BACKGROUND) != 0;
+  }
+
+  /**
+   * Is a tile unused?
+   * @param val the control value.
+   * @return true if the tile is unused
+   */
+  protected static boolean controlIsUnused(byte val) {
+    return (val & CONTROL_UNUSED) != 0;
+  }
+
+  /**
+   * Is this a separator?
+   * @param val the control value.
+   * @return true if this is a separator
+   */
+  protected static boolean controlIsSeparator(byte val) {
+    return (val & CONTROL_SEPARATOR) != 0;
+  }
+
+  /**
+   * Initialise the value of a control.
+   * @param index The index of the tile.
+   * @param value The new value of the control
+   */
+  protected void initControl(int index, byte value) {
+    control[index] = value;
+  }
+
+  /**
+   * Add a control to the tile
+   * @param index The index of the tile.
+   * @param value The control to add.
+   */
+  protected void addControl(int index, byte value) {
+    control[index] |= value;
+  }
+
+  /** Set the control
+   * @param value The value to set
+   */
+  protected void setControl(int index, byte value) {
+    control[index] &= value;
+  }
+
+  /**
+   * Get the controls for a tile.
+   * @param index The index of the tile.
+   * @return The value of the controls
+   */
+  public byte getControl(int index) {
+    return control[index];
+  }
+
+  /**
+   * Initialise control values in all tiles
+   */
+  protected void initControls() {
+    for (int index = 0; index < control.length; ++index) {
+      initControl(index, CONTROL_USED);
+    }
+  }
+
+  /**
+   * Set the control value in each tile in a region.
+   * @param tag The control tag.
+   * @param start The start index of the region.
+   * @param len The number of tiles in the region.
+   */
+  protected void controlValues(byte tag, int start, int len) {
+    if (DEBUG) {
+      Log.write("AbstractDriver.controlValues for space ");
+      Log.write(name);
+      Log.write(", control length=", control.length);
+      Log.write(" writing controls from ", start);
+      Log.writeln(" to ", start + len);
+    }
+    changed = true;
+    for (int i = start; i < (start+len); ++i) {
+      // Cannot be both USED and UNUSED or BACKGROUND
+      if (controlIsBackground(tag) || controlIsUnused(tag))
+        setControl(i, (byte)~CONTROL_USED);
+      else if (controlIsUsed(tag))
+        setControl(i, (byte)~CONTROL_UNUSED);
+      addControl(i, tag);
+    }
+  }
+
+  /**
+   * Transmit the streams for this space. A driver will typically
+   * <ol>
+   * <li> Determine whether a GCspy client is connected and interested in
+   *      this event, e.g.
+   *      <pre>server.isConnected(event)</pre>
+   * <li> Setup the summaries for each stream, e.g.
+   *      <pre>stream.setSummary(values...);</pre>
+   * <li> Setup the control information for each tile. e.g.
+   *      <pre>controlValues(CONTROL_USED, start, numBlocks);</pre>
+   *      <pre>controlValues(CONTROL_UNUSED, end, remainingBlocks);</pre>
+   * <li> Set up the space information, e.g.
+   *      <pre>setSpace(info);</pre>
+   * <li> Send the data for all streams, e.g.
+   *      <pre>send(event, numTiles);</pre>
+   *      Note that AbstractDriver.send takes care of sending the information
+   *      for all streams (including control data).
+   *
+   * @param event The event
+   */
+  public abstract void transmit(int event);
+
+  /**
+   * Send all the streams for this space if it has changed.
+   * Assume that the data has been gathered and that summary info
+   * and control values have been set before this is called.
+   *
+   * @param event the event
+   * @param numTiles the number of blocks in this space
+   */
+  protected void send(int event, int numTiles) {
+    if (changed) {
+      serverSpace.startCommunication();
+      for (int i = 0; i < MAX_STREAMS; i++)
+        if (streams[i] != null)
+          streams[i].send(event, numTiles);
+      serverSpace.sendControls(this, numTiles);
+      serverSpace.endCommunication();
+    }
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenImmortalSpaceDriver.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenImmortalSpaceDriver.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenImmortalSpaceDriver.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenImmortalSpaceDriver.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,144 @@
+/*
+ *  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.mmtk.utility.gcspy.drivers;
+
+import org.mmtk.policy.Space;
+
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.vm.VM;
+import org.mmtk.vm.gcspy.ShortStream;
+
+import org.mmtk.utility.Log;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * GCspy driver for the MMTk generational immortal space.
+ * Additional Stream for remset references.
+ * This class extends ImmortalSpaceDriver, a simple driver for
+ * the contiguous MMTk ImmortalSpace.
+ */
+ at Uninterruptible public class GenImmortalSpaceDriver extends ImmortalSpaceDriver {
+
+  private static final boolean DEBUG = false;
+
+  // The Stream for newly promoted objects
+  protected ShortStream remsetStream;
+  // Statistics for remset references
+  protected int totalRemset = 0;
+
+
+  /**
+   * Create a new driver for a generational immortal space.
+   *
+   * @param server The GCspy ServerInterpreter
+   * @param spaceName The name of this GCspy space
+   * @param mmtkSpace The MMTk space
+   * @param blockSize The tile size
+   * @param mainSpace Is this the main space?
+   */
+  public GenImmortalSpaceDriver(
+                     ServerInterpreter server,
+                     String spaceName,
+                     Space mmtkSpace,
+                     int blockSize,
+                     boolean mainSpace) {
+
+    super(server, spaceName, mmtkSpace, blockSize, mainSpace);
+
+    // create additional stream
+    remsetStream = createRemsetStream();
+
+    if (DEBUG) {
+      Log.write("GenImmortalSpaceDriver for "); Log.write(spaceName);
+      Log.write(", blocksize="); Log.write(blockSize);
+      Log.write(", start="); Log.write(mmtkSpace.getStart());
+      Log.write(", extent="); Log.write(mmtkSpace.getExtent());
+      Log.write(", maxTileNum="); Log.writeln(maxTileNum);
+    }
+
+    resetData();
+  }
+
+  /**
+   * Get the name of this driver type.
+   * @return The name, "MMTk GenImmortalSpaceDriver" for this driver.
+   */
+  protected String getDriverName() {
+    return "MMTk GenImmortalSpaceDriver";
+  }
+
+  /**
+   * Heelper methods to create the additional streams
+ */
+  @Interruptible
+  private ShortStream createRemsetStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Remembered set stream",
+                     (short)0,
+                     // Say, typical size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "Remset references: ",
+                     " references",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Cyan,
+                     true);
+  }
+
+  /**
+   * Setup summaries part of the <code>transmit</code> method.<p>
+   * Overrides method in superclass to handle additional Stream.
+ */
+  protected void setupSummaries() {
+    super.setupSummaries();
+    remsetStream.setSummary(totalRemset);
+  }
+
+  /**
+   * Handle a remset address
+   *
+   * @param addr Remset Address
+   * @return true if the given Address is in this subspace.
+   */
+  public boolean handleRemsetAddress(Address addr) {
+    if(subspace.addressInRange(addr)) {
+      // increment tile
+      int index = subspace.getIndex(addr);
+      remsetStream.increment(index, (short)1);
+      // increment summary
+      totalRemset++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Reset the remset Stream
+   * The remset Stream has to be reset seperately because we do not
+   * gather data in the usual way using scan().
+ */
+  public void resetRemsetStream() {
+    remsetStream.resetData();
+    totalRemset = 0;
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenLOSDriver.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenLOSDriver.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenLOSDriver.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/GenLOSDriver.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,132 @@
+/*
+ *  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.mmtk.utility.gcspy.drivers;
+
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.vm.VM;
+import org.mmtk.vm.gcspy.ShortStream;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+
+import org.mmtk.policy.LargeObjectSpace;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+
+/**
+ * This class extends a simple driver for the MMTk LargeObjectSpace
+ * for Generational Collectors.
+ */
+ at Uninterruptible public class GenLOSDriver extends TreadmillDriver {
+
+  private static final boolean DEBUG = false;
+
+  // The additional remset stream
+  protected ShortStream remsetStream;
+  // Additional overall statistic
+  protected int totalRemset = 0;   // total of remset Addresses
+
+
+  /**
+   * Create a new driver for this collector
+   *
+   * @param server The name of the GCspy server that owns this space
+   * @param spaceName The name of this driver
+   * @param lospace the large object space for this allocator
+   * @param blockSize The tile size
+   * @param threshold the size threshold of the LOS
+   * @param mainSpace Is this the main space?
+   */
+  public GenLOSDriver(ServerInterpreter server,
+                      String spaceName,
+                      LargeObjectSpace lospace,
+                      int blockSize,
+                      int threshold,
+                      boolean mainSpace) {
+    //TODO blocksize should be a multiple of treadmill granularity
+    super(server, spaceName, lospace, blockSize, threshold, mainSpace);
+    // create remset stream
+    remsetStream    = createRemsetStream();
+    // Initialise the statistics
+    resetData();
+  }
+
+  /**
+   * Get the name of this driver type.
+   * @return The name, "MMTk GenLOSDriver" for this driver.
+   */
+  protected String getDriverName() {
+    return "MMTk GenLOSDriver";
+  }
+
+  // private creator methods for the streams
+  @Interruptible
+  private ShortStream createRemsetStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Remembered set stream",
+                     (short)0,
+                     // Say, typical size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "Remset references: ",
+                     " references",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Cyan,
+                     true);
+  }
+
+  /**
+   * Setup summaries part of the <code>transmit</code> method.<p>
+   * Overrides <code>transmitSetupSummaries </code> of superclass to
+   * handle additional streams.
+ */
+  protected void setupSummaries() {
+    super.setupSummaries();
+    remsetStream.setSummary(totalRemset);
+  }
+
+  /**
+   * Handle a remset address.
+   *
+   * @param addr Remset Address
+   * @return true if the given Address is in this subspace.
+   */
+  public boolean handleRemsetAddress(Address addr) {
+    if(subspace.addressInRange(addr)) {
+      // increment tile
+      int index = subspace.getIndex(addr);
+      remsetStream.increment(index, (short)1);
+      // increment summary
+      this.totalRemset++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Reset the remset Stream. <p>
+   * The remset Stream has to be reset seperately because we do not
+   * gather data in the usual way using <code>scan()</code>.
+ */
+  public void resetRemsetStream() {
+    remsetStream.resetData();
+    totalRemset = 0;
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/ImmortalSpaceDriver.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/ImmortalSpaceDriver.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/ImmortalSpaceDriver.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/ImmortalSpaceDriver.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,123 @@
+/*
+ *  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.mmtk.utility.gcspy.drivers;
+
+import org.mmtk.plan.TransitiveClosure;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Log;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * GCspy driver for the contiguous MMTk ImmortalSpace.
+ * Adds features for the Immortal space.
+ * <p>
+ *
+ * This class extends LinearSpaceDriver, a simple driver for contiguous MMTk spaces
+ * such as CopySpace and ImmortalSpace.
+ */
+ at Uninterruptible public class ImmortalSpaceDriver extends LinearSpaceDriver {
+
+  private static final boolean DEBUG = false;
+
+  // Instance variables
+  private AbstractDriver[] registeredDrivers;
+  private ImmortalSpaceDriver.Closure closure;
+
+  /**
+   * Create a new driver for an immortal Contiguous MMTk space.
+   *
+   * @param server The GCspy ServerInterpreter
+   * @param spaceName The name of this GCspy space
+   * @param mmtkSpace The MMTk space
+   * @param blockSize The tile size
+   * @param mainSpace Is this the main space?
+   */
+  public ImmortalSpaceDriver(
+                     ServerInterpreter server,
+                     String spaceName,
+                     Space mmtkSpace,
+                     int blockSize,
+                     boolean mainSpace) {
+
+    super(server, spaceName, mmtkSpace, blockSize, mainSpace);
+
+    if (DEBUG) {
+      Log.write("ImmortalSpaceDriver for "); Log.write(spaceName);
+      Log.write(", blocksize="); Log.write(blockSize);
+      Log.write(", start="); Log.write(mmtkSpace.getStart());
+      Log.write(", extent="); Log.write(mmtkSpace.getExtent());
+      Log.write(", maxTileNum="); Log.writeln(maxTileNum);
+    }
+
+    // initially no registered drivers for reference notification
+    registeredDrivers = new AbstractDriver[0];
+
+    closure = new ImmortalSpaceDriver.Closure();
+  }
+
+  /**
+   * Get the name of this driver type.
+   * @return The name, "MMTk ImmortalSpaceDriver" for this driver.
+   */
+  protected String getDriverName() {
+    return "MMTk ImmortalSpaceDriver";
+  }
+
+  /**
+   * Update the tile statistics. <br>
+   * This method overrides <code> scan </code> iin its superclass to
+   * add immortal space features.
+   *
+   * @param object The current object
+   * @param total Whether to accumulate the values
+   */
+  public void scan(ObjectReference object, boolean total) {
+    Address addr = object.toAddress();
+
+    if (subspace.addressInRange(addr)) {
+      VM.scanning.scanObject(closure, object);
+      super.scan(object, total);
+    }
+  }
+
+  /**
+   * Register a set of AbstractDriver instances to be notified about direct references.
+   *
+   * @param drivers The array of driver objects.
+   */
+  public void registerDriversForReferenceNotification(AbstractDriver[] drivers) {
+    this.registeredDrivers = drivers;
+  }
+
+  /**
+   * Used to visit the edges in the immortal object.
+   */
+  @Uninterruptible
+  private class Closure extends TransitiveClosure {
+    /**
+     * Process an edge.
+     */
+    public void processEdge(ObjectReference source, Address slot) {
+      // Address in Range, locate references
+      Address target = slot.loadAddress();
+      // notify registered drivers
+      for (int j = 0; j < registeredDrivers.length; j++) {
+        registeredDrivers[j].handleReferenceFromImmortalSpace(target);
+      }
+    }
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/LinearSpaceDriver.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/LinearSpaceDriver.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/LinearSpaceDriver.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/LinearSpaceDriver.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,508 @@
+/*
+ *  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.mmtk.utility.gcspy.drivers;
+
+import org.mmtk.policy.Space;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.LinearScan;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.utility.gcspy.Subspace;
+import org.mmtk.vm.gcspy.IntStream;
+import org.mmtk.vm.gcspy.ShortStream;
+
+import org.mmtk.utility.Log;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * GCspy driver for the MMTk ContigousSpace.
+ *
+ * This class implements a simple driver for contiguous MMTk spaces
+ * such as CopySpace and ImmortalSpace.
+ */
+ at Uninterruptible public class LinearSpaceDriver extends AbstractDriver {
+
+  // The GCspy streams
+  protected IntStream   scalarUsedSpaceStream;
+  protected IntStream   arrayUsedSpaceStream;
+  protected ShortStream scalarObjectsStream;
+  protected ShortStream arrayObjectsStream;
+  protected ShortStream arrayPrimitiveStream;
+  protected ShortStream rootsStream;
+  protected ShortStream refFromImmortalStream;
+
+  protected Subspace subspace;               // A subspace for all of this space
+  protected int allTileNum;                  // total number of tiles
+
+  // Overall statistics
+  protected int totalScalarObjects   = 0;    // total number of objects allocated
+  protected int totalArrayObjects    = 0;
+  protected int totalPrimitives      = 0;
+  protected int totalScalarUsedSpace = 0;    // total space used
+  protected int totalArrayUsedSpace  = 0;
+  protected int totalRoots           = 0;
+  protected int totalRefFromImmortal = 0;
+
+  private final LinearScan scanner;          // A scanner to trace objects
+
+  // Debugging
+  protected Address lastAddress = Address.zero();
+  protected int lastSize = 0;
+  private static final boolean DEBUG = false;
+
+
+  /**
+   * Create a new driver for a contiguous MMTk space.
+   *
+   * @param server The GCspy ServerInterpreter
+   * @param spaceName The name of this GCspy space
+   * @param mmtkSpace The MMTk space
+   * @param blockSize The tile size
+   * @param mainSpace Is this the main space?
+   */
+  public LinearSpaceDriver(ServerInterpreter server,
+                           String spaceName,
+                           Space mmtkSpace,
+                           int blockSize,
+                           boolean mainSpace) {
+
+    super(server, spaceName, mmtkSpace, blockSize, mainSpace);
+
+    if (DEBUG) {
+      Log.write("LinearSpaceDriver for "); Log.write(spaceName);
+      Log.write(", blocksize="); Log.write(blockSize);
+      Log.write(", start="); Log.write(mmtkSpace.getStart());
+      Log.write(", extent="); Log.write(mmtkSpace.getExtent());
+      Log.write(", maxTileNum="); Log.writeln(maxTileNum);
+    }
+
+    // Initialise a subspace and 4 Streams
+    subspace = createSubspace(mmtkSpace);
+    allTileNum = 0;
+    scalarUsedSpaceStream = createScalarUsedSpaceStream();
+    arrayUsedSpaceStream  = createArrayUsedSpaceStream();
+    scalarObjectsStream   = createScalarObjectsStream();
+    arrayPrimitiveStream  = createArrayPrimitiveStream();
+    arrayObjectsStream    = createArrayObjectsStream();
+    rootsStream           = createRootsStream();
+    refFromImmortalStream = createRefFromImmortalStream();
+    serverSpace.resize(0); // the collector must call resize() before gathering data
+
+    // Initialise the statistics
+    resetData();
+    scanner = new LinearScan(this);
+  }
+
+  /**
+   * Get the name of this driver type.
+   * @return The name of this driver.
+   */
+  protected String getDriverName() { return "MMTk LinearSpaceDriver"; }
+
+  /**
+   * Private creator methods to create the Streams.
+   */
+  @Interruptible
+  private IntStream createScalarUsedSpaceStream() {
+    return VM.newGCspyIntStream(
+                     this,
+                     "Scalar Used Space stream",            // stream name
+                     0,                                     // min. data value
+                     blockSize,                             // max. data value
+                     0,                                     // zero value
+                     0,                                     // default value
+                    "Scalars and primitive arrays: ",       // value prefix
+                    " bytes",                               // value suffix
+                     StreamConstants.PRESENTATION_PERCENT,  // presentation style
+                     StreamConstants.PAINT_STYLE_ZERO,      // paint style
+                     0,                                     // index of max stream (only needed if the presentation is *_VAR)
+                     Color.Red,                             // tile colour
+                     true);                                 // summary enabled
+  }
+
+  @Interruptible
+  private IntStream createArrayUsedSpaceStream() {
+    return VM.newGCspyIntStream(
+                     this,
+                     "Array Used Space stream",
+                     0,
+                     blockSize,
+                     0,
+                     0,
+                    "Reference arrays: ",
+                    " bytes",
+                     StreamConstants.PRESENTATION_PERCENT,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Blue,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createScalarObjectsStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Scalar Objects stream",
+                     (short)0,
+                     // Say, max value = 50% of max possible
+                     (short)(maxObjectsPerBlock(blockSize)/2),
+                     (short)0,
+                     (short)0,
+                     "Scalars: ",
+                     " objects",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Green,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createArrayPrimitiveStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Array Primitive stream",
+                     (short)0,
+                     // Say, typical primitive array size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "Primitive arrays: ",
+                     " objects",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Yellow,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createArrayObjectsStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Array Objects stream",
+                     (short)0,
+                     // Say, typical ref array size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "Reference arrays: ",
+                     " objects",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Cyan,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createRootsStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Roots stream",
+                     (short)0,
+                     // Say, typical size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "Roots: ",
+                     " objects",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Blue,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createRefFromImmortalStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "References from immortal stream",
+                     (short)0,
+                     // Say, typical size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "References from immortal space: ",
+                     " references",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Blue,
+                     true);
+  }
+
+  /**
+   * Reset the statistics for all the streams, including totals used for summaries
+   */
+  public void resetData() {
+    super.resetData();
+
+    // Reset all the streams
+    scalarUsedSpaceStream.resetData();
+    arrayUsedSpaceStream.resetData();
+    scalarObjectsStream.resetData();
+    arrayObjectsStream.resetData();
+    arrayPrimitiveStream.resetData();
+    refFromImmortalStream.resetData();
+
+    // Reset the summary counts
+    totalScalarObjects   = 0;
+    totalArrayObjects    = 0;
+    totalPrimitives      = 0;
+    totalScalarUsedSpace = 0;
+    totalArrayUsedSpace  = 0;
+    totalRefFromImmortal = 0;
+  }
+
+  /**
+   * BumpPointer.linearScan needs a LinearScan object, which we provide here.
+   * @return the scanner for this driver
+   */
+   public LinearScan getScanner() { return scanner; }
+
+  /**
+   * Set the current address range of a contiguous space
+   * @param start the start of the contiguous space
+   * @param end the end of the contiguous space
+   */
+  public void setRange(Address start, Address end) {
+    int current = subspace.getBlockNum();
+    int required = countTileNum(start, end, subspace.getBlockSize());
+
+    // Reset the subspace
+    if(required != current)
+      subspace.reset(start, end, 0, required);
+
+    if (DEBUG) {
+      Log.write("\nContiguousSpaceDriver.setRange for contiguous space: ");
+      Log.write(subspace.getFirstIndex()); Log.write("-", subspace.getBlockNum());
+      Log.write(" (", start); Log.write("-", end); Log.write(")");
+    }
+
+    // Reset the driver
+    // Note release() only resets a CopySpace's  cursor (and optionally zeroes
+    // or mprotects the pages); it doesn't make the pages available to other
+    // spaces. If pages were to be released, change the test here to
+    //     if (allTileNum != required) {
+    if (allTileNum < required) {
+      if (DEBUG) { Log.write(", resize from ", allTileNum); Log.write(" to ", required); }
+      allTileNum = required;
+      serverSpace.resize(allTileNum);
+      setTilenames(subspace, allTileNum);
+    }
+    if (DEBUG) Log.writeln();
+  }
+
+
+  /**
+   * Update the tile statistics
+   * @param obj The current object
+   */
+  public void  scan(ObjectReference obj) {
+    scan(obj, true);
+  }
+
+  /**
+   * Update the tile statistics
+   * @param obj The current object
+   * @param total Whether to accumulate the values
+   */
+  public void scan(ObjectReference obj, boolean total) {
+    boolean isArray = VM.objectModel.isArray(obj);
+    int length = VM.objectModel.getCurrentSize(obj);
+    Address addr = obj.toAddress();
+
+    if (VM.VERIFY_ASSERTIONS) {
+      if(addr.LT(lastAddress.plus(lastSize))) {
+        Log.write("\nContiguousSpaceDriver finds addresses going backwards: ");
+        Log.write("last="); Log.write(lastAddress);
+        Log.write(" last size="); Log.write(lastSize);
+        Log.writeln(" current=", addr);
+      }
+      lastAddress = addr;
+      lastSize = length;
+    }
+
+    // Update the stats
+    if (subspace.addressInRange(addr)) {
+      int index = subspace.getIndex(addr);
+      int remainder = subspace.spaceRemaining(addr);
+      if (isArray) {
+        arrayObjectsStream.increment(index, (short)1);
+        arrayUsedSpaceStream.distribute(index, remainder, blockSize, length);
+        if (total) {
+          totalArrayObjects++;
+          totalArrayUsedSpace += length;
+        }
+      } else {
+        if(!this.scanCheckPrimitiveArray(obj, index, total, length)) {
+          // real object
+          scalarObjectsStream.increment(index, (short)1);
+          if (total) {
+            totalScalarObjects++;
+            totalScalarUsedSpace += length;
+          }
+        }
+        scalarUsedSpaceStream.distribute(index, remainder, blockSize, length);
+      }
+    }
+  }
+
+  /**
+   * Check if this Object is an array of primitives.<br>
+   * Part of the public scan() method.
+   *
+   * @param obj The Object to check
+   * @param index Index of the tile
+   * @param total Increment summary
+   * @param length Current size of the Object, will be added to array space summary.
+   * @return True if this Object is an array of primitives.
+   */
+  protected boolean scanCheckPrimitiveArray(ObjectReference obj, int index, boolean total, int length) {
+    if(VM.objectModel.isPrimitiveArray(obj)) {
+      arrayPrimitiveStream.increment(index, (short)1);
+      if (total) {
+        totalPrimitives++;
+        totalScalarUsedSpace += length;
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Transmit the data if this event is of interest to the client.<p>
+   * Implemented using the algorithm pattern, subclasses can override parts of it.
+   * @param event The event, defined in the Plan
+   */
+  public void transmit(int event) {
+    if (!server.isConnected(event))
+      return;
+
+    if (DEBUG) {
+      Log.write("CONNECTED\n");
+      Log.write(myClass);
+      Log.write(".send: numTiles=", allTileNum);
+      //Log.write("LinearSpaceDriver.transmit: numTiles=", allTileNum);
+      Log.writeln(", control.length=", control.length);
+      Log.flush();
+    }
+
+    // Setup the summaries
+    setupSummaries();
+
+    // Setup the control info
+    setupControlInfo();
+
+    // Setup the space info
+    Offset size = subspace.getEnd().diff(subspace.getStart());
+    setSpaceInfo(size);
+
+    // Send the all streams
+    send(event, allTileNum);
+
+    // Debugging
+    if (VM.VERIFY_ASSERTIONS) {
+      lastAddress = Address.zero();
+      lastSize = 0;
+    }
+  }
+
+  /**
+   * Setup summaries part of the <code>transmit</code> method.<p>
+   * Override this method to setup summaries of additional streams in subclasses.
+ */
+  protected void setupSummaries() {
+    scalarUsedSpaceStream.setSummary(totalScalarUsedSpace,
+                                     subspace.getEnd().diff(subspace.getStart()).toInt());
+    arrayUsedSpaceStream.setSummary(totalArrayUsedSpace,
+                                    subspace.getEnd().diff(subspace.getStart()).toInt());
+    scalarObjectsStream.setSummary(totalScalarObjects);
+    arrayObjectsStream.setSummary(totalArrayObjects);
+    arrayPrimitiveStream.setSummary(totalPrimitives);
+    rootsStream.setSummary(totalRoots);
+    refFromImmortalStream.setSummary(totalRefFromImmortal);
+  }
+
+  /**
+   * Setup control info part of the <code>transmit</code> method.<p>
+   * Override this method to change the controls for your own driver subclass.
+ */
+  protected void setupControlInfo() {
+    int numBlocks = subspace.getBlockNum();
+    controlValues(CONTROL_USED, subspace.getFirstIndex(), numBlocks);
+    if (DEBUG) {
+      Log.write("LinearSpaceDriver.transmitSetupControlInfo: allTileNum=", allTileNum);
+      Log.writeln(", numBlocks=", numBlocks);
+    }
+    if (numBlocks < allTileNum)
+      controlValues(CONTROL_UNUSED,
+                    subspace.getFirstIndex() + numBlocks,
+                    allTileNum - numBlocks);
+  }
+
+  /**
+   * Handle a root address
+   *
+   * @param addr Root Address
+   * @return true if the given Address is in this subspace.
+   */
+  public boolean handleRoot(Address addr) {
+    if(subspace.addressInRange(addr)) {
+      // increment tile
+      int index = subspace.getIndex(addr);
+      rootsStream.increment(index, (short)1);
+      // increment summary
+      this.totalRoots++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Reset the roots Stream
+   * The roots Stream has to be reset seperately because we do not
+   * gather data in the usual way using <code>scan()</code>.
+ */
+  public void resetRootsStream() {
+    rootsStream.resetData();
+    totalRoots = 0;
+  }
+
+  /**
+   * Handle a direct reference from the immortal space.
+   *
+   * @param addr The Address
+   * @return true if the given Address is in this subspace.
+   */
+  public boolean handleReferenceFromImmortalSpace(Address addr) {
+    if(subspace.addressInRange(addr)) {
+      // increment tile
+      int index = subspace.getIndex(addr);
+      refFromImmortalStream.increment(index, (short)1);
+      // increment summary
+      this.totalRefFromImmortal++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/TreadmillDriver.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/TreadmillDriver.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/TreadmillDriver.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/gcspy/drivers/TreadmillDriver.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,326 @@
+/*
+ *  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.mmtk.utility.gcspy.drivers;
+
+import org.mmtk.policy.LargeObjectSpace;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.utility.gcspy.Subspace;
+import org.mmtk.vm.gcspy.IntStream;
+import org.mmtk.vm.gcspy.ShortStream;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.utility.Conversions;
+import org.mmtk.utility.Log;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+
+/**
+ * This class implements a simple driver for the MMTk LargeObjectSpace.
+ */
+ at Uninterruptible public class TreadmillDriver extends AbstractDriver {
+
+  private static final boolean DEBUG = false;
+
+  // The streams
+  protected IntStream   usedSpaceStream;
+  protected ShortStream objectsStream;
+  protected ShortStream rootsStream;
+  protected ShortStream refFromImmortalStream;
+
+  protected Subspace subspace;            // A single subspace for this space
+  protected int allTileNum;               // total number of tiles
+
+  // Overall statistics
+  protected int totalObjects         = 0; // total number of objects allocated
+  protected int totalUsedSpace       = 0; // total space used
+  protected int totalRoots           = 0; // total of roots
+  protected int totalRefFromImmortal = 0; // total direct references from the immortal space
+  protected Address maxAddr;              // the largest address seen
+  protected int threshold;
+
+
+  /**
+   * Create a new driver for this collector
+   *
+   * @param server The name of the GCspy server that owns this space
+   * @param spaceName The name of this driver
+   * @param lospace the large object space for this allocator
+   * @param blockSize The tile size
+   * @param threshold the size threshold of the LOS
+   * @param mainSpace Is this the main space?
+   */
+  public TreadmillDriver(
+                         ServerInterpreter server,
+                         String spaceName,
+                         LargeObjectSpace lospace,
+                         int blockSize,
+                         int threshold,
+                         boolean mainSpace) {
+    //TODO blocksize should be a multiple of treadmill granularity
+    super(server, spaceName, lospace, blockSize, mainSpace);
+
+    if (DEBUG) {
+      Log.write("TreadmillDriver for "); Log.write(spaceName);
+      Log.write(", blocksize="); Log.write(blockSize);
+      Log.write(", start="); Log.write(lospace.getStart());
+      Log.write(", extent="); Log.write(lospace.getExtent());
+      Log.write(", maxTileNum="); Log.writeln(maxTileNum);
+    }
+
+    this.threshold = threshold;
+
+    // Initialise a subspace and 2 Streams
+    subspace = createSubspace(lospace);
+    allTileNum = 0;
+    maxAddr = lospace.getStart();
+    usedSpaceStream       = createUsedSpaceStream();
+    objectsStream         = createObjectsStream();
+    rootsStream           = createRootsStream();
+    refFromImmortalStream = createRefFromImmortalStream();
+    serverSpace.resize(0); // the collector must call resize() before gathering data
+
+    // Initialise the statistics
+    resetData();
+  }
+
+  /**
+   * Get the name of this driver type.
+   * @return The name, "MMTk TreadmillDriver" for this driver.
+   */
+  protected String getDriverName() {
+    return "MMTk TreadmillDriver";
+  }
+
+  // private creator methods for the streams
+  @Interruptible
+  private IntStream createUsedSpaceStream() {
+    return VM.newGCspyIntStream(
+                     this,
+                     "Used Space stream",                    // stream name
+                     0,                                      // min. data value
+                     blockSize,                              // max. data value
+                     0,                                      // zero value
+                     0,                                      // default value
+                    "Space used: ",                          // value prefix
+                    " bytes",                                // value suffix
+                     StreamConstants.PRESENTATION_PERCENT,   // presentation style
+                     StreamConstants.PAINT_STYLE_ZERO,       // paint style
+                     0,                                      // index of the max stream (only needed if presentation is *_VAR)
+                     Color.Red,                              // tile colour
+                     true);                                  // summary enabled
+  }
+
+  @Interruptible
+  private ShortStream createObjectsStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Objects stream",
+                     (short)0,
+                     (short)(blockSize/threshold),
+                     (short)0,
+                     (short)0,
+                     "No. of objects = ",
+                     " objects",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Green,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createRootsStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "Roots stream",
+                     (short)0,
+                     // Say, typical size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "Roots: ",
+                     " objects",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Blue,
+                     true);
+  }
+
+  @Interruptible
+  private ShortStream createRefFromImmortalStream() {
+    return VM.newGCspyShortStream(
+                     this,
+                     "References from Immortal stream",
+                     (short)0,
+                     // Say, typical size = 4 * typical scalar size?
+                     (short)(maxObjectsPerBlock(blockSize)/8),
+                     (short)0,
+                     (short)0,
+                     "References from immortal space: ",
+                     " references",
+                     StreamConstants.PRESENTATION_PLUS,
+                     StreamConstants.PAINT_STYLE_ZERO,
+                     0,
+                     Color.Blue,
+                     true);
+  }
+
+  /**
+   * Reset the tile stats for all streams, including values used for summaries
+   */
+  public void resetData() {
+    super.resetData();
+
+    // Reset all the streams
+    usedSpaceStream.resetData();
+    objectsStream.resetData();
+    refFromImmortalStream.resetData();
+
+    // Reset the summary counts
+    totalUsedSpace = 0;
+    totalObjects = 0;
+    totalRefFromImmortal = 0;
+  }
+
+  /**
+   * Update the tile statistics
+   * In this case, we are accounting for super-page objects, rather than
+   * simply for the objects they contain.
+   *
+   * @param addr The address of the superpage
+   */
+  public void scan(Address addr) {
+
+    int index = subspace.getIndex(addr);
+    int length = ((LargeObjectSpace)mmtkSpace).getSize(addr).toInt();
+
+    if (DEBUG) {
+      Log.write("TreadmillDriver: super=", addr);
+      Log.write(", index=", index);
+      Log.write(", pages=", length);
+      Log.write(", bytes=", Conversions.pagesToBytes(length).toInt());
+      Log.writeln(", max=", usedSpaceStream.getMaxValue());
+    }
+
+    totalObjects++;
+    totalUsedSpace += length;
+    objectsStream.increment(index, (short)1);
+    int remainder = subspace.spaceRemaining(addr);
+    usedSpaceStream.distribute(index, remainder, blockSize, length);
+
+    Address tmp = addr.plus(length);
+    if (tmp.GT(maxAddr)) maxAddr = tmp;
+  }
+
+  /**
+   * Transmit the data if this event is of interest to the client
+   * @param event The event, either BEFORE_COLLECTION, SEMISPACE_COPIED
+   * or AFTER_COLLECTION
+   */
+  public void transmit(int event) {
+    if (!isConnected(event))
+      return;
+
+    // At this point, we've filled the tiles with data,
+    // however, we don't know the size of the space
+    // Calculate the highest indexed tile used so far, and update the subspace
+    Address start = subspace.getStart();
+    int required = countTileNum(start, maxAddr, blockSize);
+    int current = subspace.getBlockNum();
+    if (required > current || maxAddr != subspace.getEnd()) {
+      subspace.reset(start, maxAddr, 0, required);
+      allTileNum = required;
+      serverSpace.resize(allTileNum);
+      setTilenames(subspace, allTileNum);
+    }
+
+    // Set the summaries
+    setupSummaries();
+
+    // set the control info: all of space is USED
+    controlValues(CONTROL_USED,
+                  subspace.getFirstIndex(), subspace.getBlockNum());
+
+    // send the space info
+    Offset size = subspace.getEnd().diff(subspace.getStart());
+    setSpaceInfo(size);
+
+    // Send the streams
+    send(event, allTileNum);
+  }
+
+  /**
+   * Setup summaries part of the <code>transmit</code> method.<p>
+   * Override this method to setup summaries of additional streams in subclasses.
+   */
+  protected void setupSummaries() {
+    usedSpaceStream.setSummary(totalUsedSpace,
+                               subspace.getEnd().diff(subspace.getStart()).toInt());
+    objectsStream.setSummary(totalObjects);
+    rootsStream.setSummary(totalRoots);
+    refFromImmortalStream.setSummary(totalRefFromImmortal);
+  }
+
+
+  /**
+   * Handle a root address
+   *
+   * @param addr Root Address
+   * @return true if the given Address is in this subspace.
+   */
+  public boolean handleRoot(Address addr) {
+    if(subspace.addressInRange(addr)) {
+      // increment tile
+      int index = subspace.getIndex(addr);
+      rootsStream.increment(index, (short)1);
+      // increment summary
+      this.totalRoots++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Reset the roots Stream. <br>
+   * The roots Stream has to be reset seperately because we do not
+   * gather data in the usual way using <code>scan()</code>.
+   */
+  public void resetRootsStream() {
+    rootsStream.resetData();
+    totalRoots = 0;
+  }
+
+  /**
+   * Handle a direct reference from the immortal space.
+   *
+   * @param addr The Address
+   * @return true if the given Address is in this subspace.
+   */
+  public boolean handleReferenceFromImmortalSpace(Address addr) {
+    if(subspace.addressInRange(addr)) {
+      // increment tile
+      int index = subspace.getIndex(addr);
+      refFromImmortalStream.increment(index, (short)1);
+      // increment summary
+      this.totalRefFromImmortal++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/FreeListPageResource.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/FreeListPageResource.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/FreeListPageResource.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/FreeListPageResource.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,382 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.policy.Space;
+import static org.mmtk.policy.Space.PAGES_IN_CHUNK;
+import org.mmtk.utility.alloc.EmbeddedMetaData;
+import org.mmtk.utility.Conversions;
+import org.mmtk.utility.GenericFreeList;
+import org.mmtk.vm.VM;
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This class manages the allocation of pages for a space.  When a
+ * page is requested by the space both a page budget and the use of
+ * virtual address space are checked.  If the request for space can't
+ * be satisfied (for either reason) a GC may be triggered.<p>
+ */
+ at Uninterruptible
+public final class FreeListPageResource extends PageResource implements Constants {
+
+  private final GenericFreeList freeList;
+  private int highWaterMark = 0;
+  private final int metaDataPagesPerRegion;
+  private int pagesCurrentlyOnFreeList = 0;
+
+  /**
+   * Constructor
+   *
+   * Contiguous free list resource. The address range is pre-defined at
+   * initialization time and is immutable.
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   * @param start The start of the address range allocated to this resource
+   * @param bytes The size of the address rage allocated to this resource
+   */
+  public FreeListPageResource(int pageBudget, Space space, Address start,
+      Extent bytes) {
+    super(pageBudget, space, start);
+    int pages = Conversions.bytesToPages(bytes);
+    freeList = new GenericFreeList(pages);
+    pagesCurrentlyOnFreeList = pages;
+    this.metaDataPagesPerRegion = 0;
+  }
+
+  /**
+   * Constructor
+   *
+   * Contiguous free list resource. The address range is pre-defined at
+   * initialization time and is immutable.
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   * @param start The start of the address range allocated to this resource
+   * @param bytes The size of the address rage allocated to this resource
+   * @param metaDataPagesPerRegion The number of pages of meta data
+   * that are embedded in each region.
+   */
+  public FreeListPageResource(int pageBudget, Space space, Address start,
+      Extent bytes, int metaDataPagesPerRegion) {
+    super(pageBudget, space, start);
+    this.metaDataPagesPerRegion = metaDataPagesPerRegion;
+    int pages = Conversions.bytesToPages(bytes);
+    freeList = new GenericFreeList(pages, EmbeddedMetaData.PAGES_IN_REGION);
+    pagesCurrentlyOnFreeList = pages;
+    reserveMetaData(space.getExtent());
+  }
+
+  /**
+   * Constructor
+   *
+   * Discontiguous monotone resource. The address range is <i>not</i>
+   * pre-defined at initialization time and is dynamically defined to
+   * be some set of pages, according to demand and availability.
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   */
+  public FreeListPageResource(int pageBudget, Space space, int metaDataPagesPerRegion) {
+    super(pageBudget, space);
+    this.metaDataPagesPerRegion = metaDataPagesPerRegion;
+    this.start = Space.AVAILABLE_START;
+    freeList = new GenericFreeList(Map.globalPageMap, Map.getDiscontigFreeListPROrdinal(this));
+    pagesCurrentlyOnFreeList = 0;
+  }
+
+  /**
+   * Return the number of available physical pages for this resource.
+   * This includes all pages currently free on the resource's free list.
+   * If the resource is using discontiguous space it also includes
+   * currently unassigned discontiguous space.<p>
+   *
+   * Note: This just considers physical pages (ie virtual memory pages
+   * allocated for use by this resource). This calculation is orthogonal
+   * to and does not consider any restrictions on the number of pages
+   * this resource may actually use at any time (ie the number of
+   * committed and reserved pages).<p>
+   *
+   * Note: The calculation is made on the assumption that all space that
+   * could be assigned to this resource would be assigned to this resource
+   * (ie the unused discontiguous space could just as likely be assigned
+   * to another competing resource).
+   *
+   * @return The number of available physical pages for this resource.
+   */
+  @Override
+  public int getAvailablePhysicalPages() {
+    int rtn = pagesCurrentlyOnFreeList;
+    if (!contiguous) {
+      int chunks = Map.getAvailableDiscontiguousChunks()-Map.getChunkConsumerCount();
+      if (chunks < 0) chunks = 0;
+      rtn += chunks*(Space.PAGES_IN_CHUNK-metaDataPagesPerRegion);
+    }
+    return rtn;
+  }
+
+  /**
+   * Allocate <code>pages</code> pages from this resource.<p>
+   *
+   * If the request can be satisfied, then ensure the pages are
+   * mmpapped and zeroed before returning the address of the start of
+   * the region.  If the request cannot be satisfied, return zero.
+   *
+   * @param pages The number of pages to be allocated.
+   * @return The start of the first page if successful, zero on
+   * failure.
+   */
+  @Inline
+  protected Address allocPages(int pages) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(metaDataPagesPerRegion == 0 || pages <= PAGES_IN_CHUNK - metaDataPagesPerRegion);
+    lock();
+    boolean newChunk = false;
+    int pageOffset = freeList.alloc(pages);
+    if (pageOffset == GenericFreeList.FAILURE && !contiguous) {
+      pageOffset = allocateContiguousChunks(pages);
+      newChunk = true;
+    }
+    if (pageOffset == -1) {
+      unlock();
+      return Address.zero();
+    } else {
+      pagesCurrentlyOnFreeList -= pages;
+      if (pageOffset > highWaterMark) {
+        if ((pageOffset ^ highWaterMark) > EmbeddedMetaData.PAGES_IN_REGION) {
+          int regions = 1 + ((pageOffset - highWaterMark) >> EmbeddedMetaData.LOG_PAGES_IN_REGION);
+          int metapages = regions * metaDataPagesPerRegion;
+          reserved += metapages;
+          committed += metapages;
+          newChunk = true;
+        }
+        highWaterMark = pageOffset;
+      }
+      Address rtn = start.plus(Conversions.pagesToBytes(pageOffset));
+      Extent bytes = Conversions.pagesToBytes(pages);
+      commitPages(pages, pages);
+      space.growSpace(rtn, bytes, newChunk);
+      unlock();
+      Mmapper.ensureMapped(rtn, pages);
+      VM.memory.zero(rtn, bytes);
+      VM.events.tracePageAcquired(space, rtn, pages);
+      return rtn;
+    }
+  }
+
+  /**
+   * Release a group of pages, associated with this page resource,
+   * that were allocated together, optionally zeroing on release and
+   * optionally memory protecting on release.
+   *
+   * @param first The first page in the group of pages that were
+   * allocated together.
+   */
+  @Inline
+  public void releasePages(Address first) {
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(Conversions.isPageAligned(first));
+
+    int pageOffset = Conversions.bytesToPages(first.diff(start));
+
+    int pages = freeList.size(pageOffset);
+    if (ZERO_ON_RELEASE)
+      VM.memory.zero(first, Conversions.pagesToBytes(pages));
+    /* Can't use protect here because of the chunk sizes involved!
+    if (protectOnRelease.getValue())
+      LazyMmapper.protect(first, pages);
+     */
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(pages <= committed);
+
+    lock();
+    reserved -= pages;
+    committed -= pages;
+    int freed = freeList.free(pageOffset, true);
+    pagesCurrentlyOnFreeList += pages;
+
+    if (!contiguous) // only discontiguous spaces use chunks
+      releaseFreeChunks(first, freed);
+
+    unlock();
+
+    VM.events.tracePageReleased(space, first, pages);
+  }
+
+  /**
+   * The release of a page may have freed up an entire chunk or
+   * set of chunks.  We need to check whether any chunks can be
+   * freed, and if so, free them.
+   *
+   * @param freedPage The address of the page that was just freed.
+   * @param pagesFreed The number of pages made available when the page was freed.
+   */
+  private void releaseFreeChunks(Address freedPage, int pagesFreed) {
+    int pageOffset = Conversions.bytesToPages(freedPage.diff(start));
+
+    if (metaDataPagesPerRegion > 0) {       // can only be a single chunk
+      if (pagesFreed == (PAGES_IN_CHUNK - metaDataPagesPerRegion)) {
+        freeContiguousChunk(Space.chunkAlign(freedPage, true));
+      }
+    } else {                                // may be multiple chunks
+      if (pagesFreed % PAGES_IN_CHUNK == 0) {    // necessary, but not sufficient condition
+        /* grow a region of chunks, starting with the chunk containing the freed page */
+        int regionStart = pageOffset & ~(PAGES_IN_CHUNK - 1);
+        int nextRegionStart = regionStart + PAGES_IN_CHUNK;
+        /* now try to grow (end point pages are marked as non-coalescing) */
+        while (regionStart >= 0 && freeList.isCoalescable(regionStart))
+          regionStart -= PAGES_IN_CHUNK;
+        while (nextRegionStart < GenericFreeList.MAX_UNITS && freeList.isCoalescable(nextRegionStart))
+          nextRegionStart += PAGES_IN_CHUNK;
+         if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(regionStart >= 0 && nextRegionStart < GenericFreeList.MAX_UNITS);
+        if (pagesFreed == nextRegionStart - regionStart) {
+          freeContiguousChunk(start.plus(Conversions.pagesToBytes(regionStart)));
+        }
+      }
+    }
+  }
+
+  /**
+   * Allocate sufficient contiguous chunks within a discontiguous region to
+   * satisfy the pending request.  Note that this is purely about address space
+   * allocation within a discontiguous region.  This method does not reserve
+   * individual pages, it merely assigns a suitably large region of virtual
+   * memory from within the discontiguous region for use by a particular space.
+   *
+   * @param pages The number of pages currently being requested
+   * @return A chunk number or GenericFreelist.FAILURE
+   */
+  private int allocateContiguousChunks(int pages) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(metaDataPagesPerRegion == 0 || pages <= PAGES_IN_CHUNK - metaDataPagesPerRegion);
+    int rtn = GenericFreeList.FAILURE;
+    int requiredChunks = Space.requiredChunks(pages);
+    Address region = space.growDiscontiguousSpace(requiredChunks);
+    if (!region.isZero()) {
+      int regionStart = Conversions.bytesToPages(region.diff(start));
+      int regionEnd = regionStart + (requiredChunks*Space.PAGES_IN_CHUNK) - 1;
+      freeList.setUncoalescable(regionStart);
+      freeList.setUncoalescable(regionEnd + 1);
+      for (int p = regionStart; p < regionEnd; p += Space.PAGES_IN_CHUNK) {
+        int liberated;
+        if (p != regionStart)
+          freeList.clearUncoalescable(p);
+        liberated = freeList.free(p, true); // add chunk to our free list
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(liberated == Space.PAGES_IN_CHUNK + (p - regionStart));
+        if (metaDataPagesPerRegion > 1)
+          freeList.alloc(metaDataPagesPerRegion, p); // carve out space for metadata
+        pagesCurrentlyOnFreeList += Space.PAGES_IN_CHUNK - metaDataPagesPerRegion;
+      }
+      rtn = freeList.alloc(pages); // re-do the request which triggered this call
+    }
+    return rtn;
+  }
+
+  /**
+   * Release a single chunk from a discontiguous region.  All this does is
+   * release a chunk from the virtual address space associated with this
+   * discontiguous space.
+   *
+   * @param chunk The chunk to be freed
+   */
+  private void freeContiguousChunk(Address chunk) {
+    int numChunks = Map.getContiguousRegionChunks(chunk);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(numChunks == 1 || metaDataPagesPerRegion == 0);
+
+    /* nail down all pages associated with the chunk, so it is no longer on our free list */
+    int chunkStart = Conversions.bytesToPages(chunk.diff(start));
+    int chunkEnd = chunkStart + (numChunks*Space.PAGES_IN_CHUNK);
+    while (chunkStart < chunkEnd) {
+      freeList.setUncoalescable(chunkStart);
+      if (metaDataPagesPerRegion > 0)
+        freeList.free(chunkStart);  // first free any metadata pages
+      int tmp = freeList.alloc(Space.PAGES_IN_CHUNK, chunkStart); // then alloc the entire chunk
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tmp == chunkStart);
+      chunkStart += Space.PAGES_IN_CHUNK;
+      pagesCurrentlyOnFreeList -= (Space.PAGES_IN_CHUNK - metaDataPagesPerRegion);
+    }
+    /* now return the address space associated with the chunk for global reuse */
+    space.releaseDiscontiguousChunks(chunk);
+  }
+
+  /**
+   * Reserve virtual address space for meta-data.
+   *
+   * @param extent The size of this space
+   */
+  private void reserveMetaData(Extent extent) {
+    highWaterMark = 0;
+    if (metaDataPagesPerRegion > 0) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(start.toWord().rshl(EmbeddedMetaData.LOG_BYTES_IN_REGION).lsh(EmbeddedMetaData.LOG_BYTES_IN_REGION).toAddress().EQ(start));
+      Extent size = extent.toWord().rshl(EmbeddedMetaData.LOG_BYTES_IN_REGION).lsh(EmbeddedMetaData.LOG_BYTES_IN_REGION).toExtent();
+      Address cursor = start.plus(size);
+      while (cursor.GT(start)) {
+        cursor = cursor.minus(EmbeddedMetaData.BYTES_IN_REGION);
+        int unit = cursor.diff(start).toWord().rshl(LOG_BYTES_IN_PAGE).toInt();
+        int tmp = freeList.alloc(metaDataPagesPerRegion, unit);
+        pagesCurrentlyOnFreeList -= metaDataPagesPerRegion;
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tmp == unit);
+      }
+    }
+  }
+
+  /**
+   * Adjust a page request to include metadata requirements, if any.  In the
+   * case of a free-list allocator, meta-data is pre-allocated, so simply
+   * return the un-adjusted request size.
+   *
+   * @param pages The size of the pending allocation in pages
+   * @return The (unadjusted) request size, since metadata is pre-allocated
+   */
+  public int adjustForMetaData(int pages) { return pages; }
+
+  public Address getHighWater() {
+    return start.plus(Extent.fromIntSignExtend(highWaterMark<<LOG_BYTES_IN_PAGE));
+  }
+
+  /**
+   * Return the size of the super page
+   *
+   * @param first the Address of the first word in the superpage
+   * @return the size in bytes
+   */
+  @Inline
+  public Extent getSize(Address first) {
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(Conversions.isPageAligned(first));
+
+    int pageOffset = Conversions.bytesToPages(first.diff(start));
+    int pages = freeList.size(pageOffset);
+    return Conversions.pagesToBytes(pages);
+  }
+
+  /**
+   * Resize the free list associated with this resource and nail down
+   * its start address. This method is called to re-set the free list
+   * once the global free list (which it shares) is finalized and the
+   * base address is finalized.  There's a circular dependency, so we
+   * need an explicit call-back to reset the free list size and start
+   *
+   * @param startAddress The final start address for the discontiguous space.
+   */
+  @Interruptible
+  public void resizeFreeList(Address startAddress) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!contiguous && !Plan.isInitialized());
+    start = startAddress;
+    freeList.resizeFreeList();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/HeapGrowthManager.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/HeapGrowthManager.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/HeapGrowthManager.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/HeapGrowthManager.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,293 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.utility.*;
+import org.mmtk.utility.options.Options;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class is responsible for growing and shrinking the
+ * heap size by observing heap utilization and GC load.
+ */
+ at Uninterruptible public abstract class HeapGrowthManager implements Constants {
+
+  /**
+   * The initial heap size (-Xms) in bytes
+   */
+  private static Extent initialHeapSize;
+
+  /**
+   * The maximum heap size (-Xms) in bytes
+   */
+  private static Extent maxHeapSize;
+
+  /**
+   * The current heap size in bytes
+   */
+  private static Extent currentHeapSize;
+
+
+  private static final double[][] generationalFunction =    {{0.00, 0.00, 0.10, 0.30, 0.60, 0.80, 1.00},
+      { 0.00, 0.90, 0.90, 0.95, 1.00, 1.00, 1.00 },
+      { 0.01, 0.90, 0.90, 0.95, 1.00, 1.00, 1.00 },
+      { 0.02, 0.95, 0.95, 1.00, 1.00, 1.00, 1.00 },
+      { 0.07, 1.00, 1.00, 1.10, 1.15, 1.20, 1.20 },
+      { 0.15, 1.00, 1.00, 1.20, 1.25, 1.35, 1.30 },
+      { 0.40, 1.00, 1.00, 1.25, 1.30, 1.50, 1.50 },
+      { 1.00, 1.00, 1.00, 1.25, 1.30, 1.50, 1.50 } };
+
+  private static final double[][] nongenerationalFunction = {{0.00, 0.00, 0.10, 0.30, 0.60, 0.80, 1.00},
+      { 0.00, 0.90, 0.90, 0.95, 1.00, 1.00, 1.00 },
+      { 0.02, 0.90, 0.90, 0.95, 1.00, 1.00, 1.00 },
+      { 0.05, 0.95, 0.95, 1.00, 1.00, 1.00, 1.00 },
+      { 0.15, 1.00, 1.00, 1.10, 1.15, 1.20, 1.20 },
+      { 0.30, 1.00, 1.00, 1.20, 1.25, 1.35, 1.30 },
+      { 0.50, 1.00, 1.00, 1.25, 1.30, 1.50, 1.50 },
+      { 1.00, 1.00, 1.00, 1.25, 1.30, 1.50, 1.50 } };
+
+  /**
+   * An encoding of the function used to manage heap size.
+   * The xaxis represents the live ratio at the end of a major collection.
+   * The yaxis represents the GC load (GC time/total time).
+   * The interior of the matrix represents a ratio to shrink or grow
+   * the heap for a given pair of live ratio and GC load.
+   * The constraints on the matrix are:
+   * <ul>
+   * <li> function[0][0] is ignored.
+   * <li> All numbers in the first row must monotonically increase and
+   *      must be in the range from 0 to 1 inclusive.</li>
+   * <li> All numbers in the first column must monotonically increase
+   *      and must be in the range from 0 to 1 inclusive.</li>
+   * <li> There must be 0 and 1 values specified in both dimensions.
+   * <li> For all interior points in the matrix, the value must be
+   *      greater than the liveRatio for that column.</li>
+   * </ul>
+   */
+  private static final double[][] function =
+    VM.activePlan.constraints().generational() ? generationalFunction : nongenerationalFunction;
+
+  private static long endLastMajorGC;
+  private static double accumulatedGCTime;
+
+  /**
+   * Initialize heap size parameters and the mechanisms
+   * used to adaptively change heap size.
+   */
+  public static void boot(Extent initial, Extent max) {
+    initialHeapSize = initial;
+    maxHeapSize = max;
+    if (initialHeapSize.GT(maxHeapSize))
+      maxHeapSize = initialHeapSize;
+    currentHeapSize = initialHeapSize;
+    VM.events.heapSizeChanged(currentHeapSize);
+    if (VM.VERIFY_ASSERTIONS) sanityCheck();
+    endLastMajorGC = VM.statistics.nanoTime();
+  }
+
+  /**
+   * @return the current heap size in bytes
+   */
+  public static Extent getCurrentHeapSize() {
+    return currentHeapSize;
+  }
+
+  /**
+   * Return the max heap size in bytes (as set by -Xmx).
+   *
+   * @return The max heap size in bytes (as set by -Xmx).
+   */
+  public static Extent getMaxHeapSize() {
+    return maxHeapSize;
+  }
+
+  /**
+   * Return the initial heap size in bytes (as set by -Xms).
+   *
+   * @return The initial heap size in bytes (as set by -Xms).
+   */
+  public static Extent getInitialHeapSize() {
+    return initialHeapSize;
+  }
+
+  /**
+   * Forcibly grow the heap by the given number of bytes.
+   * Used to provide headroom when handling an OutOfMemory
+   * situation.
+   * @param size number of bytes to grow the heap
+   */
+  public static void overrideGrowHeapSize(Extent size) {
+    currentHeapSize = currentHeapSize.plus(size);
+    VM.events.heapSizeChanged(currentHeapSize);
+  }
+
+  /**
+   * Record the time taken by the current GC;
+   * used to compute gc load, one of the inputs
+   * into the heap size management function
+   */
+  public static void recordGCTime(double time) {
+    accumulatedGCTime += time;
+  }
+
+  /**
+   * Reset timers used to compute gc load
+   */
+  public static void reset() {
+    endLastMajorGC = VM.statistics.nanoTime();
+    accumulatedGCTime = 0;
+  }
+
+  /**
+   * Decide how to grow/shrink the heap to respond
+   * to application's memory usage.
+   * @return true if heap size was changed, false otherwise
+   */
+  public static boolean considerHeapSize() {
+    Extent oldSize = currentHeapSize;
+    Extent reserved = Plan.reservedMemory();
+    double liveRatio = reserved.toLong() / ((double) currentHeapSize.toLong());
+    double ratio = computeHeapChangeRatio(liveRatio);
+    Extent newSize = Word.fromIntSignExtend((int)(ratio * (double) (oldSize.toLong()>>LOG_BYTES_IN_MBYTE))).lsh(LOG_BYTES_IN_MBYTE).toExtent(); // do arith in MB to avoid overflow
+    if (newSize.LT(reserved)) newSize = reserved;
+    newSize = newSize.plus(BYTES_IN_MBYTE - 1).toWord().rshl(LOG_BYTES_IN_MBYTE).lsh(LOG_BYTES_IN_MBYTE).toExtent(); // round to next megabyte
+    if (newSize.GT(maxHeapSize)) newSize = maxHeapSize;
+    if (newSize.NE(oldSize) && newSize.GT(Extent.zero())) {
+      // Heap size is going to change
+      currentHeapSize = newSize;
+      if (Options.verbose.getValue() >= 2) {
+        Log.write("GC Message: Heap changed from "); Log.writeDec(oldSize.toWord().rshl(LOG_BYTES_IN_KBYTE));
+        Log.write("KB to "); Log.writeDec(newSize.toWord().rshl(LOG_BYTES_IN_KBYTE));
+        Log.writeln("KB");
+      }
+      VM.events.heapSizeChanged(currentHeapSize);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  private static double computeHeapChangeRatio(double liveRatio) {
+    // (1) compute GC load.
+    long totalNanos = VM.statistics.nanoTime() - endLastMajorGC;
+    double totalTime = VM.statistics.nanosToMillis(totalNanos);
+    double gcLoad = accumulatedGCTime / totalTime;
+
+    if (liveRatio > 1) {
+      // Perhaps indicates bad bookkeeping in MMTk?
+      Log.write("GCWarning: Live ratio greater than 1: ");
+      Log.writeln(liveRatio);
+      liveRatio = 1;
+    }
+    if (gcLoad > 1) {
+      if (gcLoad > 1.0001) {
+        Log.write("GC Error: GC load was greater than 1!! ");
+        Log.writeln(gcLoad);
+        Log.write("GC Error:\ttotal time (ms) "); Log.writeln(totalTime);
+        Log.write("GC Error:\tgc time (ms) "); Log.writeln(accumulatedGCTime);
+      }
+      gcLoad = 1;
+    }
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(liveRatio >= 0);
+    if (VM.VERIFY_ASSERTIONS && gcLoad < -0.0) {
+      Log.write("gcLoad computed to be "); Log.writeln(gcLoad);
+      Log.write("\taccumulateGCTime was (ms) "); Log.writeln(accumulatedGCTime);
+      Log.write("\ttotalTime was (ms) "); Log.writeln(totalTime);
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(false);
+    }
+
+    if (Options.verbose.getValue() > 2) {
+      Log.write("Live ratio "); Log.writeln(liveRatio);
+      Log.write("GCLoad     "); Log.writeln(gcLoad);
+    }
+
+    // (2) Find the 4 points surrounding gcLoad and liveRatio
+    int liveRatioUnder = 1;
+    int liveRatioAbove = function[0].length - 1;
+    int gcLoadUnder = 1;
+    int gcLoadAbove = function.length - 1;
+    while (true) {
+      if (function[0][liveRatioUnder+1] >= liveRatio) break;
+      liveRatioUnder++;
+    }
+    while (true) {
+      if (function[0][liveRatioAbove-1] <= liveRatio) break;
+      liveRatioAbove--;
+    }
+    while (true) {
+      if (function[gcLoadUnder+1][0] >= gcLoad) break;
+      gcLoadUnder++;
+    }
+    while (true) {
+      if (function[gcLoadAbove-1][0] <= gcLoad) break;
+      gcLoadAbove--;
+    }
+
+    // (3) Compute the heap change ratio
+    double factor = function[gcLoadUnder][liveRatioUnder];
+    double liveRatioFraction =
+      (liveRatio - function[0][liveRatioUnder]) /
+      (function[0][liveRatioAbove] - function[0][liveRatioUnder]);
+    double liveRatioDelta =
+      function[gcLoadUnder][liveRatioAbove] - function[gcLoadUnder][liveRatioUnder];
+    factor += (liveRatioFraction * liveRatioDelta);
+    double gcLoadFraction =
+      (gcLoad - function[gcLoadUnder][0]) /
+      (function[gcLoadAbove][0] - function[gcLoadUnder][0]);
+    double gcLoadDelta =
+      function[gcLoadAbove][liveRatioUnder] - function[gcLoadUnder][liveRatioUnder];
+    factor += (gcLoadFraction * gcLoadDelta);
+
+    if (Options.verbose.getValue() > 2) {
+      Log.write("Heap adjustment factor is ");
+      Log.writeln(factor);
+    }
+    return factor;
+  }
+
+  /**
+   * Check that function satisfies the invariants
+   */
+  private static void sanityCheck() {
+    // Check live ratio
+    double[] liveRatio = function[0];
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(liveRatio[1] == 0);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(liveRatio[liveRatio.length-1] == 1);
+    for (int i = 2; i < liveRatio.length; i++) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(liveRatio[i-1] < liveRatio[i]);
+      for (int j = 1; j < function.length; j++) {
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(function[j][i] >= 1 || function[j][i] > liveRatio[i]);
+      }
+    }
+
+    // Check GC load
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(function[1][0] == 0);
+    int len = function.length;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(function[len-1][0] == 1);
+    for (int i = 2; i < len; i++) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(function[i-1][0] < function[i][0]);
+    }
+
+    // Check that we have a rectangular matrix
+    for (int i = 1; i < function.length; i++) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(function[i-1].length == function[i].length);
+    }
+  }
+
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Map.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Map.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Map.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Map.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,339 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.policy.Space;
+import org.mmtk.utility.GenericFreeList;
+import org.mmtk.utility.Log;
+import org.mmtk.vm.Lock;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.Inline;
+import org.vmmagic.pragma.Interruptible;
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Address;
+import org.vmmagic.unboxed.Extent;
+import org.vmmagic.unboxed.Word;
+
+/**
+ * This class manages the mapping of spaces to virtual memory ranges.<p>
+ *
+ */
+ at Uninterruptible
+public class Map {
+
+  /* set the map base address so that we have an unused (null) chunk at the bottome of the space for 64 bit */
+  private static final Address MAP_BASE_ADDRESS = Space.BITS_IN_ADDRESS == 32 ? Address.zero() : Space.HEAP_START.minus(Space.BYTES_IN_CHUNK);
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+  private static final int[] descriptorMap;
+  private static final int[] linkageMap;
+  private static final Space[] spaceMap;
+  private static final GenericFreeList regionMap;
+  public static final GenericFreeList globalPageMap;
+  private static int sharedDiscontigFLCount = 0;
+  private static final FreeListPageResource[] sharedFLMap;
+  private static int totalAvailableDiscontiguousChunks = 0;
+
+  private static final Lock lock = VM.newLock("Map lock");
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Class initializer. Create our two maps
+   */
+  static {
+    descriptorMap = new int[Space.MAX_CHUNKS];
+    linkageMap = new int[Space.MAX_CHUNKS];
+    spaceMap = new Space[Space.MAX_CHUNKS];
+    regionMap = new GenericFreeList(Space.MAX_CHUNKS);
+    globalPageMap = new GenericFreeList(1, 1, Space.MAX_SPACES);
+    sharedFLMap = new FreeListPageResource[Space.MAX_SPACES];
+    if (VM.VERIFY_ASSERTIONS)
+        VM.assertions._assert(Space.BITS_IN_ADDRESS == Space.LOG_ADDRESS_SPACE ||
+            Space.HEAP_END.diff(MAP_BASE_ADDRESS).toWord().rshl(Space.LOG_ADDRESS_SPACE).isZero());
+  }
+
+  /****************************************************************************
+   *
+   * Map accesses and insertion
+   */
+
+  /**
+   * Insert a space and its descriptor into the map, associating it
+   * with a particular address range.
+   *
+   * @param start The start address of the region to be associated
+   * with this space.
+   * @param extent The size of the region, in bytes
+   * @param descriptor The descriptor for this space
+   * @param space The space to be associated with this region
+   */
+  public static void insert(Address start, Extent extent, int descriptor,
+      Space space) {
+    Extent e = Extent.zero();
+    while (e.LT(extent)) {
+      int index = getChunkIndex(start.plus(e));
+      if (descriptorMap[index] != 0) {
+        Log.write("Conflicting virtual address request for space \"");
+        Log.write(space.getName()); Log.write("\" at ");
+        Log.writeln(start.plus(e));
+        Space.printVMMap();
+        VM.assertions.fail("exiting");
+      }
+      descriptorMap[index] = descriptor;
+      VM.barriers.setArrayNoBarrier(spaceMap, index, space);
+      e = e.plus(Space.BYTES_IN_CHUNK);
+    }
+  }
+
+  /**
+   * Allocate some number of contiguous chunks within a discontiguous region
+   *
+   * @param descriptor The descriptor for the space to which these chunks will be assigned
+   * @param space The space to which these chunks will be assigned
+   * @param chunks The number of chunks required
+   * @param previous The previous contgiuous set of chunks for this space (to create a linked list of contiguous regions for each space)
+   * @return The address of the assigned memory.  This always succeeds.  If the request fails we fail right here.
+   */
+  public static Address allocateContiguousChunks(int descriptor, Space space, int chunks, Address previous) {
+    lock.acquire();
+    int chunk = regionMap.alloc(chunks);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(chunk != 0);
+    if (chunk == -1) {
+      Log.write("Unable to allocate virtual address space for space \"");
+      Log.write(space.getName()); Log.write("\" for ");
+      Log.write(chunks); Log.write(" chunks (");
+      Log.write(chunks<<Space.LOG_BYTES_IN_CHUNK); Log.writeln(" bytes)");
+      Space.printVMMap();
+      VM.assertions.fail("exiting");
+    }
+    totalAvailableDiscontiguousChunks -= chunks;
+    Address rtn = addressForChunkIndex(chunk);
+    insert(rtn, Extent.fromIntZeroExtend(chunks<<Space.LOG_BYTES_IN_CHUNK), descriptor, space);
+    linkageMap[chunk] = previous.isZero() ? 0 : getChunkIndex(previous);
+    lock.release();
+    return rtn;
+  }
+
+  /**
+   * Return the address of the next contiguous region associated with some discontiguous space by following the linked list for that space.
+   *
+   * @param start The current region (return the next region in the list)
+   * @return Return the next contiguous region after start in the linked list of regions
+   */
+  public static Address getNextContiguousRegion(Address start) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(start.EQ(Space.chunkAlign(start, true)));
+    int chunk = getChunkIndex(start);
+    return (chunk == 0) ? Address.zero() : (linkageMap[chunk] == 0) ? Address.zero() : addressForChunkIndex(linkageMap[chunk]);
+  }
+
+  /**
+   * Return the size of a contiguous region in chunks.
+   *
+   * @param start The start address of the region whose size is being requested
+   * @return The size of the region in question
+   */
+  public static int getContiguousRegionChunks(Address start) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(start.EQ(Space.chunkAlign(start, true)));
+    int chunk = getChunkIndex(start);
+    return regionMap.size(chunk);
+  }
+
+  /**
+   * Return the size of a contiguous region in bytes.
+   *
+   * @param start The start address of the region whose size is being requested
+   * @return The size of the region in question
+   */
+  public static Extent getContiguousRegionSize(Address start) {
+    return Word.fromIntSignExtend(getContiguousRegionChunks(start)).lsh(Space.LOG_BYTES_IN_CHUNK).toExtent();
+  }
+
+  /**
+   * Free all chunks in a linked list of contiguous chunks.  This means starting
+   * with lastChunk and then walking the chain of contiguous regions, freeing each.
+   *
+   * @param lastChunk The last chunk in the linked list of chunks to be freed
+   */
+  public static void freeAllChunks(Address lastChunk) {
+    lock.acquire();
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(lastChunk.EQ(Space.chunkAlign(lastChunk, true)));
+    int chunk = getChunkIndex(lastChunk);
+    while (chunk != 0) {
+      int next = linkageMap[chunk];
+      freeContiguousChunks(chunk);
+      chunk = next;
+    }
+    lock.release();
+  }
+
+  /**
+   * Free some set of contiguous chunks, given the chunk address
+   *
+   * @param start The start address of the first chunk in the series
+   * @return The number of chunks which were contiguously allocated
+   */
+  public static int freeContiguousChunks(Address start) {
+    lock.acquire();
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(start.EQ(Space.chunkAlign(start, true)));
+    int rtn = freeContiguousChunks(getChunkIndex(start));
+    lock.release();
+    return rtn;
+  }
+
+  /**
+   * Free some set of contiguous chunks, given the chunk index
+   *
+   * @param chunk The chunk index of the region to be freed
+   * @return The number of chunks freed
+   */
+  private static int freeContiguousChunks(int chunk) {
+    int chunks = regionMap.free(chunk);
+    totalAvailableDiscontiguousChunks += chunks;
+    for (int offset = 0; offset < chunks; offset++) {
+      descriptorMap[chunk + offset] = 0;
+      VM.barriers.setArrayNoBarrier(spaceMap, chunk + offset, null);
+      linkageMap[chunk + offset] = 0;
+    }
+    return chunks;
+  }
+
+  /**
+   * Finalize the space map, establishing which virtual memory
+   * is nailed down, and then placing the rest into a map to
+   * be used by discontiguous spaces.
+   */
+  @Interruptible
+  public static void finalizeStaticSpaceMap() {
+    /* establish bounds of discontiguous space */
+    Address startAddress = Space.getDiscontigStart();
+    int firstChunk = getChunkIndex(startAddress);
+    int lastChunk = getChunkIndex(Space.getDiscontigEnd());
+    int unavailStartChunk = lastChunk + 1;
+    int trailingChunks = Space.MAX_CHUNKS - unavailStartChunk;
+    int pages = (1 + lastChunk - firstChunk) * Space.PAGES_IN_CHUNK;
+    globalPageMap.resizeFreeList(pages, pages);
+    for (int pr = 0; pr < sharedDiscontigFLCount; pr++)
+      sharedFLMap[pr].resizeFreeList(startAddress);
+
+    /* set up the region map free list */
+    int allocedChunk = regionMap.alloc(firstChunk);       // block out entire bottom of address range
+    for (int chunkIndex = firstChunk; chunkIndex <= lastChunk; chunkIndex++)
+      allocedChunk = regionMap.alloc(1);             // Tentatively allocate all usable chunks
+    allocedChunk = regionMap.alloc(trailingChunks);  // block out entire top of address range
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(allocedChunk == unavailStartChunk);
+
+    /* set up the global page map and place chunks on free list */
+    int firstPage = 0;
+    for (int chunkIndex = firstChunk; chunkIndex <= lastChunk; chunkIndex++) {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(spaceMap[chunkIndex] == null);
+      totalAvailableDiscontiguousChunks++;
+      regionMap.free(chunkIndex);  // put this chunk on the free list
+      globalPageMap.setUncoalescable(firstPage);
+      int allocedPages = globalPageMap.alloc(Space.PAGES_IN_CHUNK); // populate the global page map
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(allocedPages == firstPage);
+      firstPage += Space.PAGES_IN_CHUNK;
+    }
+  }
+
+  /**
+   * Return the ordinal number for some free list space wishing to share a discontiguous region.
+   * @return The ordinal number for a free list space wishing to share a discontiguous region
+   */
+  @Interruptible
+  public static int getDiscontigFreeListPROrdinal(FreeListPageResource pr) {
+    sharedFLMap[sharedDiscontigFLCount] = pr;
+    sharedDiscontigFLCount++;
+    return sharedDiscontigFLCount;
+  }
+
+  /**
+   * Return the total number of chunks available (unassigned) within the
+   * range of virtual memory apportioned to discontiguous spaces.
+   *
+   * @return The number of available chunks for use by discontiguous spaces.
+   */
+  public static int getAvailableDiscontiguousChunks() {
+    return totalAvailableDiscontiguousChunks;
+  }
+
+  /**
+   * Return the total number of clients contending for chunks.   This
+   * is useful when establishing conservative bounds on the number
+   * of remaining chunks.
+   *
+   * @return The total number of clients who may contend for chunks.
+   */
+  public static int getChunkConsumerCount() {
+    return sharedDiscontigFLCount;
+  }
+
+  /**
+   * Return the space in which this address resides.
+   *
+   * @param address The address in question
+   * @return The space in which the address resides
+   */
+  @Inline
+  public static Space getSpaceForAddress(Address address) {
+    int index = getChunkIndex(address);
+    return spaceMap[index];
+  }
+
+  /**
+   * Return the space descriptor for the space in which this object
+   * resides.
+   *
+   * @param object The object in question
+   * @return The space descriptor for the space in which the object
+   * resides
+   */
+  @Inline
+  public static int getDescriptorForAddress(Address object) {
+    int index = getChunkIndex(object);
+    return descriptorMap[index];
+  }
+
+  /**
+   * Hash an address to a chunk (this is simply done via bit shifting)
+   *
+   * @param address The address to be hashed
+   * @return The chunk number that this address hashes into
+   */
+  @Inline
+  private static int getChunkIndex(Address address) {
+    if (Space.BYTES_IN_ADDRESS == 8) {
+      if (address.LT(Space.HEAP_START) || address.GE(Space.HEAP_END))
+        return 0;
+      else
+        return address.diff(MAP_BASE_ADDRESS).toWord().rshl(Space.LOG_BYTES_IN_CHUNK).toInt();
+    } else
+      return address.toWord().rshl(Space.LOG_BYTES_IN_CHUNK).toInt();
+  }
+  @Inline
+  private static Address addressForChunkIndex(int chunk) {
+    if (Space.BYTES_IN_ADDRESS == 8) {
+      if (chunk == 0)
+        return Address.zero();
+      else
+        return MAP_BASE_ADDRESS.plus(Word.fromIntZeroExtend(chunk).lsh(Space.LOG_BYTES_IN_CHUNK).toExtent());
+    } else
+      return Word.fromIntZeroExtend(chunk).lsh(Space.LOG_BYTES_IN_CHUNK).toAddress();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Mmapper.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Mmapper.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Mmapper.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/Mmapper.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,237 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.utility.*;
+
+import org.mmtk.vm.Lock;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements mmapping and protection of virtual memory.
+ */
+ at Uninterruptible public final class Mmapper implements Constants {
+
+  /****************************************************************************
+   * Constants
+   */
+  public static final byte UNMAPPED = 0;
+  public static final byte MAPPED = 1;
+  public static final byte PROTECTED = 2; // mapped but not accessible
+  public static final int LOG_MMAP_CHUNK_BYTES = 20;
+  public static final int MMAP_CHUNK_BYTES = 1 << LOG_MMAP_CHUNK_BYTES;   // the granularity VMResource operates at
+  //TODO: 64-bit: this is not OK: value does not fit in int, but should, we do not want to create such big array
+  private static final int MMAP_CHUNK_MASK = MMAP_CHUNK_BYTES - 1;
+  private static final int MMAP_NUM_CHUNKS = 1 << (Constants.LOG_BYTES_IN_ADDRESS_SPACE - LOG_MMAP_CHUNK_BYTES);
+  public static final boolean verbose = false;
+
+  /****************************************************************************
+   * Class variables
+   */
+  public static final Lock lock = VM.newLock("Mmapper");
+  private static byte[] mapped;
+
+
+  /****************************************************************************
+   * Initialization
+   */
+
+  /**
+   * Class initializer.  This is executed <i>prior</i> to bootstrap
+   * (i.e. at "build" time).
+   */
+  static {
+    mapped = new byte[MMAP_NUM_CHUNKS];
+    for (int c = 0; c < MMAP_NUM_CHUNKS; c++) {
+      mapped[c] = UNMAPPED;
+    }
+  }
+
+  /****************************************************************************
+   * Generic mmap and protection functionality
+   */
+
+  /**
+   * Given an address array describing the regions of virtual memory to be used
+   * by MMTk, demand zero map all of them if they are not already mapped.
+   *
+   * @param spaceMap An address array containing a pairs of start and end
+   * addresses for each of the regions to be mappe3d
+   */
+  public static void eagerlyMmapAllSpaces(AddressArray spaceMap) {
+
+    /*for (int i = 0; i < spaceMap.length() / 2; i++) {
+      Address regionStart = spaceMap.get(i * 2);
+      Address regionEnd = spaceMap.get(i * 2 + 1);
+      Log.write(regionStart); Log.write(" "); Log.writeln(regionEnd);
+      if (regionEnd.EQ(Address.zero()) || regionStart.EQ(Address.fromIntSignExtend(-1)) ||regionEnd.EQ(Address.fromIntSignExtend(-1)))
+          break;
+      if (VM.VERIFY_ASSERTIONS) {
+        VM.assertions._assert(regionStart.EQ(chunkAlignDown(regionStart)));
+        VM.assertions._assert(regionEnd.EQ(chunkAlignDown(regionEnd)));
+      }
+      int pages = Conversions.bytesToPages(regionEnd.diff(regionStart));
+      ensureMapped(regionStart, pages);
+    }*/
+  }
+
+  /**
+   *  Mark a range of pages as having (already) been mapped.  This is useful
+   *  where the VM has performed the mapping of the pages itself.
+   *
+   * @param start The start of the range to be marked as mapped
+   * @param bytes The size of the range, in bytes.
+   */
+  public static void markAsMapped(Address start, int bytes) {
+    int startChunk = Conversions.addressToMmapChunksDown(start);
+    int endChunk = Conversions.addressToMmapChunksUp(start.plus(bytes));
+    for (int i = startChunk; i <= endChunk; i++)
+      mapped[i] = MAPPED;
+  }
+
+  /**
+   * Ensure that a range of pages is mmapped (or equivalent).  If the
+   * pages are not yet mapped, demand-zero map them. Note that mapping
+   * occurs at chunk granularity, not page granularity.<p>
+   *
+   * NOTE: There is a monotonicity assumption so that only updates require lock
+   * acquisition.
+   * TODO: Fix the above to support unmapping.
+   *
+   * @param start The start of the range to be mapped.
+   * @param pages The size of the range to be mapped, in pages
+   */
+  public static void ensureMapped(Address start, int pages) {
+    int startChunk = Conversions.addressToMmapChunksDown(start);
+    int endChunk = Conversions.addressToMmapChunksUp(start.plus(Conversions.pagesToBytes(pages)));
+    for (int chunk = startChunk; chunk < endChunk; chunk++) {
+      if (mapped[chunk] == MAPPED) continue;
+      Address mmapStart = Conversions.mmapChunksToAddress(chunk);
+      lock.acquire();
+//      Log.writeln(mmapStart);
+      // might have become MAPPED here
+      if (mapped[chunk] == UNMAPPED) {
+        int errno = VM.memory.dzmmap(mmapStart, MMAP_CHUNK_BYTES);
+        if (errno != 0) {
+          lock.release();
+          Log.write("ensureMapped failed with errno "); Log.write(errno);
+          Log.write(" on address "); Log.writeln(mmapStart);
+          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(false);
+        } else {
+          if (verbose) {
+            Log.write("mmap succeeded at chunk "); Log.write(chunk);  Log.write("  "); Log.write(mmapStart);
+            Log.write(" with len = "); Log.writeln(MMAP_CHUNK_BYTES);
+          }
+        }
+      }
+      if (mapped[chunk] == PROTECTED) {
+        if (!VM.memory.munprotect(mmapStart, MMAP_CHUNK_BYTES)) {
+          lock.release();
+          VM.assertions.fail("Mmapper.ensureMapped (unprotect) failed");
+        } else {
+          if (verbose) {
+            Log.write("munprotect succeeded at chunk "); Log.write(chunk);  Log.write("  "); Log.write(mmapStart);
+            Log.write(" with len = "); Log.writeln(MMAP_CHUNK_BYTES);
+          }
+        }
+      }
+      mapped[chunk] = MAPPED;
+      lock.release();
+    }
+
+  }
+
+  /**
+   * Memory protect a range of pages (using mprotect or equivalent).  Note
+   * that protection occurs at chunk granularity, not page granularity.
+   *
+   * @param start The start of the range to be protected.
+   * @param pages The size of the range to be protected, in pages
+   */
+  public static void protect(Address start, int pages) {
+    int startChunk = Conversions.addressToMmapChunksDown(start);
+    int chunks = Conversions.pagesToMmapChunksUp(pages);
+    int endChunk = startChunk + chunks;
+    lock.acquire();
+    for (int chunk = startChunk; chunk < endChunk; chunk++) {
+      if (mapped[chunk] == MAPPED) {
+        Address mmapStart = Conversions.mmapChunksToAddress(chunk);
+        if (!VM.memory.mprotect(mmapStart, MMAP_CHUNK_BYTES)) {
+          lock.release();
+          VM.assertions.fail("Mmapper.mprotect failed");
+        } else {
+          if (verbose) {
+            Log.write("mprotect succeeded at chunk "); Log.write(chunk);  Log.write("  "); Log.write(mmapStart);
+            Log.write(" with len = "); Log.writeln(MMAP_CHUNK_BYTES);
+          }
+        }
+        mapped[chunk] = PROTECTED;
+      } else {
+        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(mapped[chunk] == PROTECTED);
+      }
+    }
+    lock.release();
+  }
+
+  /****************************************************************************
+   * Utility functions
+   */
+
+  /**
+   * Return true if the given address has been mmapped
+   *
+   * @param addr The address in question.
+   * @return true if the given address has been mmapped
+   */
+  @Uninterruptible
+  public static boolean addressIsMapped(Address addr) {
+    int chunk = Conversions.addressToMmapChunksDown(addr);
+    return mapped[chunk] == MAPPED;
+  }
+
+  /**
+   * Return true if the given object has been mmapped
+   *
+   * @param object The object in question.
+   * @return true if the given object has been mmapped
+   */
+  @Uninterruptible
+  public static boolean objectIsMapped(ObjectReference object) {
+    return addressIsMapped(VM.objectModel.refToAddress(object));
+  }
+
+  /**
+   * Return a given address rounded up to an mmap chunk size
+   *
+   * @param addr The address to be aligned
+   * @return The given address rounded up to an mmap chunk size
+   */
+  @SuppressWarnings("unused")  // but might be useful someday
+  private static Address chunkAlignUp(Address addr) {
+    return chunkAlignDown(addr.plus(MMAP_CHUNK_MASK));
+  }
+
+  /**
+   * Return a given address rounded down to an mmap chunk size
+   *
+   * @param addr The address to be aligned
+   * @return The given address rounded down to an mmap chunk size
+   */
+  private static Address chunkAlignDown(Address addr) {
+    return addr.toWord().and(Word.fromIntSignExtend(MMAP_CHUNK_MASK).not()).toAddress();
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/MonotonePageResource.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/MonotonePageResource.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/MonotonePageResource.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/MonotonePageResource.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,307 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.utility.alloc.EmbeddedMetaData;
+import org.mmtk.utility.options.Options;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Conversions;
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class manages the allocation of pages for a space.  When a
+ * page is requested by the space both a page budget and the use of
+ * virtual address space are checked.  If the request for space can't
+ * be satisfied (for either reason) a GC may be triggered.<p>
+ */
+ at Uninterruptible
+public final class MonotonePageResource extends PageResource
+  implements Constants {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private Address cursor;
+  private Address sentinel;
+  private final int metaDataPagesPerRegion;
+  private Address currentChunk = Address.zero();
+
+  /**
+   * Constructor
+   *
+   * Contiguous monotone resource. The address range is pre-defined at
+   * initialization time and is immutable.
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   * @param start The start of the address range allocated to this resource
+   * @param bytes The size of the address rage allocated to this resource
+   * @param metaDataPagesPerRegion The number of pages of meta data
+   * that are embedded in each region.
+   */
+  public MonotonePageResource(int pageBudget, Space space, Address start,
+      Extent bytes, int metaDataPagesPerRegion) {
+    super(pageBudget, space, start);
+    this.cursor = start;
+    this.sentinel = start.plus(bytes);
+    this.metaDataPagesPerRegion = metaDataPagesPerRegion;
+  }
+
+  /**
+   * Constructor
+   *
+   * Discontiguous monotone resource. The address range is <i>not</i>
+   * pre-defined at initialization time and is dynamically defined to
+   * be some set of pages, according to demand and availability.
+   *
+   * CURRENTLY UNIMPLEMENTED
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   * @param metaDataPagesPerRegion The number of pages of meta data
+   * that are embedded in each region.
+   */
+  public MonotonePageResource(int pageBudget, Space space, int metaDataPagesPerRegion) {
+    super(pageBudget, space);
+    /* unimplemented */
+    this.start = Address.zero();
+    this.cursor = Address.zero();
+    this.sentinel = Address.zero();
+    this.metaDataPagesPerRegion = metaDataPagesPerRegion;
+  }
+
+  /**
+   * Return the number of available physical pages for this resource.
+   * This includes all pages currently unused by this resource's page
+   * cursor. If the resource is using discontiguous space it also includes
+   * currently unassigned discontiguous space.<p>
+   *
+   * Note: This just considers physical pages (ie virtual memory pages
+   * allocated for use by this resource). This calculation is orthogonal
+   * to and does not consider any restrictions on the number of pages
+   * this resource may actually use at any time (ie the number of
+   * committed and reserved pages).<p>
+   *
+   * Note: The calculation is made on the assumption that all space that
+   * could be assigned to this resource would be assigned to this resource
+   * (ie the unused discontiguous space could just as likely be assigned
+   * to another competing resource).
+   *
+   * @return The number of available physical pages for this resource.
+   */
+  @Override
+  public int getAvailablePhysicalPages() {
+    int rtn = Conversions.bytesToPages(sentinel.diff(cursor));
+    if (!contiguous)
+      rtn += Map.getAvailableDiscontiguousChunks()*Space.PAGES_IN_CHUNK;
+    return rtn;
+  }
+
+  /**
+   * Allocate <code>pages</code> pages from this resource.  Simply
+   * bump the cursor, and fail if we hit the sentinel.<p>
+   *
+   * If the request can be satisfied, then ensure the pages are
+   * mmpapped and zeroed before returning the address of the start of
+   * the region.  If the request cannot be satisfied, return zero.
+   *
+   * @param requestPages The number of pages to be allocated.
+   * @return The start of the first page if successful, zero on
+   * failure.
+   */
+  @Inline
+  protected Address allocPages(int requestPages) {
+    int pages = requestPages;
+    boolean newChunk = false;
+    lock();
+    Address rtn = cursor;
+    if (Space.chunkAlign(rtn, true).NE(currentChunk)) {
+      newChunk = true;
+      currentChunk = Space.chunkAlign(rtn, true);
+    }
+
+    if (metaDataPagesPerRegion != 0) {
+      /* adjust allocation for metadata */
+      Address regionStart = getRegionStart(cursor.plus(Conversions.pagesToBytes(pages)));
+      Offset regionDelta = regionStart.diff(cursor);
+      if (regionDelta.sGE(Offset.zero())) {
+        /* start new region, so adjust pages and return address accordingly */
+        pages += Conversions.bytesToPages(regionDelta) + metaDataPagesPerRegion;
+        rtn = regionStart.plus(Conversions.pagesToBytes(metaDataPagesPerRegion));
+      }
+    }
+    Extent bytes = Conversions.pagesToBytes(pages);
+    Address tmp = cursor.plus(bytes);
+
+    if (!contiguous && tmp.GT(sentinel)) {
+      /* we're out of virtual memory within our discontiguous region, so ask for more */
+      int requiredChunks = Space.requiredChunks(pages);
+      start = space.growDiscontiguousSpace(requiredChunks);
+      cursor = start;
+      sentinel = cursor.plus(start.isZero() ? 0 : requiredChunks<<Space.LOG_BYTES_IN_CHUNK);
+      rtn = cursor;
+      tmp = cursor.plus(bytes);
+      newChunk = true;
+    }
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(rtn.GE(cursor) && rtn.LT(cursor.plus(bytes)));
+    if (tmp.GT(sentinel)) {
+      unlock();
+      return Address.zero();
+    } else {
+      Address old = cursor;
+      cursor = tmp;
+      commitPages(requestPages, pages);
+      space.growSpace(old, bytes, newChunk);
+      unlock();
+      Mmapper.ensureMapped(old, pages);
+      VM.memory.zero(old, bytes);
+      VM.events.tracePageAcquired(space, rtn, pages);
+      return rtn;
+    }
+  }
+
+  /**
+   * Adjust a page request to include metadata requirements, if any.<p>
+   *
+   * In this case we simply report the expected page cost. We can't use
+   * worst case here because we would exhaust our budget every time.
+   *
+   * @param pages The size of the pending allocation in pages
+   * @return The number of required pages, inclusive of any metadata
+   */
+  public int adjustForMetaData(int pages) {
+    return (metaDataPagesPerRegion * pages) / EmbeddedMetaData.PAGES_IN_REGION;
+   }
+
+  /**
+   * Adjust a page request to include metadata requirements, if any.<p>
+   *
+   * Note that there could be a race here, with multiple threads each
+   * adjusting their request on account of the same single metadata
+   * region.  This should not be harmful, as the failing requests will
+   * just retry, and if multiple requests succeed, only one of them
+   * will actually have the metadata accounted against it, the others
+   * will simply have more space than they originally requested.
+   *
+   * @param pages The size of the pending allocation in pages
+   * @param begin The start address of the region assigned to this pending
+   * request
+   * @return The number of required pages, inclusive of any metadata
+   */
+  public int adjustForMetaData(int pages, Address begin) {
+    if (getRegionStart(begin).plus(metaDataPagesPerRegion<<LOG_BYTES_IN_PAGE).EQ(begin))
+      pages += metaDataPagesPerRegion;
+    return pages;
+   }
+
+  private static Address getRegionStart(Address addr) {
+    return addr.toWord().and(Word.fromIntSignExtend(EmbeddedMetaData.BYTES_IN_REGION - 1).not()).toAddress();
+  }
+
+  /**
+   * Reset this page resource, freeing all pages and resetting
+   * reserved and committed pages appropriately.
+   */
+  @Inline
+  public void reset() {
+    lock();
+    reserved = 0;
+    committed = 0;
+    releasePages();
+    unlock();
+  }
+
+  /**
+   * Notify that several pages are no longer in use.
+   *
+   * @param pages The number of pages
+   */
+  public void unusePages(int pages) {
+    lock();
+    reserved -= pages;
+    committed -= pages;
+    unlock();
+  }
+
+  /**
+   * Notify that previously unused pages are in use again.
+   *
+   * @param pages The number of pages
+   */
+  public void reusePages(int pages) {
+    lock();
+    reserved += pages;
+    committed += pages;
+    unlock();
+  }
+
+  /**
+   * Release all pages associated with this page resource, optionally
+   * zeroing on release and optionally memory protecting on release.
+   */
+  @Inline
+  private void releasePages() {
+    Address first = start;
+    do {
+      Extent bytes = cursor.diff(start).toWord().toExtent();
+      releasePages(start, bytes);
+      cursor = start;
+    } while (!contiguous && moveToNextChunk());
+    if (!contiguous) {
+      sentinel = Address.zero();
+      Map.freeAllChunks(first);
+    }
+  }
+
+  /**
+   * Adjust the start and cursor fields to point to the next chunk
+   * in the linked list of chunks tied down by this page resource.
+   *
+   * @return True if we moved to the next chunk; false if we hit the
+   * end of the linked list.
+   */
+  private boolean moveToNextChunk() {
+    start = Map.getNextContiguousRegion(start);
+    if (start.isZero())
+      return false;
+    else {
+      cursor = start.plus(Map.getContiguousRegionSize(start));
+      return true;
+    }
+  }
+
+  /**
+   * Release a range of pages associated with this page resource, optionally
+   * zeroing on release and optionally memory protecting on release.
+   */
+  @Inline
+  private void releasePages(Address first, Extent bytes) {
+    int pages = Conversions.bytesToPages(bytes);
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(bytes.EQ(Conversions.pagesToBytes(pages)));
+    if (ZERO_ON_RELEASE)
+      VM.memory.zero(first, bytes);
+    if (Options.protectOnRelease.getValue())
+      Mmapper.protect(first, pages);
+    VM.events.tracePageReleased(space, first, pages);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/PageResource.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/PageResource.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/PageResource.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/PageResource.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,320 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Constants;
+import org.mmtk.utility.options.ProtectOnRelease;
+import org.mmtk.utility.options.Options;
+
+import org.mmtk.vm.Lock;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class manages the allocation of pages for a space.  When a
+ * page is requested by the space both a page budget and the use of
+ * virtual address space are checked.  If the request for space can't
+ * be satisfied (for either reason) a GC may be triggered.<p>
+ *
+ * This class is abstract, and is subclassed with monotone and
+ * freelist variants, which reflect monotonic and ad hoc space usage
+ * respectively.  Monotonic use is easier to manage, but is obviously
+ * more restrictive (useful for copying collectors which allocate
+ * monotonically before freeing the entire space and starting over).
+ */
+ at Uninterruptible
+public abstract class PageResource implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+  protected static final boolean ZERO_ON_RELEASE = false; // debugging
+
+  private static final Lock classLock;
+  private static long cumulativeCommitted = 0;
+
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  // page budgeting
+  protected int reserved;
+  protected int committed;
+  protected int required;
+  private final int pageBudget;
+
+  protected final boolean contiguous;
+  protected final Space space;
+  protected Address start; // only for contiguous
+
+  // locking
+  private final Lock gcLock; // used during GC
+  private final Lock mutatorLock; // used by mutators
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+  static {
+    classLock = VM.newLock("PageResource");
+    Options.protectOnRelease = new ProtectOnRelease();
+  }
+
+  /**
+   * Constructor
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   */
+  private PageResource(int pageBudget, Space space, boolean contiguous) {
+    this.pageBudget = pageBudget;
+    this.contiguous = contiguous;
+    this.space = space;
+    gcLock = VM.newLock(space.getName() + ".gcLock");
+    mutatorLock = VM.newLock(space.getName() + ".mutatorLock");
+  }
+
+  /**
+   * Constructor for discontiguous spaces
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   */
+  PageResource(int pageBudget, Space space) {
+    this(pageBudget, space, false);
+  }
+
+  /**
+   * Constructor for contiguous spaces
+   *
+   * @param pageBudget The budget of pages available to this memory
+   * manager before it must poll the collector.
+   * @param space The space to which this resource is attached
+   */
+  PageResource(int pageBudget, Space space, Address start) {
+    this(pageBudget, space, true);
+    this.start = start;
+  }
+
+  /**
+   * Return the number of available physical pages for this resource.
+   *
+   * Note: This just considers physical pages (ie virtual memory pages
+   * allocated for use by this resource). This calculation is orthogonal
+   * to and does not consider any restrictions on the number of pages
+   * this resource may actually use at any time (ie the number of
+   * committed and reserved pages).<p>
+   *
+   * Note: The calculation is made on the assumption that all space that
+   * could be assigned to this resource would be assigned to this resource
+   * (ie the unused discontiguous space could just as likely be assigned
+   * to another competing resource).
+   *
+   * @return The number of available physical pages for this resource.
+   */
+   public abstract int getAvailablePhysicalPages();
+
+  /**
+   * Reserve pages.<p>
+   *
+   * The role of reserving pages is that it allows the request to be
+   * noted as pending (the difference between committed and reserved
+   * indicates pending requests).  If the request would exceed the
+   * page budget then the caller must poll in case a GC is necessary.
+   *
+   * @param pages The number of pages requested
+   * @return True if the page budget could satisfy the request.
+   */
+  @Inline
+  public final boolean reservePages(int pages) {
+    lock();
+    required += adjustForMetaData(pages);
+    reserved = committed + required;
+    boolean satisfied = reserved <= pageBudget;
+    unlock();
+    return satisfied;
+  }
+
+  /**
+   * Remove a request to the space.
+   *
+   * @param pages The number of pages in the request.
+   */
+  @Inline
+  public final void clearRequest(int pages) {
+    lock();
+    required -= adjustForMetaData(pages);
+    unlock();
+  }
+
+  /**
+   * Reserve pages unconditionally.<p>
+   *
+   * An example of where this is useful is in cases where it is
+   * desirable to put some space aside as head-room.  By
+   * unconditionally reserving the pages, the pages are counted
+   * against the collectors budget.  When the space is actually
+   * needed, the pages can be unconditionally released, freeing
+   * the pages for other purposes.
+   *
+   * @param pages The number of pages to be unconditionally
+   * reserved.
+   */
+  public final void unconditionallyReservePages(int pages) {
+    lock();
+    committed += pages;
+    reserved += pages;
+    unlock();
+  }
+
+  /**
+   * Release pages unconditionally.<p>
+   *
+   * This call allows pages to be unconditionally removed from
+   * the collectors page budget.
+   *
+   * @see #unconditionallyReservePages
+   * @param pages The number of pages to be unconditionally
+   * released.
+   */
+  public final void unconditionallyReleasePages(int pages) {
+    lock();
+    committed -= pages;
+    reserved -= pages;
+    unlock();
+  }
+
+  abstract Address allocPages(int pages);
+
+  /**
+   * Adjust a page request to include metadata requirements for a request
+   * of the given size. This must be a pure function, that is it does not
+   * depend on the state of the PageResource.
+   *
+   * @param pages The size of the pending allocation in pages
+   * @return The number of required pages, inclusive of any metadata
+   */
+  public abstract int adjustForMetaData(int pages);
+
+  /**
+   * Allocate pages in virtual memory, returning zero on failure.<p>
+   *
+   * If the request cannot be satisfied, zero is returned and it
+   * falls to the caller to trigger the GC.
+   *
+   * Call <code>allocPages</code> (subclass) to find the pages in
+   * virtual memory.  If successful then commit the pending page
+   * request and return the address of the first page.
+   *
+   * @param pages The number of pages requested
+   * @return The address of the first of <code>pages</code> pages, or
+   * zero on failure.
+   */
+  @Inline
+  public final Address getNewPages(int pages) {
+    return allocPages(pages);
+  }
+
+  /**
+   * Commit pages to the page budget.  This is called after
+   * successfully determining that the request can be satisfied by
+   * both the page budget and virtual memory.  This simply accounts
+   * for the descrepency between <code>committed</code> and
+   * <code>reserved</code> while the request was pending.
+   *
+   * This *MUST* be called by each PageResource during the
+   * allocPages, and the caller must hold the lock.
+   *
+   * @param requestedPages The number of pages from this request
+   * @param totalPages The number of pages
+   */
+  protected void commitPages(int requestedPages, int totalPages) {
+    int predictedPages = adjustForMetaData(requestedPages);
+    int delta = totalPages - predictedPages;
+    required -= predictedPages;
+    reserved += delta;
+    committed += totalPages;
+    if (!Plan.gcInProgress())
+      addToCommitted(totalPages); // only count mutator pages
+  }
+
+  /**
+   * Return the number of reserved pages
+   *
+   * @return The number of reserved pages.
+   */
+  public final int reservedPages() { return reserved; }
+
+  /**
+   * Return the number of committed pages
+   *
+   * @return The number of committed pages.
+   */
+  public final int committedPages() { return committed; }
+
+  /**
+   * Return the number of required pages
+   *
+   * @return The number of required pages.
+   */
+  public final int requiredPages() { return required; }
+
+  /**
+   * Return the cumulative number of committed pages
+   *
+   * @return The cumulative number of committed pages.
+   */
+  public static long cumulativeCommittedPages() { return cumulativeCommitted; }
+
+  /**
+   * Add to the total cumulative committed page count.
+   *
+   * @param pages The number of pages to be added.
+   */
+  private static void addToCommitted(int pages) {
+    classLock.acquire();
+    cumulativeCommitted += pages;
+    classLock.release();
+  }
+
+  /**
+   * Acquire the appropriate lock depending on whether the context is
+   * GC or mutator.
+   */
+  protected final void lock() {
+    if (Plan.gcInProgress())
+      gcLock.acquire();
+    else
+      mutatorLock.acquire();
+  }
+
+  /**
+   * Release the appropriate lock depending on whether the context is
+   * GC or mutator.
+   */
+  protected final void unlock() {
+    if (Plan.gcInProgress())
+      gcLock.release();
+    else
+      mutatorLock.release();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/SpaceDescriptor.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/SpaceDescriptor.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/SpaceDescriptor.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/SpaceDescriptor.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,166 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class manages the encoding and decoding of space descriptors.<p>
+ *
+ * Space descriptors are integers that encode a space's mapping into
+ * virtual memory.  For discontiguous spaces, they indicate
+ * discontiguity and mapping must be done by consulting the space map.
+ * For contiguous spaces, the space's address range is encoded into
+ * the integer (using a fixed point notation).<p>
+ *
+ * The purpose of this class is to allow <code>static final int</code>
+ * space descriptors to exist for each space, which can then be used
+ * in tests to determine whether an object is in a space.  A good
+ * compiler can perform this decoding at compile time and produce
+ * optimal code for the test.
+ */
+ at Uninterruptible public class SpaceDescriptor implements Constants {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  private static final int TYPE_BITS = 2;
+  private static final int TYPE_SHARED = 0;
+  private static final int TYPE_CONTIGUOUS = 1;
+  private static final int TYPE_CONTIGUOUS_HI = 3;
+  private static final int TYPE_MASK = (1 << TYPE_BITS) - 1;
+  private static final int SIZE_SHIFT = TYPE_BITS;
+  private static final int SIZE_BITS = 10;
+  private static final int SIZE_MASK = ((1 << SIZE_BITS) - 1) << SIZE_SHIFT;
+  private static final int EXPONENT_SHIFT = SIZE_SHIFT + SIZE_BITS;
+  private static final int EXPONENT_BITS = 5;
+  private static final int EXPONENT_MASK = ((1 << EXPONENT_BITS) - 1) << EXPONENT_SHIFT;
+  private static final int MANTISSA_SHIFT = EXPONENT_SHIFT + EXPONENT_BITS;
+  private static final int MANTISSA_BITS = 14;
+  private static final int BASE_EXPONENT = BITS_IN_INT - MANTISSA_BITS;
+
+  private static int discontiguousSpaceIndex = 0;
+  private static final int DISCONTIG_INDEX_INCREMENT = 1<<TYPE_BITS;
+
+  /****************************************************************************
+   *
+   * Descriptor creation
+   */
+
+  /**
+   * Create a descriptor for a <i>contiguous</i> space
+   *
+   * @param start The start address of the space
+   * @param end The end address of the space
+   * @return An integer descriptor encoding the region of virtual
+   * memory occupied by the space
+   */
+  public static int createDescriptor(Address start, Address end) {
+    int chunks = end.diff(start).toWord().rshl(Space.LOG_BYTES_IN_CHUNK).toInt();
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(!start.isZero() && chunks > 0 && chunks < (1 << SIZE_BITS));
+    boolean top = end.EQ(Space.HEAP_END);
+    Word tmp = start.toWord();
+    tmp = tmp.rshl(BASE_EXPONENT);
+    int exponent = 0;
+    while (!tmp.isZero() && tmp.and(Word.one()).isZero()) {
+      tmp = tmp.rshl(1);
+      exponent++;
+    }
+    int mantissa = tmp.toInt();
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(tmp.lsh(BASE_EXPONENT + exponent).EQ(start.toWord()));
+    return (mantissa<<MANTISSA_SHIFT) |
+           (exponent<<EXPONENT_SHIFT) |
+           (chunks << SIZE_SHIFT) |
+           ((top) ? TYPE_CONTIGUOUS_HI : TYPE_CONTIGUOUS);
+  }
+
+  /**
+   * Create a descriptor for a <i>dis-contiguous</i> (shared) space
+   *
+   * @return An integer descriptor reflecting the fact that this space
+   * is shared (and thus discontiguous and so must be established via
+   * maps).
+   */
+  public static int createDescriptor() {
+    discontiguousSpaceIndex += DISCONTIG_INDEX_INCREMENT;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((discontiguousSpaceIndex & TYPE_CONTIGUOUS) != TYPE_CONTIGUOUS);
+    return discontiguousSpaceIndex;
+  }
+
+  /****************************************************************************
+   *
+   * Descriptor interrogation
+   */
+
+  /**
+   * Return true if this descriptor describes a contiguous space
+   *
+   * @param descriptor
+   * @return True if this descriptor describes a contiguous space
+   */
+  @Inline
+  public static boolean isContiguous(int descriptor) {
+    return ((descriptor & TYPE_CONTIGUOUS) == TYPE_CONTIGUOUS);
+  }
+
+  /**
+   * Return true if this descriptor describes a contiguous space that
+   * is at the top of the virtual address space
+   *
+   * @param descriptor
+   * @return True if this descriptor describes a contiguous space that
+   * is at the top of the virtual address space
+   */
+  @Inline
+  public static boolean isContiguousHi(int descriptor) {
+    return ((descriptor & TYPE_MASK) == TYPE_CONTIGUOUS_HI);
+  }
+
+  /**
+   * Return the start of this region of memory encoded in this descriptor
+   *
+   * @param descriptor
+   * @return The start of this region of memory encoded in this descriptor
+   */
+  @Inline
+  public static Address getStart(int descriptor) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
+    Word mantissa = Word.fromIntSignExtend(descriptor >>> MANTISSA_SHIFT);
+    int exponent = (descriptor & EXPONENT_MASK) >>> EXPONENT_SHIFT;
+    return mantissa.lsh(BASE_EXPONENT + exponent).toAddress();
+  }
+
+  /**
+   * Return the size of the region of memory encoded in this
+   * descriptor, in chunks
+   *
+   * @param descriptor
+   * @return The size of the region of memory encoded in this
+   * descriptor, in chunks
+   */
+  @Inline
+  public static int getChunks(int descriptor) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
+    return (descriptor & SIZE_MASK) >>> SIZE_SHIFT;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/VMRequest.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/VMRequest.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/VMRequest.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/heap/VMRequest.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,126 @@
+/*
+ *  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.mmtk.utility.heap;
+
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class manages the encoding and decoding of virtual memory requests.
+ *
+ * By encapsulating this aspect of the construction of a space, we greatly
+ * reduce the number of constructors required.
+ */
+public final class VMRequest implements Constants {
+
+  public static final int REQUEST_DISCONTIGUOUS = 0;
+  public static final int REQUEST_FIXED = 1;
+  public static final int REQUEST_EXTENT = 3;
+  public static final int REQUEST_FRACTION = 4;
+
+  public final int type;
+  public final Address start;
+  public final Extent extent;
+  public final float frac;
+  public final boolean top;
+
+  private VMRequest(int type, Address start, Extent bytes, float frac, boolean top) {
+    this.type = type;
+    this.start = start;
+    this.extent = bytes;
+    this.frac = frac;
+    this.top = top;
+  }
+
+  /**
+   * Is this a discontiguous space request?
+   * @return true if this is a discontiguous space request, false otherwise
+   */
+  public boolean isDiscontiguous() {
+    return type == REQUEST_DISCONTIGUOUS;
+  }
+
+  /**
+   * A request for a discontiguous region of memory
+   *
+   * @return The request object
+   */
+  public static VMRequest create() {
+    return new VMRequest(REQUEST_DISCONTIGUOUS, Address.zero(), Extent.zero(), 0f, false);
+  }
+
+  /**
+   * A request for an explicit region of memory
+   *
+   * @param start The start of the region
+   * @param extent The size of the region
+   * @return The request object
+   */
+  public static VMRequest create(Address start, Extent extent) {
+    return new VMRequest(REQUEST_FIXED, start, extent, 0f, false);
+  }
+
+  /**
+   * A request for a number of megabytes of memory
+   *
+   * @param mb The number of megabytes
+   * @return The request object
+   */
+  public static VMRequest create(int mb) {
+    return create(mb, false);
+  }
+
+  /**
+   * A request for a fraction of available memory
+   *
+   * @param frac The fraction
+   * @return The request object
+   */
+  public static VMRequest create(float frac) {
+    return create(frac, false);
+  }
+
+  /**
+   * A request for a number of megabytes of memory, optionally requesting the highest available.
+   *
+   * @param mb The number of megabytes
+   * @param top True to request high memory
+   * @return The request object
+   */
+  public static VMRequest create(int mb, boolean top) {
+    return new VMRequest(REQUEST_EXTENT, Address.zero(), Word.fromIntSignExtend(mb).lsh(LOG_BYTES_IN_MBYTE).toExtent(), 0f, top);
+  }
+
+  /**
+   * A request for a fraction of available memory, optionally requesting the highest available.
+   *
+   * @param frac The fraction
+   * @param top True to request high memory
+   * @return The request object
+   */
+  public static VMRequest create(float frac, boolean top) {
+    return new VMRequest(REQUEST_FRACTION, Address.zero(), Extent.zero(), frac, top);
+  }
+
+  /**
+   * A request for a number of bytes of memory, optionally requesting the highest available.
+   *
+   * @param extent The number of bytes
+   * @param top True to request high memory
+   * @return The request object
+   */
+  public static VMRequest create(Extent extent, boolean top) {
+    return new VMRequest(REQUEST_EXTENT, Address.zero(), extent, 0f, top);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/BoundedNursery.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/BoundedNursery.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/BoundedNursery.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/BoundedNursery.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,37 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.mmtk.plan.Plan;
+
+/**
+ * Provide an upper bound on nursery size. This option is not intended to
+ * be created directly, but via NurserySize.
+ */
+public final class BoundedNursery extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public BoundedNursery() {
+    super(Options.set, "Bounded Nursery",
+        "Bound the maximum size of the nursery to this value",
+        Plan.DEFAULT_MAX_NURSERY);
+  }
+
+  /**
+   * Nursery can not be empty.
+   */
+  protected void validate() {
+    failIf(value <= 0, "Can not have an empty nursery");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ConcurrentTrigger.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ConcurrentTrigger.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ConcurrentTrigger.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ConcurrentTrigger.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,35 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Concurrent trigger percentage
+ */
+public class ConcurrentTrigger extends org.vmutil.options.IntOption {
+  /**
+   * Create the option.
+   */
+  public ConcurrentTrigger() {
+    super(Options.set, "Concurrent Trigger",
+          "Concurrent trigger percentage",
+          50);
+  }
+
+  /**
+   * Only accept values between 1 and 100 (inclusive)
+   */
+  protected void validate() {
+    failIf(this.value <= 0, "Trigger must be between 1 and 100");
+    failIf(this.value > 100, "Trigger must be between 1 and 100");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleFilterThreshold.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleFilterThreshold.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleFilterThreshold.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleFilterThreshold.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Trigger cycle buffer filtering if the space available falls below this threshold.
+ */
+public final class CycleFilterThreshold extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public CycleFilterThreshold() {
+    super(Options.set, "Cycle Filter Threshold",
+        "Trigger cycle buffer filtering if the space available falls below this threshold",
+        512);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleMetaDataLimit.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleMetaDataLimit.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleMetaDataLimit.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleMetaDataLimit.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Trigger cycle detection if the meta data volume grows to this limit.
+ */
+public final class CycleMetaDataLimit extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public CycleMetaDataLimit() {
+    super(Options.set, "Cycle Meta Data Limit",
+        "Trigger cycle detection if the meta data volume grows to this limit",
+        4096);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleTriggerThreshold.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleTriggerThreshold.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleTriggerThreshold.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/CycleTriggerThreshold.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Trigger cycle detection if the space available falls below this threshold.
+ */
+public final class CycleTriggerThreshold extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public CycleTriggerThreshold() {
+    super(Options.set, "Cycle Trigger Threshold",
+        "Trigger cycle detection if the space available falls below this threshold",
+        512);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DebugAddress.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DebugAddress.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DebugAddress.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DebugAddress.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,29 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.vmmagic.unboxed.Address;
+
+/**
+ * Allow an address to be specified on the command line for use in debugging.
+ */
+public final class DebugAddress extends org.vmutil.options.AddressOption {
+  /**
+   * Create the option
+   */
+  public DebugAddress() {
+    super(Options.set, "Debug Address",
+          "Specify an address at runtime for use in debugging",
+        Address.zero());
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroom.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroom.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroom.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroom.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,26 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_DEFRAG_FREE_HEADROOM;
+
+public class DefragFreeHeadroom extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public DefragFreeHeadroom() {
+    super(Options.set, "Defrag Free Headroom",
+          "Allow the defragmenter this amount of free headroom during defrag. For analysis purposes only!",
+          DEFAULT_DEFRAG_FREE_HEADROOM);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroomFraction.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroomFraction.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroomFraction.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragFreeHeadroomFraction.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,33 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_DEFRAG_FREE_HEADROOM_FRACTION;
+
+public class DefragFreeHeadroomFraction extends org.vmutil.options.FloatOption {
+  /**
+   * Create the option.
+   */
+  public DefragFreeHeadroomFraction() {
+    super(Options.set, "Defrag Free Headroom Fraction",
+          "Allow the defragmenter this fraction of the heap size as free headroom during defrag. For analysis purposes only!",
+          DEFAULT_DEFRAG_FREE_HEADROOM_FRACTION);
+  }
+
+  /**
+   * Ensure the value is valid.
+   */
+  protected void validate() {
+    failIf((this.value < 0 || this.value > 1.0), "Ratio must be a float between 0 and 1");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroom.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroom.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroom.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroom.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_DEFRAG_HEADROOM;
+
+/**
+ */
+public class DefragHeadroom extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public DefragHeadroom() {
+    super(Options.set, "Defrag Headroom",
+          "Allow the defragmenter this amount of headroom during defrag.",
+          DEFAULT_DEFRAG_HEADROOM);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroomFraction.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroomFraction.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroomFraction.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragHeadroomFraction.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,33 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_DEFRAG_HEADROOM_FRACTION;
+
+public class DefragHeadroomFraction extends org.vmutil.options.FloatOption {
+  /**
+   * Create the option.
+   */
+  public DefragHeadroomFraction() {
+    super(Options.set, "Defrag Headroom Fraction",
+          "Allow the defrag this fraction of the heap as headroom during defrag.",
+          DEFAULT_DEFRAG_HEADROOM_FRACTION);
+  }
+
+  /**
+   * Ensure the value is valid.
+   */
+  protected void validate() {
+    failIf((this.value < 0 || this.value > 1.0), "Ratio must be a float between 0 and 1");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragLineReuseRatio.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragLineReuseRatio.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragLineReuseRatio.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragLineReuseRatio.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,33 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_DEFRAG_LINE_REUSE_RATIO;
+
+public class DefragLineReuseRatio extends org.vmutil.options.FloatOption {
+  /**
+   * Create the option.
+   */
+  public DefragLineReuseRatio() {
+    super(Options.set, "Defrag Line Reuse Ratio",
+          "Blocks with this fraction marked may be reused for defrag allocation",
+          DEFAULT_DEFRAG_LINE_REUSE_RATIO);
+  }
+
+  /**
+   * Ensure the value is valid.
+   */
+  protected void validate() {
+    failIf((this.value <= 0 || this.value > 1.0), "Ratio must be a float between 0 and 1");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragSimpleSpillThreshold.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragSimpleSpillThreshold.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragSimpleSpillThreshold.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragSimpleSpillThreshold.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,33 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_SIMPLE_SPILL_THRESHOLD;
+
+public class DefragSimpleSpillThreshold extends org.vmutil.options.FloatOption {
+  /**
+   * Create the option.
+   */
+  public DefragSimpleSpillThreshold() {
+    super(Options.set, "Defrag Simple Spill Threshold",
+          "Blocks with this fraction spilled will be defrag sources",
+          DEFAULT_SIMPLE_SPILL_THRESHOLD);
+  }
+
+  /**
+   * Ensure the value is valid.
+   */
+  protected void validate() {
+    failIf((this.value <= 0 || this.value > 1.0), "Ratio must be a float between 0 and 1");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragStress.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragStress.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragStress.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DefragStress.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we force degfrag every time the immix space is collected?
+ */
+public final class DefragStress extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public DefragStress() {
+    super(Options.set, "Defrag Stress",
+        "Should we force degfrag every time the immix space is collected?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DummyEnum.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DummyEnum.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DummyEnum.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/DummyEnum.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,33 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * A sample enumeration for testing.
+ */
+public final class DummyEnum extends org.vmutil.options.EnumOption {
+
+  // enumeration values.
+  public final int FOO = 0;
+  public final int BAR = 1;
+
+  /**
+   * Create the option.
+   */
+  public DummyEnum() {
+    super(Options.set, "Dummy Enum",
+          "This is a sample enumeration to test the options system",
+          new String[] {"foo", "bar"},
+          "foo");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerCompleteSweep.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerCompleteSweep.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerCompleteSweep.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerCompleteSweep.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we eagerly finish sweeping at the start of a collection
+ */
+public final class EagerCompleteSweep extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public EagerCompleteSweep() {
+    super(Options.set, "Eager Complete Sweep",
+          "Should we eagerly finish sweeping at the start of a collection",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerMmapSpaces.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerMmapSpaces.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerMmapSpaces.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EagerMmapSpaces.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should spaces be eagerly demand zero mmapped?
+ */
+public final class EagerMmapSpaces extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public EagerMmapSpaces() {
+    super(Options.set, "Eager Mmap Spaces",
+          "If true, all spaces are eagerly demand zero mmapped at boot time",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EchoOptions.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EchoOptions.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EchoOptions.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/EchoOptions.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Echo when options are set?
+ */
+public final class EchoOptions extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public EchoOptions() {
+    super(Options.set, "Echo Options",
+          "Echo when options are set?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FixedNursery.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FixedNursery.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FixedNursery.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FixedNursery.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,44 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.mmtk.plan.Plan;
+
+/**
+ * Provide an lower and upper bound on nursery size.
+ *
+ * This option is not intended to be created directly, but via NurserySize.
+ */
+public final class FixedNursery extends org.vmutil.options.PagesOption {
+  // values
+  BoundedNursery boundedNursery;
+
+  /**
+   * Create the option
+   */
+  public FixedNursery(BoundedNursery boundedNursery) {
+    super(Options.set, "Fixed Nursery",
+        "Fix the minimum and maximum size of the nursery to this value",
+        Plan.DEFAULT_MIN_NURSERY);
+    this.boundedNursery = boundedNursery;
+  }
+
+  /**
+   * Nursery can not be empty.
+   */
+  protected void validate() {
+    failIf(value <= 0, "Can not have an empty nursery");
+    // Update upper bound.
+    boundedNursery.setBytes(this.getBytes());
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FragmentationStats.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FragmentationStats.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FragmentationStats.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FragmentationStats.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Option to print fragmentation information for the free list.
+ */
+public final class FragmentationStats extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public FragmentationStats() {
+    super(Options.set, "Fragmentation Stats",
+        "Should we print fragmentation statistics for the free list allocator?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FullHeapSystemGC.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FullHeapSystemGC.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FullHeapSystemGC.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/FullHeapSystemGC.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should a major GC be performed when a system GC is triggered?
+ */
+public final class FullHeapSystemGC extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public FullHeapSystemGC() {
+    super(Options.set, "Full Heap System GC",
+          "Should a major GC be performed when a system GC is triggered?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCTimeCap.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCTimeCap.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCTimeCap.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCTimeCap.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Try to limit reference counting collections to this time cap.
+ */
+public final class GCTimeCap extends org.vmutil.options.MicrosecondsOption {
+  /**
+   * Create the option.
+   */
+  public GCTimeCap() {
+    super(Options.set, "GC Time Cap",
+          "Try to limit reference counting collections to this time cap",
+          1000000);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyPort.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyPort.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyPort.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyPort.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,34 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Port number for GCSpy server to connect with visualiser.
+ */
+public final class GCspyPort extends org.vmutil.options.IntOption {
+  /**
+   * Create the option.
+   */
+  public GCspyPort() {
+    super(Options.set, "GCSpy Port",
+          "Port number for GCSpy server to connect with visualiser",
+          0);
+  }
+
+  /**
+   * Ensure the port is valid.
+   */
+  protected void validate() {
+    failIf(this.value <= 0, "Unreasonable GCSpy port value");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyTileSize.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyTileSize.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyTileSize.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyTileSize.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,34 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * GCspy Tile Size.
+ */
+public final class GCspyTileSize extends org.vmutil.options.IntOption {
+  /**
+   * Create the option.
+   */
+  public GCspyTileSize() {
+    super(Options.set, "GCspy Tile Size",
+          "GCspy Tile Size",
+          131072);
+  }
+
+  /**
+   * Ensure the tile size is positive
+   */
+  protected void validate() {
+    failIf(this.value <= 0, "Unreasonable gcspy tilesize");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyWait.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyWait.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyWait.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GCspyWait.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should the VM wait for the visualiser to connect?
+ */
+public final class GCspyWait extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option
+   */
+  public GCspyWait() {
+    super(Options.set, "GCSpy Wait",
+          "Should the VM wait for the visualiser to connect?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GenCycleDetection.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GenCycleDetection.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GenCycleDetection.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/GenCycleDetection.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we use a generational approach to cycle detection?
+ */
+public final class GenCycleDetection extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public GenCycleDetection() {
+    super(Options.set, "Gen Cycle Detection",
+          "Should we use a generational approach to cycle detection?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/HarnessAll.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/HarnessAll.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/HarnessAll.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/HarnessAll.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we wrap the entire execution with a harnessBegin/harnessEnd?
+ */
+public final class HarnessAll extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public HarnessAll() {
+    super(Options.set, "Harness All",
+        "Should we wrap the entire execution inside calls to harnessBegin and harnessEnd?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/IgnoreSystemGC.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/IgnoreSystemGC.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/IgnoreSystemGC.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/IgnoreSystemGC.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we ignore calls to java.lang.System.gc?
+ */
+public final class IgnoreSystemGC extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public IgnoreSystemGC() {
+    super(Options.set, "Ignore System GC",
+          "Should we ignore calls to java.lang.System.gc?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/LineReuseRatio.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/LineReuseRatio.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/LineReuseRatio.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/LineReuseRatio.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,35 @@
+/*
+ *  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.mmtk.utility.options;
+
+import static org.mmtk.policy.immix.ImmixConstants.DEFAULT_LINE_REUSE_RATIO;
+
+/**
+ */
+public class LineReuseRatio extends org.vmutil.options.FloatOption {
+  /**
+   * Create the option.
+   */
+  public LineReuseRatio() {
+    super(Options.set, "Line Reuse Ratio",
+          "Blocks with this fraction marked may be reused for allocation",
+          DEFAULT_LINE_REUSE_RATIO);
+  }
+
+  /**
+   * Ensure the value is valid.
+   */
+  protected void validate() {
+    failIf((this.value <= 0 || this.value > 1.0), "Ratio must be a float between 0 and 1");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MarkSweepMarkBits.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MarkSweepMarkBits.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MarkSweepMarkBits.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MarkSweepMarkBits.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,37 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.mmtk.policy.MarkSweepSpace;
+
+/**
+ * Number of bits to use for the header cycle of mark sweep spaces.
+ */
+public final class MarkSweepMarkBits extends org.vmutil.options.IntOption {
+  /**
+   * Create the option.
+   */
+  public MarkSweepMarkBits() {
+    super(Options.set, "Mark Sweep Mark Bits",
+          "Number of bits to use for the header cycle of mark sweep spaces",
+          MarkSweepSpace.DEFAULT_MARKCOUNT_BITS);
+  }
+
+  /**
+   * Ensure the value is valid.
+   */
+  protected void validate() {
+    failIf(this.value <= 0, "Must provide at least one bit");
+    failIf(this.value > MarkSweepSpace.MAX_MARKCOUNT_BITS , "Only "+MarkSweepSpace.MAX_MARKCOUNT_BITS+" bits are reserved in MarkSweepSpace");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MetaDataLimit.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MetaDataLimit.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MetaDataLimit.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/MetaDataLimit.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Provide a bound on how much metadata is allowed before a GC is triggered.
+ */
+public final class MetaDataLimit extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option.
+   */
+  public MetaDataLimit() {
+    super(Options.set, "Meta Data Limit",
+          "Trigger a GC if the meta data volume grows to this limit",
+          4096);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoFinalizer.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoFinalizer.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoFinalizer.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoFinalizer.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should finalization be disabled?
+ */
+public final class NoFinalizer extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public NoFinalizer() {
+    super(Options.set, "No Finalizer",
+          "Should finalization be disabled?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoReferenceTypes.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoReferenceTypes.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoReferenceTypes.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NoReferenceTypes.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should reference type processing be disabled?
+ */
+public final class NoReferenceTypes extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public NoReferenceTypes() {
+    super(Options.set, "No Reference Types",
+          "Should reference type processing be disabled?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NurserySize.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NurserySize.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NurserySize.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/NurserySize.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,53 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * A composite option that provides a min/max interface to MMTk,
+ * and a fixed/bounded option interface to the VM/user.
+ */
+public final class NurserySize {
+  // values
+  private FixedNursery fixedNursery;
+  private BoundedNursery boundedNursery;
+
+  /**
+   * Create the options.
+   */
+  public NurserySize() {
+    boundedNursery = new BoundedNursery();
+    fixedNursery = new FixedNursery(boundedNursery);
+  }
+
+  /**
+   * Read the upper bound of the nursery size.
+   *
+   * @return maximum number of pages in the nursery.
+   */
+  @Uninterruptible
+  public int getMaxNursery() {
+    return boundedNursery.getPages();
+  }
+
+  /**
+   * Read the lower bound of the nursery size.
+   *
+   * @return minimum number of pages in the nursery.
+   */
+  @Uninterruptible
+  public int getMinNursery() {
+    return fixedNursery.getPages();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Options.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Options.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Options.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Options.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,67 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.vmutil.options.OptionSet;
+
+/**
+ * Repository for all option instances.
+ */
+public final class Options {
+  public static OptionSet set;
+
+  /* Other options */
+  public static BoundedNursery boundedNursery;
+  public static ConcurrentTrigger concurrentTrigger;
+  public static CycleFilterThreshold cycleFilterThreshold;
+  public static CycleMetaDataLimit cycleMetaDataLimit;
+  public static CycleTriggerThreshold cycleTriggerThreshold;
+  public static DebugAddress debugAddress;
+  public static DummyEnum dummyEnum;
+  public static DefragHeadroom defragHeadroom;
+  public static DefragHeadroomFraction defragHeadroomFraction;
+  public static DefragFreeHeadroom defragFreeHeadroom;
+  public static DefragFreeHeadroomFraction defragFreeHeadroomFraction;
+  public static DefragLineReuseRatio defragLineReuseRatio;
+  public static DefragSimpleSpillThreshold defragSimpleSpillThreshold;
+  public static DefragStress defragStress;
+  public static EagerCompleteSweep eagerCompleteSweep;
+  public static EagerMmapSpaces eagerMmapSpaces;
+  public static FixedNursery fixedNursery;
+  public static FragmentationStats fragmentationStats;
+  public static FullHeapSystemGC fullHeapSystemGC;
+  public static GCspyPort gcspyPort;
+  public static GCspyTileSize gcspyTileSize;
+  public static GCspyWait gcspyWait;
+  public static GCTimeCap gcTimeCap;
+  public static GenCycleDetection genCycleDetection;
+  public static HarnessAll harnessAll;
+  public static IgnoreSystemGC ignoreSystemGC;
+  public static LineReuseRatio lineReuseRatio;
+  public static MarkSweepMarkBits markSweepMarkBits;
+  public static MetaDataLimit metaDataLimit;
+  public static NoFinalizer noFinalizer;
+  public static NoReferenceTypes noReferenceTypes;
+  public static NurserySize nurserySize;
+  public static PerfMetric perfMetric;
+  public static PrintPhaseStats printPhaseStats;
+  public static ProtectOnRelease protectOnRelease;
+  public static SanityCheck sanityCheck;
+  public static StressFactor stressFactor;
+  public static TraceRate traceRate;
+  public static VariableSizeHeap variableSizeHeap;
+  public static VerboseFragmentationStats verboseFragmentationStats;
+  public static Verbose verbose;
+  public static VerboseTiming verboseTiming;
+  public static XmlStats xmlStats;
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PerfMetric.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PerfMetric.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PerfMetric.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PerfMetric.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Performance counter options.
+ */
+public class PerfMetric extends org.vmutil.options.EnumOption {
+  /**
+   * Create the option.
+   */
+  public PerfMetric() {
+    super(Options.set, "Perf Metric",
+          "Use this to select a performance metric to measure",
+          new String[] {"RI", "L1D_MISS", "L2_MISS", "DTLB_MISS", "ITLB_MISS", "ITLB_HIT", "BPU_TC", "TC_FLUSH", "L1I_MISS", "BRANCHES", "BRANCH_MISS"},
+          "RI");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PrintPhaseStats.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PrintPhaseStats.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PrintPhaseStats.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/PrintPhaseStats.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * When printing statistics, should statistics for each
+ * gc-mutator phase be printed?
+ */
+public final class PrintPhaseStats extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public PrintPhaseStats() {
+    super(Options.set, "Print Phase Stats",
+        "When printing statistics, should statistics for each gc-mutator phase be printed?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ProtectOnRelease.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ProtectOnRelease.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ProtectOnRelease.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/ProtectOnRelease.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should memory be protected on release?
+ */
+public final class ProtectOnRelease extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public ProtectOnRelease() {
+    super(Options.set, "Protect On Release",
+          "Should memory be protected on release?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/SanityCheck.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/SanityCheck.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/SanityCheck.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/SanityCheck.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.mmtk.utility.options;
+
+
+/**
+ * Should a major GC be performed when a system GC is triggered?
+ */
+public final class SanityCheck extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public SanityCheck() {
+    super(Options.set, "Sanity Check",
+          "Perform sanity checks before and after each collection?",
+          false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/StressFactor.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/StressFactor.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/StressFactor.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/StressFactor.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,38 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.utility.Constants;
+
+/**
+ * Force frequent collections after amounts of allocation.
+ */
+public final class StressFactor extends org.vmutil.options.PagesOption {
+  /**
+   * Create the option, defaulting to the maximum possible value.
+   */
+  public StressFactor() {
+    super(Options.set, "Stress Factor",
+          "Force a collection after this much allocation",
+        Integer.MAX_VALUE >>> Constants.LOG_BYTES_IN_PAGE);
+  }
+
+  /**
+   * Ensure that the value is sensible.
+   */
+  public void validate() {
+    failIf(this.value < Plan.DEFAULT_POLL_FREQUENCY,
+        "Stress Factor must be at least equal to plan's poll frequency");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/TraceRate.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/TraceRate.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/TraceRate.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/TraceRate.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,47 @@
+/*
+ *  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.mmtk.utility.options;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * The granularity of the trace being produced.
+ */
+public final class TraceRate extends org.vmutil.options.IntOption
+  implements org.mmtk.utility.Constants {
+  /**
+   * Create the option.
+   */
+  public TraceRate() {
+    super(Options.set, "Trace Rate",
+        "The granularity of the trace being produced.  By default, the trace has the maximum possible granularity.",
+        Integer.MAX_VALUE);
+  }
+
+  /**
+   * Return the appropriate value.
+   *
+   * @return the trace rate.
+   */
+  @Uninterruptible
+  public int getValue() {
+    return (this.value < BYTES_IN_ADDRESS) ? 1 : (this.value >> LOG_BYTES_IN_ADDRESS);
+  }
+
+  /**
+   * Trace rate must be positive.
+   */
+  protected void validate() {
+    failIf(value <= 0, "Can not have a negative trace rate");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VariableSizeHeap.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VariableSizeHeap.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VariableSizeHeap.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VariableSizeHeap.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we shrink/grow the heap to adjust to application working set?
+ */
+public final class VariableSizeHeap extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public VariableSizeHeap() {
+    super(Options.set, "Variable Size Heap",
+        "Should we shrink/grow the heap to adjust to application working set?",
+        true);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Verbose.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Verbose.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Verbose.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/Verbose.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,34 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * GC verbosity level.
+ */
+public final class Verbose extends org.vmutil.options.IntOption {
+  /**
+   * Create the option.
+   */
+  public Verbose() {
+    super(Options.set, "Verbose",
+          "GC verbosity level",
+          0);
+  }
+
+  /**
+   * Only accept non-negative values.
+   */
+  protected void validate() {
+    failIf(this.value < 0, "Unreasonable verbosity level");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseFragmentationStats.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseFragmentationStats.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseFragmentationStats.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseFragmentationStats.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we print verbose fragmentation statistics for the free list allocator?
+ */
+public final class VerboseFragmentationStats extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public VerboseFragmentationStats() {
+    super(Options.set, "Verbose Fragmentation Stats",
+        "Should we print verbose fragmentation statistics for the free list allocator?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseTiming.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseTiming.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseTiming.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/VerboseTiming.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Should we display detailed breakdown of where GC time is spent?
+ */
+public final class VerboseTiming extends org.vmutil.options.BooleanOption {
+  /**
+   * Create the option.
+   */
+  public VerboseTiming() {
+    super(Options.set, "Verbose Timing",
+        "Should we display detailed breakdown of where GC time is spent?",
+        false);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/XmlStats.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/XmlStats.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/XmlStats.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/options/XmlStats.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.mmtk.utility.options;
+
+/**
+ * Display statistics and options in XML rather than himan-readable
+ * format.
+ */
+public final class XmlStats extends org.vmutil.options.BooleanOption {
+
+  /**
+   * Create the option.
+   */
+  public XmlStats() {
+    super(Options.set, "Xml Stats", "Print end-of-run statistics in XML format", false);
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityChecker.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityChecker.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityChecker.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityChecker.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,253 @@
+/*
+ *  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.mmtk.utility.sanitychecker;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.plan.Trace;
+import org.mmtk.plan.Simple;
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.policy.Space;
+import org.mmtk.utility.Constants;
+import org.mmtk.utility.Log;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class performs sanity checks for Simple collectors.
+ */
+ at Uninterruptible
+public final class SanityChecker implements Constants {
+
+  /* Counters */
+  public static long referenceCount;
+  public static long rootReferenceCount;
+  public static long danglingReferenceCount;
+  public static long nullReferenceCount;
+  public static long liveObjectCount;
+
+  public static final int DEAD = -2;
+  public static final int ALIVE = -1;
+  public static final int UNSURE = 0;
+
+  public static final int LOG_SANITY_DATA_SIZE = 24;
+
+  /* Tracing */
+  public Trace rootTrace;
+  public Trace checkTrace;
+  private final SanityDataTable sanityTable;
+  private boolean preGCSanity;
+
+  /* Local, but we only run the check trace single-threaded. */
+  final SanityTraceLocal checkTraceLocal;
+
+  /* Linear scanning */
+  private final SanityLinearScan scanner = new SanityLinearScan(this);
+
+  /****************************************************************************
+   * Constants
+   */
+  public SanityChecker() {
+    sanityTable = new SanityDataTable(Plan.sanitySpace, LOG_SANITY_DATA_SIZE);
+    checkTrace = new Trace(Plan.sanitySpace);
+    rootTrace = new Trace(Plan.sanitySpace);
+    checkTraceLocal = new SanityTraceLocal(checkTrace, this);
+  }
+
+  /**
+   * Perform any sanity checking collection phases.
+   *
+   * @param phaseId The id to proces
+   * @return True if the phase was handled.
+   */
+  @NoInline
+  public boolean collectionPhase(int phaseId) {
+    if (phaseId == Simple.SANITY_SET_PREGC) {
+      preGCSanity = true;
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_SET_POSTGC) {
+      preGCSanity = false;
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_PREPARE) {
+      Log.writeln("");
+      Log.write("============================== GC Sanity Checking ");
+      Log.writeln("==============================");
+      Log.writeln(preGCSanity ? "Performing Pre-GC Sanity Checks..." : "Performing Post-GC Sanity Checks...");
+
+      // Reset counters
+      referenceCount = 0;
+      nullReferenceCount = 0;
+      liveObjectCount = 0;
+      danglingReferenceCount = 0;
+      rootReferenceCount = 0;
+
+      // Clear data space
+      sanityTable.acquireTable();
+
+      // Root trace
+      rootTrace.prepareNonBlocking();
+
+      // Checking trace
+      checkTrace.prepareNonBlocking();
+      checkTraceLocal.prepare();
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_ROOTS) {
+      VM.scanning.resetThreadCounter();
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_BUILD_TABLE) {
+      // Trace, checking for dangling pointers
+      checkTraceLocal.completeTrace();
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_CHECK_TABLE) {
+      // Iterate over the reachable objects.
+      Address curr = sanityTable.getFirst();
+      while (!curr.isZero()) {
+        ObjectReference ref = SanityDataTable.getObjectReference(curr);
+        int normalRC = SanityDataTable.getNormalRC(curr);
+        int rootRC = SanityDataTable.getRootRC(curr);
+        if (!preGCSanity) {
+          int expectedRC = VM.activePlan.global().sanityExpectedRC(ref, rootRC);
+          switch (expectedRC) {
+          case SanityChecker.ALIVE:
+          case SanityChecker.UNSURE:
+            // Always ok.
+            break;
+          case SanityChecker.DEAD:
+            // Never ok.
+            Log.write("ERROR: SanityRC = ");
+            Log.write(normalRC);
+            Log.write(", SpaceRC = 0 ");
+            SanityChecker.dumpObjectInformation(ref);
+            break;
+          default:
+            // A mismatch in an RC space
+            if (normalRC != expectedRC && VM.activePlan.global().lastCollectionFullHeap()) {
+              Log.write("WARNING: SanityRC = ");
+              Log.write(normalRC);
+              Log.write(", SpaceRC = ");
+              Log.write(expectedRC);
+              Log.write(" ");
+              SanityChecker.dumpObjectInformation(ref);
+              break;
+            }
+          }
+        }
+        curr = sanityTable.getNext(curr);
+      }
+
+      if (!preGCSanity && VM.activePlan.global().lastCollectionFullHeap()) {
+        VM.activePlan.global().sanityLinearScan(scanner);
+      }
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_RELEASE) {
+      checkTrace.release();
+      sanityTable.releaseTable();
+      checkTraceLocal.release();
+
+      Log.writeln("roots\tobjects\trefs\tnull");
+      Log.write(rootReferenceCount);Log.write("\t");
+      Log.write(liveObjectCount);Log.write("\t");
+      Log.write(referenceCount);Log.write("\t");
+      Log.writeln(nullReferenceCount);
+
+      Log.write("========================================");
+      Log.writeln("========================================");
+
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * Process an object during a linear scan of the heap. We have already checked
+   * all objects in the table. So we are only interested in objects that are not in
+   * the sanity table here. We are therefore only looking for leaks here.
+   *
+   * @param object The object being scanned.
+   */
+  public void scanProcessObject(ObjectReference object) {
+    if (sanityTable.getEntry(object, false).isZero()) {
+      // Is this a leak?
+      int expectedRC = VM.activePlan.global().sanityExpectedRC(object, 0);
+
+      if (expectedRC == SanityChecker.UNSURE) {
+        // Probably not.
+        return;
+      }
+
+      // Possibly
+      Log.write("WARNING: Possible leak, SpaceRC = ");
+      Log.write(expectedRC);
+      Log.write(" ");
+      SanityChecker.dumpObjectInformation(object);
+    }
+  }
+
+  /**
+   * Process an object during sanity checking, validating data,
+   * incrementing counters and enqueuing if this is the first
+   * visit to the object.
+   *
+   * @param object The object to mark.
+   * @param root True If the object is a root.
+   */
+  public void processObject(TraceLocal trace, ObjectReference object, boolean root) {
+    SanityChecker.referenceCount++;
+    if (root) SanityChecker.rootReferenceCount++;
+
+    if (object.isNull()) {
+      SanityChecker.nullReferenceCount++;
+      return;
+    }
+
+    if (Plan.SCAN_BOOT_IMAGE && Space.isInSpace(Plan.VM_SPACE, object)) {
+      return;
+    }
+
+    // Get the table entry.
+    Address tableEntry = sanityTable.getEntry(object, true);
+
+    if (SanityDataTable.incRC(tableEntry, root)) {
+      SanityChecker.liveObjectCount++;
+      trace.processNode(object);
+    }
+  }
+
+  /**
+   * Print out object information (used for warning and error messages)
+   *
+   * @param object The object to dump info for.
+   */
+  public static void dumpObjectInformation(ObjectReference object) {
+    Log.write(object);
+    Log.write(" [");
+    Log.write(Space.getSpaceForObject(object).getName());
+    Log.write("] ");
+    Log.writeln(VM.objectModel.getTypeDescriptor(object));
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityCheckerLocal.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityCheckerLocal.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityCheckerLocal.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityCheckerLocal.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,78 @@
+/*
+ *  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.mmtk.utility.sanitychecker;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.plan.Simple;
+import org.mmtk.utility.Constants;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class performs sanity checks for Simple collectors.
+ */
+ at Uninterruptible
+public final class SanityCheckerLocal implements Constants {
+
+  /* Trace */
+  final SanityRootTraceLocal rootTraceLocal;
+
+  /****************************************************************************
+   * Constants
+   */
+  public SanityCheckerLocal() {
+    rootTraceLocal = new SanityRootTraceLocal(Plan.sanityChecker.rootTrace);
+  }
+
+  /**
+   * Perform any sanity checking collection phases.
+   *
+   * @param phaseId The id to proces
+   * @param primary Perform local single threaded actions on this thread
+   * @return True if the phase was handled.
+   */
+  @NoInline
+  public boolean collectionPhase(int phaseId, boolean primary) {
+    if (phaseId == Simple.SANITY_PREPARE) {
+      rootTraceLocal.prepare();
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_ROOTS) {
+      VM.scanning.computeGlobalRoots(rootTraceLocal);
+      VM.scanning.computeThreadRoots(rootTraceLocal);
+      VM.scanning.computeStaticRoots(rootTraceLocal);
+      if (Plan.SCAN_BOOT_IMAGE) {
+        VM.scanning.computeBootImageRoots(rootTraceLocal);
+      }
+      rootTraceLocal.flush();
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_COPY_ROOTS) {
+      if (primary) {
+        rootTraceLocal.copyRootValuesTo(Plan.sanityChecker.checkTraceLocal);
+      }
+      return true;
+    }
+
+    if (phaseId == Simple.SANITY_RELEASE) {
+      rootTraceLocal.release();
+      return true;
+    }
+
+    return false;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityDataTable.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityDataTable.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityDataTable.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityDataTable.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,161 @@
+/*
+ *  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.mmtk.utility.sanitychecker;
+
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.policy.RawPageSpace;
+import org.mmtk.utility.Constants;
+import org.mmtk.utility.deque.*;
+import org.mmtk.utility.SimpleHashtable;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements a simple hashtable to store and retrieve per
+ * object information for sanity checking. <p>
+ *
+ * This class is not thread safe.
+ */
+ at Uninterruptible
+public final class SanityDataTable extends SimpleHashtable implements Constants {
+
+  /** The number of bits for the normal reference count */
+  private static final int NORMAL_RC_BITS = 25;
+
+  /** The mask for the normal reference count */
+  private static final int NORMAL_RC_MASK = (1 << 25) - 1;
+
+  /** The shift for the root reference count */
+  private static final int ROOT_RC_SHIFT = NORMAL_RC_BITS;
+
+  /** The increment to use for normal increments */
+  private static final int NORMAL_RC_INC = 1;
+
+  /** The increment to use for root increments */
+  private static final int ROOT_RC_INC = 1 << ROOT_RC_SHIFT;
+
+  /**
+   * Create a new data table of a specified size.
+   *
+   * @param rps The space to acquire the data structure from.
+   * @param logSize The log of the number of table entries.
+   */
+  public SanityDataTable(RawPageSpace rps, int logSize) {
+    super(rps, logSize, Extent.fromIntSignExtend(BYTES_IN_WORD));
+  }
+
+  /**
+   * Increment the data word for an object.
+   *
+   * @param entry The table entry.
+   * @param root True if this is a root reference.
+   * @return True if this is the first ref to that object.
+   */
+  @Inline
+  public static boolean incRC(Address entry, boolean root) {
+    Address data = SimpleHashtable.getPayloadAddress(entry);
+    int old = data.loadInt();
+    data.store(old + (root ? ROOT_RC_INC : NORMAL_RC_INC));
+    return (old == 0);
+  }
+
+  /**
+   * Push any entries that are only in this table, and not the
+   * passed table. This does not compare values.
+   *
+   * @param other The table to use for comparison.
+   * @param deque The buffer to push results onto.
+   */
+  public void pushNotInOther(SanityDataTable other,
+                             ObjectReferenceDeque deque) {
+    Address entry = getFirst();
+    while (!entry.isZero()) {
+      Word key = SimpleHashtable.getKey(entry);
+      if (!other.contains(key)) {
+        deque.push(key.toAddress().toObjectReference());
+      }
+      entry = getNext(entry);
+    }
+  }
+
+
+  /**
+   * Given an address of an entry, read the reference count,
+   * excluding root references.
+   *
+   * @param entry The entry
+   * @return The reference count.
+   */
+  public static int getNormalRC(Address entry) {
+    return SimpleHashtable.getPayloadAddress(entry).loadInt() & NORMAL_RC_MASK;
+  }
+
+  /**
+   * Given an address of an entry, read the root reference count.
+   *
+   * @param entry The entry
+   * @return The root reference count.
+   */
+  public static int getRootRC(Address entry) {
+    return SimpleHashtable.getPayloadAddress(entry).loadInt() >>> ROOT_RC_SHIFT;
+  }
+
+  /**
+   * Given an address of an entry, read the total reference count.
+   *
+   * @param entry The entry
+   * @return The total reference count.
+   */
+  public static int getRC(Address entry) {
+    int val = SimpleHashtable.getPayloadAddress(entry).loadInt();
+    return (val & NORMAL_RC_MASK) + val >>> ROOT_RC_SHIFT;
+  }
+
+  /**
+   * Given an address of an entry, read the reference component.
+   *
+   * @param entry The entry
+   * @return The object reference.
+   */
+  public static ObjectReference getObjectReference(Address entry) {
+    return SimpleHashtable.getKey(entry).toAddress().toObjectReference();
+  }
+
+  /**
+   * Forward data table using the supplied trace. Note that the data is
+   * not hashed correctly, so only enumeration can be used without
+   * rehashing.
+   *
+   * @param trace The trace to use.
+   */
+  public void forwardTable(TraceLocal trace) {
+    Address entry = getFirst();
+    while (!entry.isZero()) {
+      ObjectReference obj = getObjectReference(entry);
+      SimpleHashtable.replaceKey(entry, trace.getForwardedReference(obj).toAddress().toWord());
+      entry = getNext(entry);
+    }
+  }
+
+  /**
+   * Get an entry for an object.
+   *
+   * @param object The object to find an entry for.
+   * @param create Create an entry if none exists?
+   * @return The entry address.
+   */
+  public Address getEntry(ObjectReference object, boolean create) {
+    return super.getEntry(object.toAddress().toWord(), create);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityLinearScan.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityLinearScan.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityLinearScan.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityLinearScan.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,34 @@
+/*
+ *  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.mmtk.utility.sanitychecker;
+
+import org.mmtk.utility.alloc.LinearScan;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.ObjectReference;
+
+/**
+ * This class performs sanity checks for Simple collectors.
+ */
+ at Uninterruptible
+final class SanityLinearScan extends LinearScan {
+
+  private final SanityChecker sanityChecker;
+  public SanityLinearScan(SanityChecker sanityChecker) {
+    this.sanityChecker = sanityChecker;
+  }
+
+  public void scan(ObjectReference object) {
+    sanityChecker.scanProcessObject(object);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityRootTraceLocal.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityRootTraceLocal.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityRootTraceLocal.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityRootTraceLocal.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,101 @@
+/*
+ *  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.mmtk.utility.sanitychecker;
+
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.plan.Trace;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements the parallel root-gathering part of a sanity check.
+ */
+ at Uninterruptible
+public final class SanityRootTraceLocal extends TraceLocal {
+
+  /**
+   * Constructor
+   */
+  public SanityRootTraceLocal(Trace trace) {
+    super(trace);
+  }
+
+  /****************************************************************************
+   *
+   * Object processing and tracing
+   */
+
+  /**
+   * Copy root values across to the 'real' single-threaded trace that will do
+   * the sanity checking.
+   */
+  @Inline
+  public void copyRootValuesTo(TraceLocal trace) {
+    while (!rootLocations.isEmpty()) {
+      ObjectReference object = rootLocations.pop().loadObjectReference();
+      if (!object.isNull()) {
+        trace.traceObject(object, true);
+      }
+    }
+    while (!values.isEmpty()) {
+      trace.traceObject(values.pop(), true);
+    }
+  }
+
+  /**
+   * Process delayed roots. This does not make sense for SanityRootTraceLocal.
+   * are empty.
+   */
+  @Inline
+  public void processRoots() {
+    VM.assertions.fail("SanityRootTraceLocal.processRoots called.");
+  }
+
+  /**
+   * Finishing processing all GC work. This does not make sense for SanityRootTraceLocal.
+   */
+  @Inline
+  public void completeTrace() {
+    VM.assertions.fail("SanityRootTraceLocal.completeTrace called.");
+  }
+
+  /**
+   * This method is the core method during the trace of the object graph.
+   * The role of this method is to:
+   *
+   * @param object The object to be traced.
+   * @param root Is this object a root?
+   * @return The new reference to the same object instance.
+   */
+  @Inline
+  public ObjectReference traceObject(ObjectReference object, boolean root) {
+    if (!root) VM.assertions.fail("SanityRootTraceLocal.traceObject called for non-root object.");
+    if (!object.isNull()) {
+      values.push(object);
+    }
+    return object;
+  }
+
+  /**
+   * Will this object move from this point on, during the current trace ?
+   *
+   * @param object The object to query.
+   * @return True if the object will not move.
+   */
+  public boolean willNotMoveInCurrentCollection(ObjectReference object) {
+    // We never move objects!
+    return true;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityTraceLocal.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityTraceLocal.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityTraceLocal.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/sanitychecker/SanityTraceLocal.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,66 @@
+/*
+ *  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.mmtk.utility.sanitychecker;
+
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.plan.Trace;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.*;
+
+/**
+ * This class implements the simply sanity closure.
+ */
+ at Uninterruptible
+public final class SanityTraceLocal extends TraceLocal {
+
+  private final SanityChecker sanityChecker;
+
+  /**
+   * Constructor
+   */
+  public SanityTraceLocal(Trace trace, SanityChecker sanityChecker) {
+    super(trace);
+    this.sanityChecker = sanityChecker;
+  }
+
+  /****************************************************************************
+   *
+   * Object processing and tracing
+   */
+
+  /**
+   * This method is the core method during the trace of the object graph.
+   * The role of this method is to:
+   *
+   * @param object The object to be traced.
+   * @param root Is this object a root?
+   * @return The new reference to the same object instance.
+   */
+  @Inline
+  public ObjectReference traceObject(ObjectReference object, boolean root) {
+    sanityChecker.processObject(this, object, root);
+    return object;
+  }
+
+  /**
+   * Will this object move from this point on, during the current trace ?
+   *
+   * @param object The object to query.
+   * @return True if the object will not move.
+   */
+  public boolean willNotMoveInCurrentCollection(ObjectReference object) {
+    // We never move objects!
+    return true;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/BooleanCounter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/BooleanCounter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/BooleanCounter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/BooleanCounter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,200 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.utility.Log;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements a simple boolean counter (counting number of
+ * phases where some boolean event is true).
+ */
+ at Uninterruptible public class BooleanCounter extends Counter {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  private final boolean[] state;
+
+  protected int total = 0;
+  private boolean running = false;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  public BooleanCounter(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   */
+  public BooleanCounter(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   * @param mergephases True if this counter does not separately
+   * report GC and Mutator phases.
+   */
+  public BooleanCounter(String name, boolean start, boolean mergephases) {
+    super(name, start, mergephases);
+    state = new boolean[Stats.MAX_PHASES];
+    for (int i = 0; i < Stats.MAX_PHASES; i++)
+      state[i] = false;
+  }
+
+  /****************************************************************************
+   *
+   * Counter-specific methods
+   */
+
+  /**
+   * Set the boolean to true for this phase, increment the total.
+   */
+  public void set() {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Stats.phase == Stats.MAX_PHASES -1 || !state[Stats.phase]);
+    state[Stats.phase] = true;
+    total++;
+  }
+
+  /****************************************************************************
+   *
+   * Generic counter control methods: start, stop, print etc
+   */
+
+  /**
+   * Start this counter
+   */
+  protected void start() {
+    if (!Stats.gatheringStats) return;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!running);
+    running = true;
+  }
+
+  /**
+   * Stop this counter
+   */
+  protected void stop() {
+    if (!Stats.gatheringStats) return;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(running);
+    running = false;
+  }
+
+  /**
+   * The phase has changed (from GC to mutator or mutator to GC).
+   * Take action with respect to the last phase if necessary.
+   * <b>Do nothing in this case.</b>
+   *
+   * @param oldPhase The last phase
+   */
+  void phaseChange(int oldPhase) {}
+
+  /**
+   * Print the value of this counter for the given phase.  Print '0'
+   * for false, '1' for true.
+   *
+   * @param phase The phase to be printed
+   */
+  protected final void printCount(int phase) {
+    if (VM.VERIFY_ASSERTIONS && mergePhases())
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((phase | 1) == (phase + 1));
+    if (mergePhases())
+      printValue((state[phase] || state[phase + 1]) ? 1 : 0);
+    else
+      printValue((state[phase]) ? 1 : 0);
+  }
+
+  /**
+   * Print the current total number of 'true' phases for this counter
+   */
+  protected final void printTotal() {
+    int total = 0;
+    for (int p = 0; p <= Stats.phase; p++) {
+      total += (state[p]) ? 1 : 0;
+    }
+    printValue(total);
+  }
+
+  /**
+   * Print the current total number of 'true' phases for either the
+   * mutator or GC phase
+   *
+   * @param mutator True if the total for the mutator phases is to be
+   * printed (otherwise the total for the GC phases will be printed).
+   */
+  protected final void printTotal(boolean mutator) {
+    int total = 0;
+    for (int p = (mutator) ? 0 : 1; p <= Stats.phase; p += 2) {
+      total += (state[p]) ? 1 : 0;
+    }
+    printValue(total);
+  }
+
+  /**
+   * Print the current minimum value for either the mutator or GC
+   * phase. <b>Do nothing in this case.</b>
+   *
+   * @param mutator True if the minimum for the mutator phase is to be
+   * printed (otherwise the minimum for the GC phase will be printed).
+   */
+  protected final void printMin(boolean mutator) {}
+
+  /**
+   * Print the current maximum value for either the mutator or GC
+   * phase. <b>Do nothing in this case.</b>
+   *
+   * @param mutator True if the maximum for the mutator phase is to be
+   * printed (otherwise the maximum for the GC phase will be printed).
+   */
+  protected final void printMax(boolean mutator) {}
+
+  /**
+   * Print the given value
+   *
+   * @param value The value to be printed
+   */
+  void printValue(int value) {
+    Log.write(value);
+  }
+
+  /**
+   * Print statistics for the most recent phase
+   */
+  public void printLast() {
+    if (Stats.phase > 0) printCount(Stats.phase - 1);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Counter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Counter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Counter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Counter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,173 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.vmmagic.pragma.*;
+
+/**
+ *
+ * This abstract class describes the interface of a generic counter.
+ */
+ at Uninterruptible public abstract class Counter {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  private final String name;
+  private final boolean start;
+  private final boolean mergephases;
+
+  /**
+   * Allow for counters whose values are too complex to be simply printed out.
+   */
+  protected boolean complex = false;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  Counter(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   */
+  Counter(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start  True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   * @param mergephases True if this counter does not separately
+   * report GC and Mutator phases.
+   */
+  Counter(String name, boolean start, boolean mergephases) {
+    this.name = name;
+    this.start = start;
+    this.mergephases = mergephases;
+    Stats.newCounter(this);
+  }
+
+  /****************************************************************************
+   *
+   * Counter control methods: start, stop, print etc
+   */
+
+  /**
+   * Start this counter
+   */
+  abstract void start();
+
+  /**
+   * Stop this counter
+   */
+  abstract void stop();
+
+  /**
+   * The phase has changed (from GC to mutator or mutator to GC).
+   * Take action with respect to the last phase if necessary.
+   *
+   * @param oldPhase The last phase
+   */
+  abstract void phaseChange(int oldPhase);
+
+  /**
+   * Print the value of this counter for the given phase
+   *
+   * @param phase The phase to be printed
+   */
+  abstract void printCount(int phase);
+
+  /**
+   * Print the current total for this counter
+   */
+  abstract void printTotal();
+
+  /**
+   * Print the current total for either the mutator or GC phase
+   *
+   * @param mutator True if the total for the mutator phases is to be
+   * printed (otherwise the total for the GC phases will be printed).
+   */
+  abstract void printTotal(boolean mutator);
+
+  /**
+   * Print the current minimum value for either the mutator or GC phase
+   *
+   * @param mutator True if the minimum for the mutator phase is to be
+   * printed (otherwise the minimum for the GC phase will be printed).
+   */
+  abstract void printMin(boolean mutator);
+
+  /**
+   * Print the current maximum value for either the mutator or GC phase
+   *
+   * @param mutator True if the maximum for the mutator phase is to be
+   * printed (otherwise the maximum for the GC phase will be printed).
+   */
+  abstract void printMax(boolean mutator);
+
+  /**
+   * Print statistics for the most recent phase
+   */
+  public void printLast() {
+    if (Stats.phase > 0) printCount(Stats.phase - 1);
+  }
+
+
+  /****************************************************************************
+   *
+   * Accessor methods
+   */
+
+  /**
+   * Return the name of this counter
+   * @return The name of this counter
+   */
+  String getName() { return name; }
+
+  /**
+   * Return true if this counter is implicitly started when
+   * <code>startAll()</code> is called.
+   * @return True if this counter is implicitly started when
+   *         <code>startAll()</code> is called.
+   */
+  boolean getStart() { return start; }
+
+  /**
+   * Return true if this counter will merge stats for GC and mutator phases.
+   * @return True if this counter will merge stats for GC and mutator phases.
+   */
+  boolean mergePhases() { return mergephases; }
+
+  boolean isComplex() { return complex; }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/EventCounter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/EventCounter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/EventCounter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/EventCounter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,230 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.utility.Log;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements a simple event counter (counting number
+ * events that occur for each phase).
+ */
+ at Uninterruptible public class EventCounter extends Counter {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  private final long[] count;
+
+  protected long totalCount = 0;
+  private boolean running = false;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  public EventCounter(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   */
+  public EventCounter(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   * @param mergephases True if this counter does not separately
+   * report GC and Mutator phases.
+   */
+  public EventCounter(String name, boolean start, boolean mergephases) {
+    super(name, start, mergephases);
+    count = new long[Stats.MAX_PHASES];
+  }
+
+  /****************************************************************************
+   *
+   * Counter-specific methods
+   */
+
+  /**
+   * Increment the event counter
+   */
+  public void inc() {
+    if (running) inc(1);
+  }
+
+  /**
+   * Increment the event counter by <code>value</code>
+   *
+   * @param value The amount by which the counter should be incremented.
+   */
+  public void inc(int value) {
+    if (running) totalCount += value;
+  }
+
+  /****************************************************************************
+   *
+   * Generic counter control methods: start, stop, print etc
+   */
+
+  /**
+   * Start this counter
+   */
+  protected void start() {
+    if (!Stats.gatheringStats) return;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!running);
+    running = true;
+  }
+
+  /**
+   * Stop this counter
+   */
+  protected void stop() {
+    if (!Stats.gatheringStats) return;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(running);
+    running = false;
+  }
+
+  /**
+   * The phase has changed (from GC to mutator or mutator to GC).
+   * Take action with respect to the last phase if necessary.
+   * <b>Do nothing in this case.</b>
+   *
+   * @param oldPhase The last phase
+   */
+  void phaseChange(int oldPhase) {
+    if (running) {
+      count[oldPhase] = totalCount;
+      totalCount = 0;
+    }
+  }
+
+  /**
+   * Print the value of this counter for the given phase.  Print '0'
+   * for false, '1' for true.
+   *
+   * @param phase The phase to be printed
+   */
+  protected final void printCount(int phase) {
+    if (VM.VERIFY_ASSERTIONS && mergePhases())
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((phase | 1) == (phase + 1));
+    if (mergePhases())
+      printValue(count[phase] + count[phase + 1]);
+    else
+      printValue(count[phase]);
+  }
+
+  /**
+   * Print the current value for this counter (mid-phase)
+   */
+  public final void printCurrent() {
+    printValue(totalCount);
+  }
+
+  /**
+   * Print the current total for this counter
+   */
+  public final void printTotal() {
+    long total = 0;
+    for (int p = 0; p <= Stats.phase; p++) {
+      total += count[p];
+    }
+    printValue(total);
+  }
+
+  /**
+   * Print the current total for either the mutator or GC phase
+   *
+   * @param mutator True if the total for the mutator phases is to be
+   * printed (otherwise the total for the GC phases will be printed).
+   */
+  protected final void printTotal(boolean mutator) {
+    long total = 0;
+    for (int p = (mutator) ? 0 : 1; p <= Stats.phase; p += 2) {
+      total += count[p];
+    }
+    printValue(total);
+  }
+
+  /**
+   * Print the current minimum value for either the mutator or GC
+   * phase.
+   *
+   * @param mutator True if the minimum for the mutator phase is to be
+   * printed (otherwise the minimum for the GC phase will be printed).
+   */
+  protected final void printMin(boolean mutator) {
+    int p = (mutator) ? 0 : 1;
+    long min = count[p];
+    for (; p < Stats.phase; p += 2) {
+      if (count[p] < min) min = count[p];
+    }
+    printValue(min);
+  }
+
+  /**
+   * Print the current maximum value for either the mutator or GC
+   * phase.
+   *
+   * @param mutator True if the maximum for the mutator phase is to be
+   * printed (otherwise the maximum for the GC phase will be printed).
+   */
+  protected final void printMax(boolean mutator) {
+    int p = (mutator) ? 0 : 1;
+    long max = count[p];
+    for (; p < Stats.phase; p += 2) {
+      if (count[p] > max) max = count[p];
+    }
+    printValue(max);
+  }
+
+  /**
+   * Print the given value
+   *
+   * @param value The value to be printed
+   */
+  void printValue(long value) {
+    Log.write(value);
+  }
+
+  /**
+   * Print statistics for the most recent phase
+   */
+  public void printLast() {
+    if (Stats.phase > 0) printCount(Stats.phase - 1);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/LongCounter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/LongCounter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/LongCounter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/LongCounter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,215 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.utility.Log;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This abstract class implements a simple counter (counting some
+ * integer (long) value for each phase).
+ */
+ at Uninterruptible public abstract class LongCounter extends Counter {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+
+  private final long[] count;
+
+  private long startValue = 0;
+  protected long totalCount = 0;
+  private boolean running = false;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  LongCounter(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   */
+  LongCounter(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   * @param mergephases True if this counter does not separately
+   * report GC and Mutator phases.
+   */
+  LongCounter(String name, boolean start, boolean mergephases) {
+    super(name, start, mergephases);
+    count = new long[Stats.MAX_PHASES];
+  }
+
+  /****************************************************************************
+   *
+   * Counter-specific methods
+   */
+  protected abstract long getCurrentValue();
+
+  /****************************************************************************
+   *
+   * Generic counter control methods: start, stop, print etc
+   */
+
+  /**
+   * Start this counter
+   */
+  public void start() {
+    if (!Stats.gatheringStats) return;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!running);
+    running = true;
+    startValue = getCurrentValue();
+  }
+
+  /**
+   * Stop this counter
+   */
+  public void stop() {
+    if (!Stats.gatheringStats) return;
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(running);
+    running = false;
+    long delta = getCurrentValue() - startValue;
+    count[Stats.phase] += delta;
+    totalCount += delta;
+  }
+
+  /**
+   * The phase has changed (from GC to mutator or mutator to GC).
+   * Take action with respect to the last phase if necessary.
+   * <b>Do nothing in this case.</b>
+   *
+   * @param oldPhase The last phase
+   */
+  protected void phaseChange(int oldPhase) {
+    if (running) {
+      long now = getCurrentValue();
+      long delta = now - startValue;
+      count[oldPhase] += delta;
+      totalCount += delta;
+      startValue = now;
+    }
+  }
+
+  /**
+   * Print the value of this counter for the given phase.  Print '0'
+   * for false, '1' for true.
+   *
+   * @param phase The phase to be printed
+   */
+  protected final void printCount(int phase) {
+    if (VM.VERIFY_ASSERTIONS && mergePhases())
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((phase | 1) == (phase + 1));
+    if (mergePhases())
+      printValue(count[phase] + count[phase + 1]);
+    else
+      printValue(count[phase]);
+  }
+
+  /**
+   * Print the current total for this counter
+   */
+  public final void printTotal() {
+    printValue(totalCount);
+  }
+
+
+  /**
+   * Get the total as at the lasts phase
+   *
+   * @return The total as at the last phase
+   */
+  long getLastTotal() {
+    return totalCount;
+  }
+
+  /**
+   * Print the current total for either the mutator or GC phase
+   *
+   * @param mutator True if the total for the mutator phases is to be
+   * printed (otherwise the total for the GC phases will be printed).
+   */
+  protected final void printTotal(boolean mutator) {
+    long total = 0;
+    for (int p = (mutator) ? 0 : 1; p <= Stats.phase; p += 2) {
+      total += count[p];
+    }
+    printValue(total);
+  }
+
+  /**
+   * Print the current minimum value for either the mutator or GC
+   * phase.
+   *
+   * @param mutator True if the minimum for the mutator phase is to be
+   * printed (otherwise the minimum for the GC phase will be printed).
+   */
+  protected final void printMin(boolean mutator) {
+    int p = (mutator) ? 0 : 1;
+    long min = count[p];
+    for (; p < Stats.phase; p += 2) {
+      if (count[p] < min) min = count[p];
+    }
+    printValue(min);
+  }
+
+  /**
+   * Print the current maximum value for either the mutator or GC
+   * phase.
+   *
+   * @param mutator True if the maximum for the mutator phase is to be
+   * printed (otherwise the maximum for the GC phase will be printed).
+   */
+  protected final void printMax(boolean mutator) {
+    int p = (mutator) ? 0 : 1;
+    long max = count[p];
+    for (; p < Stats.phase; p += 2) {
+      if (count[p] > max) max = count[p];
+    }
+    printValue(max);
+  }
+
+  /**
+   * Print the given value
+   *
+   * @param value The value to be printed
+   */
+  void printValue(long value) {
+    Log.write(value);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/PerfCounter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/PerfCounter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/PerfCounter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/PerfCounter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,78 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements a simple performance counter, used to gather
+ * data from hardware performance counters.
+ */
+ at Uninterruptible
+public class PerfCounter extends LongCounter {
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  public PerfCounter(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started at
+   * boot time (otherwise the counter must be explicitly started).
+   */
+  public PerfCounter(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started at
+   * boot time (otherwise the counter must be explicitly started).
+   * @param gconly True if this counter only pertains to (and
+   * therefore functions during) GC phases.
+   */
+  public PerfCounter(String name, boolean start, boolean gconly) {
+    super(name, start, gconly);
+  }
+
+  /****************************************************************************
+   *
+   * Counter-specific methods
+   */
+
+  /**
+   * Get the current value for this counter
+   *
+   * @return The current value for this counter
+   */
+  @Inline
+  protected final long getCurrentValue() {
+    return VM.statistics.perfCtrReadMetric();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/SizeCounter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/SizeCounter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/SizeCounter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/SizeCounter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,138 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements a simple counter of events of different sizes
+ * (eg object allocations, where total number of objects and total
+ * volume of objects would be counted).
+ *
+ * The counter is trivially composed from two event counters (one for
+ * counting the number of events, the other for counting the volume).
+ */
+ at Uninterruptible public class SizeCounter {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private EventCounter units;
+  private EventCounter volume;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  public SizeCounter(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   */
+  public SizeCounter(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   * @param mergephases True if this counter does not separately
+   * report GC and Mutator phases.
+   */
+  public SizeCounter(String name, boolean start, boolean mergephases) {
+    units = new EventCounter(name, start, mergephases);
+    volume = new EventCounter(name + "Volume", start, mergephases);
+  }
+
+  /****************************************************************************
+   *
+   * Counter-specific methods
+   */
+
+  /**
+   * Increment the event counter by <code>value</code>
+   *
+   * @param value The amount by which the counter should be incremented.
+   */
+  public void inc(int value) {
+    units.inc();
+    volume.inc(value);
+  }
+
+  /****************************************************************************
+   *
+   * Generic counter control methods: start, stop, print etc
+   */
+
+  /**
+   * Start this counter
+   */
+  public void start() {
+    units.start();
+    volume.start();
+  }
+
+  /**
+   * Stop this counter
+   */
+  public void stop() {
+    units.stop();
+    volume.stop();
+  }
+
+  /**
+   * Print current (mid-phase) units
+   */
+  public void printCurrentUnits() {
+    units.printCurrent();
+  }
+
+  /**
+   * Print (mid-phase) volume
+   */
+  public void printCurrentVolume() {
+    volume.printCurrent();
+  }
+
+  /**
+   * Print units
+   */
+  public void printUnits() {
+    units.printTotal();
+  }
+
+  /**
+   * Print volume
+   */
+  public void printVolume() {
+    volume.printTotal();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Stats.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Stats.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Stats.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Stats.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,378 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.utility.Log;
+import org.mmtk.utility.options.Options;
+import org.mmtk.utility.options.PrintPhaseStats;
+import org.mmtk.utility.options.XmlStats;
+
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements basic statistics functionality
+ */
+ at Uninterruptible public class Stats {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  public static final boolean GATHER_MARK_CONS_STATS = false;
+
+  /** Maximum number of gc/mutator phases that can be counted */
+  static final int MAX_PHASES = 1 << 12;
+  /** Maximum number of counters that can be in operation */
+  static final int MAX_COUNTERS = 100;
+
+  private static int counters = 0;
+  private static Counter[] counter;
+  static int phase = 0;
+  private static int gcCount = 0;
+  static boolean gatheringStats = false;
+  static boolean exceededPhaseLimit = false;
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Class initializer.  This is executed <i>prior</i> to bootstrap
+   * (i.e. at "build" time).  This is where key <i>global</i>
+   * instances are allocated.  These instances will be incorporated
+   * into the boot image by the build process.
+   */
+  static {
+    counter = new Counter[MAX_COUNTERS];
+    Options.printPhaseStats = new PrintPhaseStats();
+    Options.xmlStats = new XmlStats();
+  }
+
+  /**
+   * Add a new counter to the set of managed counters.
+   *
+   * @param ctr The counter to be added.
+   */
+  @Interruptible
+  static void newCounter(Counter ctr) {
+    if (counters < (MAX_COUNTERS - 1)) {
+      counter[counters++] = ctr;
+    } else {
+      Log.writeln("Warning: number of stats counters exceeds maximum");
+    }
+  }
+
+  /**
+   * Start a new GC phase.  This means notifying each counter of the
+   * phase change.
+   */
+  public static void startGC() {
+    gcCount++;
+    if (!gatheringStats) return;
+    if (phase < MAX_PHASES - 1) {
+      for (int c = 0; c < counters; c++) {
+        counter[c].phaseChange(phase);
+      }
+      phase++;
+    } else if (!exceededPhaseLimit) {
+      Log.writeln("Warning: number of GC phases exceeds MAX_PHASES");
+      exceededPhaseLimit = true;
+    }
+  }
+
+  /**
+   * End a GC phase.  This means notifying each counter of the phase
+   * change.
+   */
+  public static void endGC() {
+    if (!gatheringStats) return;
+    if (phase < MAX_PHASES - 1) {
+      for (int c = 0; c < counters; c++) {
+        counter[c].phaseChange(phase);
+      }
+      phase++;
+    } else if (!exceededPhaseLimit) {
+      Log.writeln("Warning: number of GC phases exceeds MAX_PHASES");
+      exceededPhaseLimit = true;
+    }
+  }
+
+  /**
+   * Start all implicitly started counters (i.e. those for whom
+   * <code>start == true</code>).
+   */
+  public static void startAll() {
+    if (gatheringStats) {
+      Log.writeln("Error: calling Stats.startAll() while stats running");
+      Log.writeln("       verbosity > 0 and the harness mechanism may be conflicitng");
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(false);
+    }
+    gatheringStats = true;
+    for (int c = 0; c < counters; c++) {
+      if (counter[c].getStart())
+        counter[c].start();
+    }
+    if (Options.xmlStats.getValue()) {
+      Xml.begin();
+      Xml.openTag("mmtk-stats");
+      Xml.end();
+    }
+  }
+
+  /**
+   * Stop all counters
+   */
+  @Interruptible
+  public static void stopAll() {
+    stopAllCounters();
+    Stats.printStats();
+    if (Options.xmlStats.getValue()) {
+      Xml.begin();
+      Xml.closeTag("mmtk-stats");
+      Xml.end();
+    }
+  }
+
+  /**
+   * Stop all counters
+   */
+  private static void stopAllCounters() {
+    for (int c = 0; c < counters; c++) {
+      if (counter[c].getStart())
+        counter[c].stop();
+    }
+    gatheringStats = false;
+  }
+
+  @Interruptible
+  public static void printStats() {
+    if (exceededPhaseLimit) {
+      Log.writeln("Warning: number of GC phases exceeds MAX_PHASES.  Statistics are truncated.");
+    }
+    if (Options.xmlStats.getValue())
+      printStatsXml();
+    else
+      printStatsPlain();
+  }
+
+  /**
+   * Print out statistics
+   */
+  @Interruptible
+  public static void printStatsPlain() {
+    if (Options.printPhaseStats.getValue())
+      printPhases();
+    printTotals();
+  }
+
+  /**
+   * Print out statistics totals
+   */
+  @Interruptible
+  public static void printTotals() {
+    Log.writeln("============================ MMTk Statistics Totals ============================");
+    printColumnNames();
+    Log.write(phase/2); Log.write("\t");
+    for (int c = 0; c < counters; c++) {
+      if (counter[c].mergePhases()) {
+        counter[c].printTotal(); Log.write("\t");
+      } else {
+        counter[c].printTotal(true); Log.write("\t");
+        counter[c].printTotal(false); Log.write("\t");
+      }
+    }
+    Log.writeln();
+    Log.write("Total time: ");
+    Plan.totalTime.printTotal(); Log.writeln(" ms");
+    Log.writeln("------------------------------ End MMTk Statistics -----------------------------");
+  }
+
+  /**
+   * Print out statistics for each mutator/gc phase
+   */
+  @Interruptible
+  public static void printPhases() {
+    Log.writeln("--------------------- MMTk Statistics Per GC/Mutator Phase ---------------------");
+    printColumnNames();
+    for (int p = 0; p <= phase; p += 2) {
+      Log.write((p/2)+1); Log.write("\t");
+      for (int c = 0; c < counters; c++) {
+        if (counter[c].mergePhases()) {
+          counter[c].printCount(p); Log.write("\t");
+        } else {
+          counter[c].printCount(p); Log.write("\t");
+          counter[c].printCount(p+1); Log.write("\t");
+        }
+      }
+      Log.writeln();
+    }
+  }
+
+  /**
+   * Print out statistics column names
+   */
+  @Interruptible
+  private static void printColumnNames() {
+    Log.write("GC\t");
+    for (int c = 0; c < counters; c++) {
+      if (counter[c].mergePhases()) {
+        Log.write(counter[c].getName());
+        Log.write("\t");
+      } else {
+        Log.write(counter[c].getName());
+        Log.write(".mu\t");
+        Log.write(counter[c].getName());
+        Log.write(".gc\t");
+      }
+    }
+    Log.writeln();
+  }
+
+  /* ****************************************************************
+   *
+   *              Statistics output in xml format
+ */
+
+  /**
+   * Print command-line options and statistics in XML format
+   */
+  @Interruptible
+  public static void printStatsXml() {
+    Xml.begin();
+    Options.set.logXml();
+    VM.config.printConfigXml();
+    if (Options.printPhaseStats.getValue())
+      printPhasesXml();
+    printTotalsXml();
+    Xml.end();
+  }
+
+  private static void openStatXml(String name) {
+    Xml.openMinorTag("stat");
+    Xml.attribute("name", name);
+  }
+
+  private static void closeStatXml() {
+    Xml.closeMinorTag();
+  }
+
+  enum Phase {
+    MUTATOR("mu"), GC("gc"), COMBINED("all");
+
+    private final String name;
+    Phase(String name) {
+      this.name = name;
+    }
+    public String toString() { return name; }
+  }
+
+  /**
+   * Print out statistics totals in Xml format
+   */
+  @Interruptible
+  public static void printTotalsXml() {
+    Xml.openTag("mmtk-stats-totals");
+    Xml.singleValue("gc", phase/2);
+    for (int c = 0; c < counters; c++) {
+     if (!counter[c].isComplex())
+      if (counter[c].mergePhases()) {
+        printTotalXml(counter[c],Phase.COMBINED);
+      } else {
+        printTotalXml(counter[c],Phase.MUTATOR);
+        printTotalXml(counter[c],Phase.GC);
+      }
+    }
+    Xml.singleValue("total-time",Plan.totalTime.getTotalMillis(),"ms");
+    Xml.closeTag("mmtk-stats-totals");
+  }
+
+  /**
+   * Print a single total in an xml tag
+   *
+   * @param c The counter
+   * @param phase The phase
+   */
+  @Interruptible
+  private static void printTotalXml(Counter c, Phase phase) {
+    openStatXml(c.getName());
+    Xml.openAttribute("value");
+    if (phase == Phase.COMBINED) {
+      c.printTotal();
+    } else {
+      c.printTotal(phase == Phase.MUTATOR);
+      Xml.closeAttribute();
+      Xml.openAttribute("phase");
+      Log.write(phase.toString());
+    }
+    Xml.closeAttribute();
+    closeStatXml();
+  }
+
+  /**
+   * Print a single phase counter in an xml tag
+   *
+   * @param c The counter
+   * @param p The phase number
+   * @param phase The phase (null, "mu" or "gc")
+   */
+  @Interruptible
+  private static void printPhaseStatXml(Counter c, int p, Phase phase) {
+    openStatXml(c.getName());
+    Xml.openAttribute("value");
+    if (phase == Phase.COMBINED) {
+      c.printCount(p);
+    } else {
+      c.printCount(p);
+      Xml.closeAttribute();
+      Xml.openAttribute("phase");
+      Log.write(phase.name);
+   }
+    Xml.closeAttribute();
+    closeStatXml();
+  }
+
+  /**
+   * Print out statistics for each mutator/gc phase in Xml format
+   */
+  @Interruptible
+  public static void printPhasesXml() {
+    Xml.openTag("mmtk-stats-per-gc");
+    for (int p = 0; p <= phase; p += 2) {
+      Xml.openTag("phase",false);
+      Xml.attribute("gc",(p/2)+1);
+      Xml.closeMinorTag();
+      for (int c = 0; c < counters; c++) {
+       if (!counter[c].isComplex())
+        if (counter[c].mergePhases()) {
+          printPhaseStatXml(counter[c],p,Phase.COMBINED);
+        } else {
+          printPhaseStatXml(counter[c],p,Phase.MUTATOR);
+          printPhaseStatXml(counter[c],p,Phase.GC);
+        }
+      }
+      Xml.closeTag("phase");
+    }
+    Xml.closeTag("mmtk-stats-per-gc");
+  }
+
+  /** @return The GC count (inclusive of any in-progress GC) */
+  public static int gcCount() { return gcCount; }
+
+  /** @return True if currently gathering stats */
+  public static boolean gatheringStats() { return gatheringStats; }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Timer.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Timer.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Timer.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Timer.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,145 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.utility.Log;
+import org.mmtk.vm.VM;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * This class implements a simple timer.
+ */
+ at Uninterruptible public class Timer extends LongCounter {
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   */
+  public Timer(String name) {
+    this(name, true, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   */
+  public Timer(String name, boolean start) {
+    this(name, start, false);
+  }
+
+  /**
+   * Constructor
+   *
+   * @param name The name to be associated with this counter
+   * @param start True if this counter is to be implicitly started
+   * when <code>startAll()</code> is called (otherwise the counter
+   * must be explicitly started).
+   * @param mergephases True if this counter does not separately
+   * report GC and Mutator phases.
+   */
+  public Timer(String name, boolean start, boolean mergephases) {
+    super(name, start, mergephases);
+  }
+
+  /****************************************************************************
+   *
+   * Counter-specific methods
+   */
+
+  /**
+   * Get the current value for this timer
+   *
+   * @return The current value for this timer
+   */
+  @Inline
+  protected final long getCurrentValue() {
+    return VM.statistics.nanoTime();
+  }
+
+  /**
+   * Print the total in microseconds
+   */
+  final void printTotalMicro() {
+    printMicro(totalCount);
+  }
+
+  /**
+   * Print the total in milliseconds
+   */
+  public final void printTotalMillis() {
+    printMillis(totalCount);
+  }
+
+  /**
+   * Print the total in seconds
+   */
+  public final void printTotalSecs() {
+    printSecs(totalCount);
+  }
+
+  /**
+   * Print a value (in milliseconds)
+   *
+   * @param value The value to be printed
+   */
+  final void printValue(long value) {
+    printMillis(value);
+  }
+
+  /**
+   * Print a value in microseconds
+   *
+   * @param value The value to be printed
+   */
+  final void printMicro(long value) {
+    Log.write(1000 * VM.statistics.nanosToMillis(value));
+  }
+
+  /**
+   * Print a value in milliseconds
+   *
+   * @param value The value to be printed
+   */
+  final void printMillis(long value) {
+    Log.write(VM.statistics.nanosToMillis(value));
+  }
+
+  /**
+   * Print a value in seconds
+   *
+   * @param value The value to be printed
+   */
+  final void printSecs(long value) {
+    Log.write(VM.statistics.nanosToSecs(value));
+  }
+
+  /**
+   * Get the current value of the timer in milliseconds
+   */
+  final double getTotalMillis() {
+    return VM.statistics.nanosToMillis(totalCount);
+  }
+
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Xml.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Xml.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Xml.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/utility/statistics/Xml.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,300 @@
+/*
+ *  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.mmtk.utility.statistics;
+
+import org.mmtk.utility.Log;
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Word;
+
+/**
+ * Utility class for writing statistics out in XML format.
+ */
+ at Uninterruptible
+public class Xml {
+  /**
+   * Mark the start of XML output
+   */
+  public static void begin() {
+    Log.writeln("<xml-begin/> <!-- Everything until xml-end is now valid xml -->");
+  }
+
+  /**
+   * Mark the end of XML output
+   */
+  public static void end() {
+    Log.writeln("<xml-end/> <!-- Non-xml data follows ... -->");
+  }
+
+  /**
+   * Close the innermost XML tag and pop it from the stack.
+   */
+  public static void closeTag(String name) {
+    Log.write("</"); Log.write(name); Log.writeln(">");
+  }
+
+  /**
+   * Open an XML tag.
+   *
+   * @param name Tag name
+   * @param endTag Should the tag be closed, or left open for
+   *               adding additional attributes
+   */
+  static void openTag(String name, boolean endTag) {
+    openMinorTag(name);
+    if (endTag)
+      closeTag(false);
+  }
+
+  /**
+   * Open a simple XML entity.
+   *
+   * @param name Name of the entity
+   */
+  static void openTag(String name) { openTag(name,true); }
+
+  /**
+   * Output a "stat" entity, with a given name, <code>double</code>value and optionally, units.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   * @param units The units, or null for no units.
+   */
+  public static void singleValue(String name, double value, String units) {
+    openMinorTag("stat");
+    attribute("name",name);
+    attribute("value",value);
+    if (units != null) attribute("units",units);
+    closeMinorTag();
+  }
+
+  /**
+   * Convenience version of singleValue where units are not specified.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void singleValue(String name, double value) {
+    singleValue(name,value,null);
+  }
+
+  /**
+   * Output a "config" entity, with a given name and <code>boolean</code>value.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void configItem(String name, boolean value) {
+    openMinorTag("conf");
+    attribute("name",name);
+    attribute("value",value);
+    closeMinorTag();
+  }
+
+  /**
+   * Output a "config" entity, with a given name and <code>String</code>value.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void configItem(String name, String value) {
+    openMinorTag("conf");
+    attribute("name",name);
+    attribute("value",value);
+    closeMinorTag();
+  }
+
+  /**
+   * Output a "stat" entity, with a given name, <code>long</code> value and
+   * optionally, units.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   * @param units The units, or null for no units.
+   */
+  public static void singleValue(String name, long value, String units) {
+    openMinorTag("stat");
+    attribute("name",name);
+    attribute("value",value);
+    if (units != null) attribute("units",units);
+    closeMinorTag();
+  }
+
+  /**
+   * Convenience version of singleValue where units are not specified.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void singleValue(String name, long value) {
+    singleValue(name,value,null);
+  }
+
+  /**
+   * Add a word-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, Word value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Add a byte[]-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, byte[] value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Add a String-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, String value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Add a boolean-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, boolean value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Add a double-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, double value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Add a long-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, long value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Add an int-valued attribute to an open XML tag.
+   *
+   * @param name Name of the entity
+   * @param value The value of the entity
+   */
+  public static void attribute(String name, int value) {
+    openAttribute(name); Log.write(value); closeAttribute();
+  }
+
+  /**
+   * Close an attribute (actually a simple close-quote)
+   */
+  public static void closeAttribute() {
+    Log.write("\"");
+  }
+
+  /**
+   * Open an attribute (write "{name}=\")
+   *
+   * @param name Name of the entity
+   */
+  public static void openAttribute(String name) {
+    Log.write(" "); Log.write(name); Log.write("=\"");
+  }
+
+  /**
+   * Start a tag
+   */
+  public static void startTag() {
+    Log.write("<");
+  }
+
+  /**
+   * End a tag, optionally closing it (if it is a simple entity)
+   *
+   * @param close If true, close the tag with "/>" rather than ">"
+   */
+  public static void closeTag(boolean close) {
+    closeTag(close,true);
+  }
+
+  /**
+   * End a tag, optionally closing it (if it is a simple entity),
+   * and optionally printing end-of-line
+   *
+   * @param close If true, close the tag with "/>" rather than ">"
+   * @param endLine If true end the current line.
+   */
+  public static void closeTag(boolean close, boolean endLine) {
+    if (close) Log.write("/");
+    Log.write(">");
+    if (endLine) Log.writeln();
+  }
+
+  /**
+   * Close a tag with a "/>"
+   */
+  public static void closeMinorTag() {
+    closeTag(true,true);
+  }
+
+  /**
+   * Open a tag without pushing it on the tag stack - must end this
+   * with a call to closeMinorTag()
+   *
+   * @param name Name of the entity
+   */
+  public static void openMinorTag(String name) {
+    Log.write("<"); Log.write(name);
+  }
+
+  /**
+   * Open an XML comment
+   */
+  public static void openComment() {
+    Log.write("<!-- ");
+  }
+
+  /**
+   * Close an XML comment
+   */
+  public static void closeComment() {
+    Log.write(" -->");
+  }
+
+  /**
+   * Add a comment, bracketing it with open- and close-comment tags.
+   *
+   * @param comment The comment.
+   */
+  public static void comment(String comment) {
+    openComment();
+    Log.write(comment);
+    closeComment();
+    Log.writeln();
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/ActivePlan.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/ActivePlan.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/ActivePlan.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/ActivePlan.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,59 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.plan.Plan;
+import org.mmtk.plan.CollectorContext;
+import org.mmtk.plan.MutatorContext;
+import org.mmtk.plan.PlanConstraints;
+
+import org.mmtk.utility.Log;
+
+import org.vmmagic.pragma.*;
+
+/**
+ * Stub to give access to plan local, constraint and global instances
+ */
+ at Uninterruptible public abstract class ActivePlan {
+
+  /** @return The active Plan instance. */
+  public abstract Plan global();
+
+  /** @return The active PlanConstraints instance. */
+  public abstract PlanConstraints constraints();
+
+  /** @return The active <code>CollectorContext</code> instance. */
+  public abstract CollectorContext collector();
+
+  /** @return The active <code>MutatorContext</code> instance. */
+  public abstract MutatorContext mutator();
+
+  /** @return The log for the active thread */
+  public abstract Log log();
+
+  /** @return The maximum number of collector threads that may participate in parallel GC. */
+  public abstract int collectorCount();
+
+  /** Reset the mutator iterator */
+  public abstract void resetMutatorIterator();
+
+  /**
+   * Return the next <code>MutatorContext</code> in a
+   * synchronized iteration of all mutators.
+   *
+   * @return The next <code>MutatorContext</code> in a
+   *  synchronized iteration of all mutators, or
+   *  <code>null</code> when all mutators have been done.
+   */
+  public abstract MutatorContext getNextMutator();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Assert.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Assert.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Assert.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Assert.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,77 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+ at Uninterruptible public abstract class Assert {
+  /**
+   * Logs a message and traceback, then exits.
+   *
+   * @param message the string to log
+   */
+  public abstract void fail(String message);
+
+  /**
+   * Checks that the given condition is true.  If it is not, this
+   * method does a traceback and exits.  All calls to this method
+   * must be guarded by <code>VM.VERIFY_ASSERTIONS</code>.
+   *
+   * @param cond the condition to be checked
+   */
+  public abstract void _assert(boolean cond);
+
+  /**
+   * Checks that the given condition is true.  If it is not, this
+   * method prints a message, does a traceback and exits. All calls
+   * to this method must be guarded by <code>VM.VERIFY_ASSERTIONS</code>.
+   *
+   * @param cond the condition to be checked
+   * @param message the message to print
+   */
+  public abstract void _assert(boolean cond, String message);
+
+  /**
+   * Print a stack trace
+   */
+  public abstract void dumpStack();
+
+  /**
+   * Checks if the virtual machine is running.  This value changes, so
+   * the call-through to the VM must be a method.  In Jikes RVM, just
+   * returns VM.runningVM.
+   *
+   * @return <code>true</code> if the virtual machine is running
+   */
+  public abstract boolean runningVM();
+
+  /*
+   * NOTE: The following methods must be implemented by subclasses of this
+   * class, but are internal to the VM<->MM interface glue, so are never
+   * called by MMTk users.
+   */
+   /** @return true if assertions should be verified */
+  protected abstract boolean getVerifyAssertionsConstant();
+
+  /*
+   * NOTE: This method should not be called by anything other than the
+   * reflective mechanisms in org.mmtk.vm.VM, and is not implemented by
+   * subclasses.
+   *
+   * This hack exists only to allow us to declare getVerifyAssertions() as
+   * a protected method.
+   */
+  static boolean verifyAssertionsTrapdoor(Assert a) {
+    return a.getVerifyAssertionsConstant();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Barriers.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Barriers.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Barriers.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Barriers.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,149 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.*;
+
+ at Uninterruptible
+public abstract class Barriers {
+  /**
+   * Sets an element of an object array without invoking any write
+   * barrier.  This method is called by the Map class to ensure
+   * potentially-allocation-triggering write barriers do not occur in
+   * allocation slow path code.
+   *
+   * @param dst the destination array
+   * @param index the index of the element to set
+   * @param value the new value for the element
+   */
+  public abstract void setArrayNoBarrier(Object [] dst, int index, Object value);
+
+  /**
+   * Perform the actual write of the write barrier.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param target The value that the slot will be updated to
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   */
+  public abstract void performWriteInBarrier(ObjectReference ref, Address slot,
+                                             ObjectReference target, Word metaDataA,
+                                             Word metaDataB, int mode);
+
+  /**
+   * Perform the actual write of the write barrier, writing the value as a raw Word.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param rawTarget The value that the slot will be updated to
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   */
+  public abstract void performRawWriteInBarrier(ObjectReference ref, Address slot,
+                                                Word rawTarget, Word metaDataA,
+                                                Word metaDataB, int mode);
+
+  /**
+   * Perform the actual read of the read barrier.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   * @return the read value
+   */
+  public abstract ObjectReference performReadInBarrier(ObjectReference ref, Address slot,
+                                                       Word metaDataA, Word metaDataB, int mode);
+
+  /**
+   * Perform the actual read of the read barrier, returning the value as a raw Word.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   * @return the read value
+   */
+  public abstract Word performRawReadInBarrier(ObjectReference ref, Address slot,
+                                               Word metaDataA, Word metaDataB, int mode);
+
+  /**
+   * Atomically write a reference field of an object or array and return
+   * the old value of the reference field.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param target The value that the slot will be updated to
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   * @return The value that was replaced by the write.
+   */
+  public abstract ObjectReference performWriteInBarrierAtomic(ObjectReference ref, Address slot,
+                                                              ObjectReference target, Word metaDataA,
+                                                              Word metaDataB, int mode);
+
+  /**
+   * Atomically write a reference field of an object or array and return
+   * the old value of the reference field.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param rawTarget The raw value that the slot will be updated to
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   * @return The raw value that was replaced by the write.
+   */
+  public abstract Word performRawWriteInBarrierAtomic(ObjectReference ref, Address slot,
+                                                      Word rawTarget, Word metaDataA,
+                                                      Word metaDataB, int mode);
+
+  /**
+   * Attempt an atomic compare and exchange in a write barrier sequence.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param old The old reference to be swapped out
+   * @param target The value that the slot will be updated to
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   * @return True if the compare and swap was successful
+   */
+  public abstract boolean tryCompareAndSwapWriteInBarrier(ObjectReference ref, Address slot,
+                                                          ObjectReference old, ObjectReference target,
+                                                          Word metaDataA, Word metaDataB, int mode);
+
+  /**
+   * Attempt an atomic compare and exchange in a write barrier sequence.
+   *
+   * @param ref The object that has the reference field
+   * @param slot The slot that holds the reference
+   * @param rawOld The old reference to be swapped out
+   * @param rawTarget The value that the slot will be updated to
+   * @param metaDataA VM specific meta data
+   * @param metaDataB VM specific meta data
+   * @param mode The context in which the write is occuring
+   * @return True if the compare and swap was successful
+   */
+  public abstract boolean tryRawCompareAndSwapWriteInBarrier(ObjectReference ref, Address slot,
+                                                             Word rawOld, Word rawTarget,
+                                                             Word metaDataA, Word metaDataB, int mode);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/BuildTimeConfig.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/BuildTimeConfig.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/BuildTimeConfig.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/BuildTimeConfig.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,69 @@
+/*
+ *  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.mmtk.vm;
+
+/**
+ * Build-time configuration constants for MMTk.
+ */
+public abstract class BuildTimeConfig {
+
+  /**
+   * @return The name of the current MMTk plan
+   */
+  public abstract String getPlanName();
+
+  /**
+   * Return a property of type String
+   * @param name The name of the property
+   * @return The value of the property
+   */
+  public abstract String getStringProperty(String name);
+
+  /**
+   * Return a property of type String, with default.
+   * @param name The name of the property
+   * @param dflt Default value
+   * @return The value of the property
+   */
+  public abstract String getStringProperty(String name, String dflt);
+
+  /**
+   * Return a property of type int
+   * @param name The name of the property
+   * @return The value of the property
+   */
+  public abstract int getIntProperty(String name);
+
+  /**
+   * Return a property of type String, with default.
+   * @param name The name of the property
+   * @param dflt Default value
+   * @return The value of the property
+   */
+  public abstract int getIntProperty(String name, int dflt);
+
+  /**
+   * Return a property of type boolean
+   * @param name The name of the property
+   * @return The value of the property
+   */
+  public abstract boolean getBooleanProperty(String name);
+
+  /**
+   * Return a property of type boolean, with default.
+   * @param name The name of the property
+   * @param dflt Default value
+   * @return The value of the property
+   */
+  public abstract boolean getBooleanProperty(String name, boolean dflt);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Collection.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Collection.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Collection.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Collection.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,160 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.plan.CollectorContext;
+import org.mmtk.plan.MutatorContext;
+
+import org.vmmagic.pragma.*;
+
+ at Uninterruptible public abstract class Collection {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+
+  /**
+   * An unknown GC trigger reason. Signals a logic bug.
+   */
+  public static final int UNKNOWN_GC_TRIGGER = 0;
+
+  /**
+   * Concurrent collection phase trigger.
+   */
+  public static final int INTERNAL_PHASE_GC_TRIGGER = 1;
+
+  /**
+   * Externally triggered garbage collection (eg call to System.gc())
+   */
+  public static final int EXTERNAL_GC_TRIGGER = 2;
+
+  /**
+   * Resource triggered garbage collection.  For example, an
+   * allocation request would take the number of pages in use beyond
+   * the number available.
+   */
+  public static final int RESOURCE_GC_TRIGGER = 3;
+
+  /**
+   * Internally triggered garbage collection.  For example, the memory
+   * manager attempting another collection after the first failed to
+   * free space.
+   */
+  public static final int INTERNAL_GC_TRIGGER = 4;
+
+  /**
+   * The number of garbage collection trigger reasons.
+   */
+  public static final int TRIGGER_REASONS = 5;
+
+  /** Short descriptions of the garbage collection trigger reasons. */
+  protected static final String[] triggerReasons = {
+    "unknown",
+    "concurrent phase",
+    "external request",
+    "resource exhaustion",
+    "internal request"
+  };
+
+  /**
+   * Triggers a collection.
+   *
+   * @param why the reason why a collection was triggered.  0 to
+   *          <code>TRIGGER_REASONS - 1</code>.
+   */
+  @Unpreemptible
+  public abstract void triggerCollection(int why);
+
+  /**
+   * Joins an already requested collection.
+   */
+  @Unpreemptible
+  public abstract void joinCollection();
+
+  /**
+   * Trigger an asynchronous collection, checking for memory
+   * exhaustion first.
+   *
+   * @param why the reason why a collection was triggered.  0 to
+   *          <code>TRIGGER_REASONS - 1</code>.
+   */
+  public abstract void triggerAsyncCollection(int why);
+
+  /**
+   * The maximum number collection attempts across threads.
+   */
+  public abstract int maximumCollectionAttempt();
+
+  /**
+   * Report that the allocation has succeeded.
+   */
+  public abstract void reportAllocationSuccess();
+
+  /**
+   * Report that a physical allocation has failed.
+   */
+  public abstract void reportPhysicalAllocationFailed();
+
+  /**
+   * Does the VM consider this an emergency alloction, where the normal
+   * heap size rules can be ignored.
+   */
+  public abstract boolean isEmergencyAllocation();
+
+  /**
+   * Determine whether a collection cycle has fully completed (this is
+   * used to ensure a GC is not in the process of completing, to
+   * avoid, for example, an async GC being triggered on the switch
+   * from GC to mutator thread before all GC threads have switched.
+   *
+   * @return True if GC is not in progress.
+   */
+  public abstract boolean noThreadsInGC();
+
+  /**
+   * Prepare a mutator for collection.
+   *
+   * @param m the mutator to prepare
+   */
+  public abstract void prepareMutator(MutatorContext m);
+
+  /**
+   * Prepare a collector for a collection.
+   *
+   * @param c the collector to prepare
+   */
+  public abstract void prepareCollector(CollectorContext c);
+
+  /**
+   * Rendezvous with all other processors, returning the rank
+   * (that is, the order this processor arrived at the barrier).
+   */
+  public abstract int rendezvous(int where);
+
+  /** @return The number of active collector threads */
+  public abstract int activeGCThreads();
+
+  /**
+   * @return The ordinal ID of the running collector thread w.r.t.
+   * the set of active collector threads (zero based)
+   */
+  public abstract int activeGCThreadOrdinal();
+
+  /**
+   * Request each mutator flush remembered sets. This method
+   * will trigger the flush and then yield until all processors have
+   * flushed.
+   */
+  public abstract void requestMutatorFlush();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Config.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Config.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Config.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Config.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,43 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.statistics.Xml;
+
+public class Config {
+  /* The name of the active plan */
+  private final String ACTIVE_PLAN;
+
+  /** Mark bit in the header or on the side ? */
+  public final boolean HEADER_MARK_BITS;
+
+  Config(BuildTimeConfig config) {
+    ACTIVE_PLAN            = config.getPlanName();
+    HEADER_MARK_BITS        = config.getBooleanProperty("mmtk.headerMarkBit",true);
+  }
+
+  public void printConfig() {
+    Log.writeln("================ MMTk Configuration ================");
+    Log.write("plan = "); Log.writeln(ACTIVE_PLAN);
+    Log.write("HEADER_MARK_BITS = ");  Log.writeln(HEADER_MARK_BITS);
+    Log.writeln("====================================================");
+  }
+
+  public void printConfigXml() {
+    Log.writeln("<config>");
+    Xml.configItem("plan",ACTIVE_PLAN);
+    Xml.configItem("header-mark-bit",HEADER_MARK_BITS);
+    Log.writeln("</config>");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Debug.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Debug.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Debug.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Debug.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,89 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Address;
+import org.vmmagic.unboxed.ObjectReference;
+
+/**
+ *
+ */
+ at Uninterruptible
+public abstract class Debug {
+  /**
+   * Global switch for debugging - if false the other methods of this
+   * class are never called.
+   * @return Whether debugging is enabled
+   */
+  public abstract boolean isEnabled();
+
+  /**
+   * A modbuf (object remembering barrier) entry has been
+   * traced during collection.
+   * @param object
+   */
+  public void modbufEntry(ObjectReference object) { }
+
+  /**
+   * A remset (slot remembering barrier) entry has been
+   * traced during collection.
+   * @param slot
+   */
+  public void remsetEntry(Address slot) { }
+
+  /**
+   * An array remset entry has been traced during collection.  Implicitly
+   * the slots from start (inclusive) through to guard (non-inclusive)
+   * are traced as remset entries
+   * @param start
+   * @param guard
+   */
+  public void arrayRemsetEntry(Address start, Address guard) { }
+
+  /**
+   * A global GC collection phase
+   * @param phaseId The phase ID
+   * @param before true at the start of the phase, false at the end
+   */
+  public void globalPhase(short phaseId, boolean before) { }
+
+  /**
+   * A per-collector GC collection phase
+   * @param phaseId The phase ID
+   * @param ordinal The collector ID (within this collection)
+   * @param before true at the start of the phase, false at the end
+   */
+  public void collectorPhase(short phaseId, int ordinal, boolean before) { }
+
+  /**
+   * A per-mutator GC collection phase
+   * @param phaseId The phase ID
+   * @param ordinal The mutator ID
+   * @param before true at the start of the phase, false at the end
+   */
+  public void mutatorPhase(short phaseId, int ordinal, boolean before) { }
+
+  /*
+   * NOTE: These methods should not be called by anything other than the
+   * reflective mechanisms in org.mmtk.vm.VM, and are not implemented by
+   * subclasses.
+   *
+   * This hack exists only to allow us to declare the respective
+   * methods as protected.
+   */
+  static final boolean isEnabledTrapdoor(Debug d) {
+    return d.isEnabled();
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Factory.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Factory.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Factory.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Factory.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,347 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmutil.options.OptionSet;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.mmtk.vm.gcspy.ByteStream;
+import org.mmtk.vm.gcspy.IntStream;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.vm.gcspy.ServerSpace;
+import org.mmtk.vm.gcspy.ShortStream;
+import org.mmtk.vm.gcspy.Util;
+
+/**
+ * This class defines factory methods for VM-specific types which must
+ * be instantiated within MMTk.  Since the concrete type is defined at
+ * build time, we leave it to a concrete vm-specific instance of this class
+ * to perform the object instantiation.
+ */
+public abstract class Factory {
+
+  /**
+   * Create or retrieve the OptionSet used for MMTk options.
+   *
+   * @return A concrete VM-specific OptionSet instance
+   */
+  public abstract OptionSet getOptionSet();
+
+  /**
+   * Create a new ActivePlan instance using the appropriate VM-specific
+   * concrete ActivePlan sub-class.
+   *
+   * @see ActivePlan
+   * @return A concrete VM-specific ActivePlan instance.
+   */
+  public abstract ActivePlan newActivePlan();
+
+  /**
+   * Create a new Assert instance using the appropriate VM-specific
+   * concrete Assert sub-class.
+   *
+   * @see Assert
+   * @return A concrete VM-specific Assert instance.
+   */
+  public abstract Assert newAssert();
+
+  /**
+   * Create a new Barriers instance using the appropriate VM-specific
+   * concrete Barriers sub-class.
+   *
+   * @see Barriers
+   * @return A concrete VM-specific Barriers instance.
+   */
+  public abstract Barriers newBarriers();
+
+  /**
+   * Create a new Collection instance using the appropriate VM-specific
+   * concrete Collection sub-class.
+   *
+   * @see Collection
+   * @return A concrete VM-specific Collection instance.
+   */
+  public abstract Collection newCollection();
+
+  /**
+   * Create a new Config instance using the appropriate VM-specific
+   * concrete Config sub-class.
+   *
+   * @see Collection
+   * @return A concrete VM-specific Collection instance.
+   */
+  public abstract BuildTimeConfig newBuildTimeConfig();
+
+  /**
+   * Create a new Lock instance using the appropriate VM-specific
+   * concrete Lock sub-class.
+   *
+   * @see Lock
+   * @param name The string to be associated with this lock instance
+   * @return A concrete VM-specific Lock instance.
+   */
+  public abstract Lock newLock(String name);
+
+  /**
+   * Create a new Memory instance using the appropriate VM-specific
+   * concrete Memory sub-class.
+   *
+   * @see Memory
+   * @return A concrete VM-specific Memory instance.
+   */
+  public abstract Memory newMemory();
+
+  /**
+   * Create a new ObjectModel instance using the appropriate VM-specific
+   * concrete ObjectModel sub-class.
+   *
+   * @see ObjectModel
+   * @return A concrete VM-specific ObjectModel instance.
+   */
+  public abstract ObjectModel newObjectModel();
+
+  /**
+   * Create a new ReferenceProcessor instance using the appropriate VM-specific
+   * concrete ReferenceProcessor sub-class.
+   *
+   * @see ReferenceProcessor
+   * @return A concrete VM-specific ReferenceProcessor instance.
+   */
+  public abstract ReferenceProcessor newReferenceProcessor(ReferenceProcessor.Semantics semantics);
+
+
+  /**
+   * Create a new FinalizbleProcessor instance using the appropriate VM-specific
+   * concrete FinalizableProcessor sub-class.
+   *
+   * @see FinalizableProcessor
+   * @return A concrete VM-specific FinalizableProcessor instance.
+   */
+  public abstract FinalizableProcessor newFinalizableProcessor();
+
+  /**
+   * Create a new Scanning instance using the appropriate VM-specific
+   * concrete Scanning sub-class.
+   *
+   * @see Scanning
+   * @return A concrete VM-specific Scanning instance.
+   */
+  public abstract Scanning newScanning();
+
+  /**
+   * Create a new Statistics instance using the appropriate VM-specific
+   * concrete Statistics sub-class.
+   *
+   * @see Statistics
+   * @return A concrete VM-specific Statistics instance.
+   */
+  public abstract Statistics newStatistics();
+
+  /**
+   * Create a new Strings instance using the appropriate VM-specific
+   * concrete Strings sub-class.
+   *
+   * @see Strings
+   * @return A concrete VM-specific Strings instance.
+   */
+  public abstract Strings newStrings();
+
+  /**
+   * Create a new SynchronizedCounter instance using the appropriate
+   * VM-specific concrete SynchronizedCounter sub-class.
+   *
+   * @see SynchronizedCounter
+   *
+   * @return A concrete VM-specific SynchronizedCounter instance.
+   */
+  public abstract SynchronizedCounter newSynchronizedCounter();
+
+  /**
+   * Create a new TraceInterface instance using the appropriate VM-specific
+   * concrete TraceInterface sub-class.
+   *
+   * @see TraceInterface
+   * @return A concrete VM-specific TraceInterface instance.
+   */
+  public abstract TraceInterface newTraceInterface();
+
+  /**
+   * Create a new MMTk_Events instance using the appropriate VM-specific
+   * concrete MMTk_Events sub-class.
+   */
+  public abstract MMTk_Events newEvents();
+
+  /**
+   * Create a new debug object
+   */
+  public abstract Debug newDebug();
+
+  /**********************************************************************
+   * GCspy methods
+   */
+
+  /**
+   * Create a new Util instance using the appropriate VM-specific
+   * concrete Util sub-class.
+   *
+   * @see Util
+   * @return A concrete VM-specific Util instance.
+   */
+  public abstract Util newGCspyUtil();
+
+  /**
+   * Create a new ServerInterpreter instance using the appropriate VM-specific
+   * concrete ServerInterpreter sub-class.
+   *
+   * @see ServerInterpreter
+   * @return A concrete VM-specific ServerInterpreter instance.
+   */
+  public abstract ServerInterpreter newGCspyServerInterpreter();
+
+  /**
+   * Create a new ServerSpace instance using the appropriate VM-specific
+   * concrete ServerSpace sub-class.
+   *
+   * @param serverInterpreter The server that owns this space
+   * @param serverName The server's name
+   * @param driverName The space driver's name
+   * @param title Title for the space
+   * @param blockInfo A label for each block
+   * @param tileNum Max number of tiles in this space
+   * @param unused A label for unused blocks
+   * @param mainSpace Whether this space is the main space
+   *
+   * @see ServerSpace
+   * @return A concrete VM-specific ServerSpace instance.
+   */
+  public abstract ServerSpace newGCspyServerSpace(
+      ServerInterpreter serverInterpreter,
+      String serverName,
+      String driverName,
+      String title,
+      String blockInfo,
+      int tileNum,
+      String unused,
+      boolean mainSpace);
+
+  /**
+   * Create a new IntStream instance using the appropriate
+   * VM-specific concrete IntStream sub-class.
+   *
+   * @param driver        The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   * @see IntStream
+   *
+   * @return A concrete VM-specific IntStream instance.
+   */
+  public abstract IntStream newGCspyIntStream(
+      AbstractDriver driver,
+      String name,
+      int minValue,
+      int maxValue,
+      int zeroValue,
+      int defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary);
+
+  /**
+   * Create a new ByteStream instance using the appropriate
+   * VM-specific concrete ByteStream sub-class.
+   *
+   * @param driver        The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   * @see IntStream
+   *
+   * @return A concrete VM-specific ByteStream instance.
+   */
+  public abstract ByteStream newGCspyByteStream(
+      AbstractDriver driver,
+      String name,
+      byte minValue,
+      byte maxValue,
+      byte zeroValue,
+      byte defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary);
+
+  /**
+   * Create a new ShortStream instance using the appropriate
+   * VM-specific concrete ShortStream sub-class.
+   *
+   * @param driver        The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   * @see IntStream
+   *
+   * @return A concrete VM-specific ShortStream instance.
+   */
+  public abstract ShortStream newGCspyShortStream(
+      AbstractDriver driver,
+      String name,
+      short minValue,
+      short maxValue,
+      short zeroValue,
+      short defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/FinalizableProcessor.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/FinalizableProcessor.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/FinalizableProcessor.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/FinalizableProcessor.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.plan.TraceLocal;
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * This class manages finalizable objects.
+ */
+ at Uninterruptible
+public abstract class FinalizableProcessor {
+
+  /**
+   * Clear the contents of the table. This is called when finalization is
+   * disabled to make it easier for VMs to change this setting at runtime.
+   */
+  public abstract void clear();
+
+  /**
+   * Scan through the list of references.
+   *
+   * @param trace the thread local trace element.
+   * @param nursery true if it is safe to only scan new references.
+   */
+  public abstract void scan(TraceLocal trace, boolean nursery);
+
+  /**
+   * Iterate over and forward entries in the table.
+   */
+  public abstract void forward(TraceLocal trace, boolean nursery);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Lock.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Lock.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Lock.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Lock.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,47 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * Simple, fair locks with deadlock detection.
+ */
+ at Uninterruptible public abstract class Lock {
+
+  /**
+   * Set the name of this lock instance
+   *
+   * @param str The name of the lock (for error output).
+   */
+  public abstract void setName(String str);
+
+
+  /**
+   * Try to acquire a lock and spin-wait until acquired.
+   */
+  public abstract void acquire();
+
+  /**
+   * Perform sanity checks on the lock. For debugging.
+   *
+   * @param w Identifies the code location in the debugging output.
+   */
+  public abstract void check(int w);
+
+  /**
+   * Release the lock by incrementing serving counter.
+   */
+  public abstract void release();
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/MMTk_Events.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/MMTk_Events.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/MMTk_Events.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/MMTk_Events.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,32 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.policy.Space;
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Address;
+import org.vmmagic.unboxed.Extent;
+
+/**
+ * Event generation interface for MMTk.
+ */
+ at Uninterruptible
+public abstract class MMTk_Events {
+  public abstract void tracePageAcquired(Space space, Address startAddress, int numPages);
+
+  public abstract void tracePageReleased(Space space, Address startAddress, int numPages);
+
+  public abstract void heapSizeChanged(Extent heapSize);
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Memory.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Memory.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Memory.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Memory.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,211 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.policy.ImmortalSpace;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+ at Uninterruptible public abstract class Memory {
+
+  /**
+   * Allows for the VM to reserve space between HEAP_START()
+   * and AVAILABLE_START() for its own purposes.  MMTk should
+   * expect to encounter objects in this range, but may not
+   * allocate in this range.
+   *
+   * MMTk expects the virtual address space between AVAILABLE_START()
+   * and AVAILABLE_END() to be contiguous and unmapped.
+   * Allows for the VM to reserve space between HEAP_END()
+   * and AVAILABLE_END() for its own purposes.  MMTk should
+   * expect to encounter objects in this range, but may not
+   * allocate in this range.
+   *
+   * MMTk expects the virtual address space between AVAILABLE_START()
+   * and AVAILABLE_END() to be contiguous and unmapped.
+   *
+   * @return The high bound of the memory that MMTk can allocate.
+   */
+
+  /**
+   * Return the space associated with/reserved for the VM.  In the
+   * case of Jikes RVM this is the boot image space.<p>
+   *
+   * @return The space managed by the virtual machine.
+   */
+  @Interruptible
+  public abstract ImmortalSpace getVMSpace();
+
+  /** Global preparation for a collection. */
+  public abstract void globalPrepareVMSpace();
+
+  /** Per-collector preparation for a collection. */
+  public abstract void collectorPrepareVMSpace();
+
+  /** Per-collector post-collection work. */
+  public abstract void collectorReleaseVMSpace();
+
+  /** Global post-collection work. */
+  public abstract void globalReleaseVMSpace();
+
+  /**
+   * Sets the range of addresses associated with a heap.
+   *
+   * @param id the heap identifier
+   * @param start the address of the start of the heap
+   * @param end the address of the end of the heap
+   */
+  public abstract void setHeapRange(int id, Address start, Address end);
+
+  /**
+   * Demand zero mmaps an area of virtual memory.
+   *
+   * @param start the address of the start of the area to be mapped
+   * @param size the size, in bytes, of the area to be mapped
+   * @return 0 if successful, otherwise the system errno
+   */
+  public abstract int dzmmap(Address start, int size);
+
+  /**
+   * Protects access to an area of virtual memory.
+   *
+   * @param start the address of the start of the area to be mapped
+   * @param size the size, in bytes, of the area to be mapped
+   * @return <code>true</code> if successful, otherwise
+   * <code>false</code>
+   */
+  public abstract boolean mprotect(Address start, int size);
+
+  /**
+   * Allows access to an area of virtual memory.
+   *
+   * @param start the address of the start of the area to be mapped
+   * @param size the size, in bytes, of the area to be mapped
+   * @return <code>true</code> if successful, otherwise
+   * <code>false</code>
+   */
+  public abstract boolean munprotect(Address start, int size);
+
+  /**
+   * Zero a region of memory.
+   * @param start Start of address range (inclusive)
+   * @param len Length in bytes of range to zero
+   * Returned: nothing
+   */
+  public abstract void zero(Address start, Extent len);
+
+  /**
+   * Zero a range of pages of memory.
+   * @param start Start of address range (must be a page address)
+   * @param len Length in bytes of range (must be multiple of page size)
+   */
+  public abstract void zeroPages(Address start, int len);
+
+  /**
+   * Logs the contents of an address and the surrounding memory to the
+   * error output.
+   *
+   * @param start the address of the memory to be dumped
+   * @param beforeBytes the number of bytes before the address to be
+   * included
+   * @param afterBytes the number of bytes after the address to be
+   * included
+   */
+  public abstract void dumpMemory(Address start, int beforeBytes,
+      int afterBytes);
+
+  /**
+   * Wait for preceeding cache flush/invalidate instructions to complete
+   * on all processors.  Ensures that all memory writes before this
+   * point are visible to all processors.
+   */
+  @Inline
+  public abstract void sync();
+
+  /**
+   * Wait for all preceeding instructions to complete and discard any
+   * prefetched instructions on this processor.  Also prevents the
+   * compiler from performing code motion across this point.
+   */
+  @Inline
+  public abstract void isync();
+
+  /*
+   * NOTE: The following methods must be implemented by subclasses of this
+   * class, but are internal to the VM<->MM interface glue, so are never
+   * called by MMTk users.
+   */
+  /** @return The lowest address in the virtual address space known to MMTk */
+  protected abstract Address getHeapStartConstant();
+  /** @return The highest address in the virtual address space known to MMTk */
+  protected abstract Address getHeapEndConstant();
+  /** @return The lowest address in the contiguous address space available to MMTk  */
+  protected abstract Address getAvailableStartConstant();
+  /** @return The highest address in the contiguous address space available to MMTk */
+  protected abstract Address getAvailableEndConstant();
+  /** @return The log base two of the size of an address */
+  protected abstract byte getLogBytesInAddressConstant();
+  /** @return The log base two of the size of a word */
+  protected abstract byte getLogBytesInWordConstant();
+  /** @return The log base two of the size of an OS page */
+  protected abstract byte getLogBytesInPageConstant();
+  /** @return The log base two of the minimum allocation alignment */
+  protected abstract byte getLogMinAlignmentConstant();
+  /** @return The log base two of (MAX_ALIGNMENT/MIN_ALIGNMENT) */
+  protected abstract byte getMaxAlignmentShiftConstant();
+  /** @return The maximum number of bytes of padding to prepend to an object */
+  protected abstract int getMaxBytesPaddingConstant();
+  /** @return The value to store in alignment holes */
+  protected abstract int getAlignmentValueConstant();
+
+  /*
+   * NOTE: These methods should not be called by anything other than the
+   * reflective mechanisms in org.mmtk.vm.VM, and are not implemented by
+   * subclasses. This hack exists only to allow us to declare the respective
+   * methods as protected.
+   */
+  static Address heapStartTrapdoor(Memory m) {
+    return m.getHeapStartConstant();
+  }
+  static Address heapEndTrapdoor(Memory m) {
+    return m.getHeapEndConstant();
+  }
+  static Address availableStartTrapdoor(Memory m) {
+    return m.getAvailableStartConstant();
+  }
+  static Address availableEndTrapdoor(Memory m) {
+    return m.getAvailableEndConstant();
+  }
+  static byte logBytesInAddressTrapdoor(Memory m) {
+    return m.getLogBytesInAddressConstant();
+  }
+  static byte logBytesInWordTrapdoor(Memory m) {
+    return m.getLogBytesInWordConstant();
+  }
+  static byte logBytesInPageTrapdoor(Memory m) {
+    return m.getLogBytesInPageConstant();
+  }
+  static byte logMinAlignmentTrapdoor(Memory m) {
+    return m.getLogMinAlignmentConstant();
+  }
+  static byte maxAlignmentShiftTrapdoor(Memory m) {
+    return m.getMaxAlignmentShiftConstant();
+  }
+  static int maxBytesPaddingTrapdoor(Memory m) {
+    return m.getMaxBytesPaddingConstant();
+  }
+  static int alignmentValueTrapdoor(Memory m) {
+    return m.getAlignmentValueConstant();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/ObjectModel.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/ObjectModel.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/ObjectModel.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/ObjectModel.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,256 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.*;
+
+ at Uninterruptible public abstract class ObjectModel {
+  /**
+   * Copy an object using a plan's allocCopy to get space and install
+   * the forwarding pointer.  On entry, <code>from</code> must have
+   * been reserved for copying by the caller.  This method calls the
+   * plan's <code>getStatusForCopy()</code> method to establish a new
+   * status word for the copied object and <code>postCopy()</code> to
+   * allow the plan to perform any post copy actions.
+   *
+   * @param from the address of the object to be copied
+   * @param allocator The allocator to use.
+   * @return the address of the new object
+   */
+  public abstract ObjectReference copy(ObjectReference from, int allocator);
+
+  /**
+   * Copy an object to be pointer to by the to address. This is required
+   * for delayed-copy collectors such as compacting collectors. During the
+   * collection, MMTk reserves a region in the heap for an object as per
+   * requirements found from ObjectModel and then asks ObjectModel to
+   * determine what the object's reference will be post-copy.
+   *
+   * @param from the address of the object to be copied
+   * @param to The target location.
+   * @param region The start of the region that was reserved for this object
+   * @return Address The address past the end of the copied object
+   */
+  public abstract Address copyTo(ObjectReference from, ObjectReference to, Address region);
+
+  /**
+   * Return the reference that an object will be refered to after it is copied
+   * to the specified region. Used in delayed-copy collectors such as compacting
+   * collectors.
+   *
+   * @param from The object to be copied.
+   * @param to The region to be copied to.
+   * @return The resulting reference.
+   */
+  public abstract ObjectReference getReferenceWhenCopiedTo(ObjectReference from, Address to);
+
+
+  /**
+   * Return the size required to copy an object
+   *
+   * @param object The object whose size is to be queried
+   * @return The size required to copy <code>obj</code>
+   */
+  public abstract int getSizeWhenCopied(ObjectReference object);
+
+  /**
+   * Return the alignment requirement for a copy of this object
+   *
+   * @param object The object whose size is to be queried
+   * @return The alignment required for a copy of <code>obj</code>
+   */
+  public abstract int getAlignWhenCopied(ObjectReference object);
+
+  /**
+   * Return the alignment offset requirements for a copy of this object
+   *
+   * @param object The object whose size is to be queried
+   * @return The alignment offset required for a copy of <code>obj</code>
+   */
+  public abstract int getAlignOffsetWhenCopied(ObjectReference object);
+
+
+  /**
+   * Return the size used by an object
+   *
+   * @param object The object whose size is to be queried
+   * @return The size of <code>obj</code>
+   */
+  public abstract int getCurrentSize(ObjectReference object);
+
+  /**
+   * Return the next object in the heap under contiguous allocation
+   */
+  public abstract ObjectReference getNextObject(ObjectReference object);
+
+  /**
+   * Return an object reference from knowledge of the low order word
+   */
+  public abstract ObjectReference getObjectFromStartAddress(Address start);
+  /**
+   * Gets a pointer to the address just past the end of the object.
+   *
+   * @param object The objecty.
+   */
+  public abstract Address getObjectEndAddress(ObjectReference object);
+
+
+  /**
+   * Get the type descriptor for an object.
+   *
+   * @param ref address of the object
+   * @return byte array with the type descriptor
+   */
+  public abstract byte[] getTypeDescriptor(ObjectReference ref);
+
+  /**
+   * Is the passed object an array?
+   *
+   * @param object address of the object
+   */
+  public abstract boolean isArray(ObjectReference object);
+
+  /**
+   * Is the passed object a primitive array?
+   *
+   * @param object address of the object
+   */
+  public abstract boolean isPrimitiveArray(ObjectReference object);
+
+  /**
+   * Get the length of an array object.
+   *
+   * @param object address of the object
+   * @return The array length, in elements
+   */
+  public abstract int getArrayLength(ObjectReference object);
+
+  /**
+   * Attempts to set the bits available for memory manager use in an
+   * object.  The attempt will only be successful if the current value
+   * of the bits matches <code>oldVal</code>.  The comparison with the
+   * current value and setting are atomic with respect to other
+   * allocators.
+   *
+   * @param object the address of the object
+   * @param oldVal the required current value of the bits
+   * @param newVal the desired new value of the bits
+   * @return <code>true</code> if the bits were set,
+   * <code>false</code> otherwise
+   */
+  public abstract boolean attemptAvailableBits(ObjectReference object,
+      Word oldVal, Word newVal);
+
+  /**
+   * Gets the value of bits available for memory manager use in an
+   * object, in preparation for setting those bits.
+   *
+   * @param object the address of the object
+   * @return the value of the bits
+   */
+  public abstract Word prepareAvailableBits(ObjectReference object);
+
+  /**
+   * Sets the byte available for memory manager use in an object.
+   *
+   * @param object the address of the object
+   * @param val the new value of the byte
+   */
+  public abstract void writeAvailableByte(ObjectReference object, byte val);
+  /**
+   * Read the byte available for memory manager use in an object.
+   *
+   * @param object the address of the object
+   * @return the value of the byte
+   */
+  public abstract byte readAvailableByte(ObjectReference object);
+
+  /**
+   * Sets the bits available for memory manager use in an object.
+   *
+   * @param object the address of the object
+   * @param val the new value of the bits
+   */
+  public abstract void writeAvailableBitsWord(ObjectReference object, Word val);
+  /**
+   * Read the bits available for memory manager use in an object.
+   *
+   * @param object the address of the object
+   * @return the value of the bits
+   */
+  public abstract Word readAvailableBitsWord(ObjectReference object);
+
+  /**
+   * Gets the offset of the memory management header from the object
+   * reference address.  XXX The object model / memory manager
+   * interface should be improved so that the memory manager does not
+   * need to know this.
+   *
+   * @return the offset, relative the object reference address
+   */
+  public abstract Offset GC_HEADER_OFFSET();
+
+  /**
+   * Returns the lowest address of the storage associated with an object.
+   *
+   * @param object the reference address of the object
+   * @return the lowest address of the object
+   */
+  public abstract Address objectStartRef(ObjectReference object);
+
+  /**
+   * Returns an address guaranteed to be inside the storage assocatied
+   * with and object.
+   *
+   * @param object the reference address of the object
+   * @return an address inside the object
+   */
+  public abstract Address refToAddress(ObjectReference object);
+
+  /**
+   * Checks if a reference of the given type in another object is
+   * inherently acyclic.  The type is given as a TIB.
+   *
+   * @return <code>true</code> if a reference of the type is
+   * inherently acyclic
+   */
+  public abstract boolean isAcyclic(ObjectReference typeRef);
+
+  /**
+   * Dump debugging information for an object.
+   *
+   * @param object The object whose information is to be dumped
+   */
+  public abstract void dumpObject(ObjectReference object);
+
+  /*
+   * NOTE: The following methods must be implemented by subclasses of this
+   * class, but are internal to the VM<->MM interface glue, so are never
+   * called by MMTk users.
+   */
+  /** @return The offset from array reference to element zero */
+  protected abstract Offset getArrayBaseOffset();
+
+  /*
+   * NOTE: These methods should not be called by anything other than the
+   * reflective mechanisms in org.mmtk.vm.VM, and are not implemented by
+   * subclasses.
+   *
+   * This hack exists only to allow us to declare the respective
+   * methods as protected.
+   */
+  static Offset arrayBaseOffsetTrapdoor(ObjectModel o) {
+    return o.getArrayBaseOffset();
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/ReferenceProcessor.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/ReferenceProcessor.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/ReferenceProcessor.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/ReferenceProcessor.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,50 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.plan.TraceLocal;
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * This class manages SoftReferences, WeakReferences, and
+ * PhantomReferences.
+ */
+ at Uninterruptible
+public abstract class ReferenceProcessor {
+
+  public enum Semantics { SOFT, WEAK, PHANTOM }
+
+  /**
+   * Clear the contents of the table. This is called when reference types are
+   * disabled to make it easier for VMs to change this setting at runtime.
+   */
+  public abstract void clear();
+
+  /**
+   * Scan through the list of references.
+   *
+   * @param trace the thread local trace element.
+   * @param nursery true if it is safe to only scan new references.
+   */
+  public abstract void scan(TraceLocal trace, boolean nursery);
+
+  /**
+   * Iterate over all references and forward.
+   */
+  public abstract void forward(TraceLocal trace, boolean nursery);
+
+  /**
+   * @return the number of references objects on the queue
+   */
+  public abstract int countWaitingReferences();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Scanning.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Scanning.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Scanning.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Scanning.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,137 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.plan.TransitiveClosure;
+import org.mmtk.utility.Constants;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.*;
+
+ at Uninterruptible public abstract class Scanning implements Constants {
+  /**
+   * Delegated scanning of a object, processing each pointer field
+   * encountered.
+   *
+   * @param object The object to be scanned.
+   */
+  public abstract void scanObject(TransitiveClosure trace, ObjectReference object);
+
+  /**
+   * Invoke a specialized scan method. Note that these methods must have been allocated
+   * explicitly through Plan and PlanConstraints.
+   *
+   * @param id The specialized method id
+   * @param trace The trace the method has been specialized for
+   * @param object The object to be scanned
+   */
+  public abstract void specializedScanObject(int id, TransitiveClosure trace, ObjectReference object);
+
+  /**
+   * Delegated precopying of a object's children, processing each pointer field
+   * encountered.
+   *
+   * @param trace The trace object to use for precopying.
+   * @param object The object to be scanned.
+   */
+  public abstract void precopyChildren(TraceLocal trace, ObjectReference object);
+
+  /**
+   * Prepares for using the <code>computeAllRoots</code> method.  The
+   * thread counter allows multiple GC threads to co-operatively
+   * iterate through the thread data structure (if load balancing
+   * parallel GC threads were not important, the thread counter could
+   * simply be replaced by a for loop).
+   */
+  public abstract void resetThreadCounter();
+
+  /**
+   * Pre-copy all potentially movable instances used in the course of
+   * GC.  This includes the thread objects representing the GC threads
+   * themselves.  It is crucial that these instances are forwarded
+   * <i>prior</i> to the GC proper.  Since these instances <i>are
+   * not</i> enqueued for scanning, it is important that when roots
+   * are computed the same instances are explicitly scanned and
+   * included in the set of roots.  The existence of this method
+   * allows the actions of calculating roots and forwarding GC
+   * instances to be decoupled.
+   */
+  public abstract void preCopyGCInstances(TraceLocal trace);
+
+  /**
+   * Computes static roots.  This method establishes all such roots for
+   * collection and places them in the root locations queue.  This method
+   * should not have side effects (such as copying or forwarding of
+   * objects).  There are a number of important preconditions:
+   *
+   * <ul>
+   * <li> All objects used in the course of GC (such as the GC thread
+   * objects) need to be "pre-copied" prior to calling this method.
+   * <li> The <code>threadCounter</code> must be reset so that load
+   * balancing parallel GC can share the work of scanning threads.
+   * </ul>
+   *
+   * @param trace The trace to use for computing roots.
+   */
+  public abstract void computeStaticRoots(TraceLocal trace);
+
+  /**
+   * Computes global roots.  This method establishes all such roots for
+   * collection and places them in the root locations queue.  This method
+   * should not have side effects (such as copying or forwarding of
+   * objects).  There are a number of important preconditions:
+   *
+   * <ul>
+   * <li> All objects used in the course of GC (such as the GC thread
+   * objects) need to be "pre-copied" prior to calling this method.
+   * <li> The <code>threadCounter</code> must be reset so that load
+   * balancing parallel GC can share the work of scanning threads.
+   * </ul>
+   *
+   * @param trace The trace to use for computing roots.
+   */
+  public abstract void computeGlobalRoots(TraceLocal trace);
+
+  /**
+   * Computes roots pointed to by threads, their associated registers
+   * and stacks.  This method places these roots in the root values,
+   * root locations and interior root locations queues.  This method
+   * should not have side effects (such as copying or forwarding of
+   * objects).  There are a number of important preconditions:
+   *
+   * <ul>
+   * <li> All objects used in the course of GC (such as the GC thread
+   * objects) need to be "pre-copied" prior to calling this method.
+   * <li> The <code>threadCounter</code> must be reset so that load
+   * balancing parallel GC can share the work of scanning threads.
+   * </ul>
+   *
+   * @param trace The trace to use for computing roots.
+   */
+  public abstract void computeThreadRoots(TraceLocal trace);
+
+  /**
+   * Compute all roots out of the VM's boot image (if any).  This method is a no-op
+   * in the case where the VM does not maintain an MMTk-visible Java space.   However,
+   * when the VM does maintain a space (such as a boot image) which is visible to MMTk,
+   * that space could either be scanned by MMTk as part of its transitive closure over
+   * the whole heap, or as a (considerable) performance optimization, MMTk could avoid
+   * scanning the space if it is aware of all pointers out of that space.  This method
+   * is used to establish the root set out of the scannable space in the case where
+   * such a space exists.
+   *
+   * @param trace The trace object to use to report root locations.
+   */
+  public abstract void computeBootImageRoots(TraceLocal trace);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Statistics.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Statistics.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Statistics.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Statistics.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,79 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+
+ at Uninterruptible public abstract class Statistics {
+  /**
+   * Returns the number of collections that have occurred.
+   *
+   * @return The number of collections that have occurred.
+   */
+  public abstract int getCollectionCount();
+
+  /**
+   * Read cycle counter
+   */
+  public abstract long nanoTime();
+
+  /**
+   * Convert nanoseconds to milliseconds
+   */
+  public abstract double nanosToMillis(long c);
+
+  /**
+   * Convert nanoseconds to seconds
+   */
+  public abstract double nanosToSecs(long c);
+
+  /**
+   * Convert milliseconds to nanoseconds
+   */
+  public abstract long millisToNanos(double t);
+
+  /**
+   * Convert seconds to nanoseconds
+   */
+  public abstract long secsToNanos(double t);
+
+  /**
+   * Read the cycle counter
+   */
+  public abstract long cycles();
+
+  /**
+   * Initialize performance counters
+   *
+   * @param metric An integer identifying the metric being read
+   */
+  public abstract void perfCtrInit(int metric);
+
+  /**
+   * Read the current cycle count from the perfctr libraries
+   *
+   * @return the current cycle count from the perfctr libraries
+   */
+  public abstract long perfCtrReadCycles();
+
+  /**
+   * Read the current event count for the metric being measured by the
+   * perfctr libraries
+   *
+   * @return the current event count for the metric being measured by the
+   * perfctr libraries
+   */
+  public abstract long perfCtrReadMetric();
+
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/Strings.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/Strings.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/Strings.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/Strings.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,51 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+
+ at Uninterruptible public abstract class Strings {
+  /**
+   * Log a message.
+   *
+   * @param c character array with message starting at index 0
+   * @param len number of characters in message
+   */
+  public abstract void write(char [] c, int len);
+
+  /**
+   * Log a thread identifier and a message.
+   *
+   * @param c character array with message starting at index 0
+   * @param len number of characters in message
+   */
+  public abstract void writeThreadId(char [] c, int len);
+
+  /**
+   * Copies characters from the string into the character array.
+   * Thread switching is disabled during this method's execution.
+   * <p>
+   * <b>TODO:</b> There are special memory management semantics here that
+   * someone should document.
+   *
+   * @param src the source string
+   * @param dst the destination array
+   * @param dstBegin the start offset in the desination array
+   * @param dstEnd the index after the last character in the
+   * destination to copy to
+   * @return the number of characters copied.
+   */
+  public abstract int copyStringToChars(String src, char [] dst,
+      int dstBegin, int dstEnd);
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/SynchronizedCounter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/SynchronizedCounter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/SynchronizedCounter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/SynchronizedCounter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,43 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+
+/**
+ * A counter that supports atomic increment and reset.
+ */
+ at Uninterruptible public abstract class SynchronizedCounter {
+
+  /**
+   * Reset the counter to 0, returning its previous value.
+   *
+   * @return The value of the counter, prior to reset.
+   */
+  public abstract int reset();
+
+  /**
+   * Adds 1 to the counter.
+   *
+   * @return the value before the add
+   */
+  public abstract int increment();
+
+  /**
+   * Peek at the counter
+   *
+   * @return The current value of the counter.
+   */
+  public abstract int peek();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/TraceInterface.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/TraceInterface.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/TraceInterface.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/TraceInterface.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,80 @@
+/*
+ *  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.mmtk.vm;
+
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Class that supports scanning Objects or Arrays for references
+ * during tracing, handling those references, and computing death times
+ */
+ at Uninterruptible public abstract class TraceInterface {
+
+
+  /***********************************************************************
+   *
+   * Public Methods
+   */
+
+  /**
+   * Returns if the VM is ready for a garbage collection.
+   *
+   * @return True if the VM is ready for GC, false otherwise.
+   */
+  public abstract boolean gcEnabled();
+
+  /**
+   * This adjusts the offset into an object to reflect what it would look like
+   * if the fields were laid out in memory space immediately after the object
+   * pointer.
+   *
+   * @param isScalar If this is a pointer store to a scalar object
+   * @param src The address of the source object
+   * @param slot The address within <code>src</code> into which
+   * the update will be stored
+   * @return The easy to understand offset of the slot
+   */
+  public abstract Offset adjustSlotOffset(boolean isScalar,
+                                              ObjectReference src,
+                                              Address slot);
+
+  /**
+   * This skips over the frames added by the tracing algorithm, outputs
+   * information identifying the method the containts the "new" call triggering
+   * the allocation, and returns the address of the first non-trace, non-alloc
+   * stack frame.
+   *
+   *@param typeRef The type reference (tib) of the object just allocated
+   * @return The frame pointer address for the method that allocated the object
+   */
+  @Interruptible
+  public abstract Address skipOwnFramesAndDump(ObjectReference typeRef);
+
+  /***********************************************************************
+   *
+   * Wrapper methods
+   */
+  public abstract void updateDeathTime(ObjectReference obj);
+  public abstract void setDeathTime(ObjectReference ref, Word time_);
+  public abstract void setLink(ObjectReference ref, ObjectReference link);
+  public abstract void updateTime(Word time_);
+  public abstract Word getOID(ObjectReference ref);
+  public abstract Word getDeathTime(ObjectReference ref);
+  public abstract ObjectReference getLink(ObjectReference ref);
+  public abstract Address getBootImageLink();
+  public abstract Word getOID();
+  public abstract void setOID(Word oid);
+  public abstract int getHeaderSize();
+  public abstract int getHeaderEndOffset();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/VM.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/VM.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/VM.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/VM.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,386 @@
+/*
+ *  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.mmtk.vm;
+
+import org.mmtk.utility.options.Options;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.mmtk.vm.gcspy.ByteStream;
+import org.mmtk.vm.gcspy.IntStream;
+import org.mmtk.vm.gcspy.ServerInterpreter;
+import org.mmtk.vm.gcspy.ServerSpace;
+import org.mmtk.vm.gcspy.ShortStream;
+import org.mmtk.vm.gcspy.Util;
+import org.vmmagic.pragma.Untraced;
+import org.vmmagic.unboxed.Address;
+import org.vmmagic.unboxed.Offset;
+
+/**
+ * This class is responsible for all VM-specific functionality required
+ * by MMTk.<p>
+ *
+ * The class has three major elements.  First it defines VM-specific
+ * constants which are used throughout MMTk, second, it declares
+ * singleton instances of each of the abstract classes in this
+ * package, and third, it provides factory methods for VM-specific
+ * instances which are needed by MMTk (such as <code>Lock</code>).<p>
+ *
+ * Both the constants and the singleton instances are initialized to
+ * VM-specific values at build time using reflection and a VM-specific
+ * factory class. The system property <code>mmtk.hostjvm</code> is
+ * interrogated at build time to establish concrete instantations of
+ * the abstract classes in this package. By <b>convention</b>,
+ * <code>mmtk.hostjvm</code> will identify a VM-provided package which
+ * includes concrete instances of each of the abstract classes, with
+ * each concrete class having the same base class name (but different
+ * package name) as the abstract classes defined here.  The class
+ * initializer for this class then uses the system property
+ * <code>mmtk.hostjvm</code> to load the VM-specific concrete classes
+ * and initialize the constants and singletons defined here.
+ */
+public final class VM {
+  /*
+   * VM-specific constant values
+   */
+  /** <code>true</code> if assertions should be verified */
+  public static final boolean VERIFY_ASSERTIONS;
+  /** The lowest address in virtual memory known to MMTk */
+  public static final Address HEAP_START;
+  /** The highest address in virtual memory known to MMTk */
+  public static final Address HEAP_END;
+  /** The lowest address in the contiguously available memory available to MMTk */
+  public static final Address AVAILABLE_START;
+  /** The highest address in the contiguously available memory available to MMTk */
+  public static final Address AVAILABLE_END;
+  /** The log base two of the size of an address */
+  public static final byte LOG_BYTES_IN_ADDRESS;
+  /** The log base two of the size of a word */
+  public static final byte LOG_BYTES_IN_WORD;
+  /** The log base two of the size of an OS page */
+  public static final byte LOG_BYTES_IN_PAGE;
+  /** The log base two of the minimum allocation alignment */
+  public static final byte LOG_MIN_ALIGNMENT;
+  /** The log base two of (MAX_ALIGNMENT/MIN_ALIGNMENT) */
+  public static final byte MAX_ALIGNMENT_SHIFT;
+  /** The maximum number of bytes of padding to prepend to an object */
+  public static final int MAX_BYTES_PADDING;
+  /** The value to store in alignment holes */
+  public static final int ALIGNMENT_VALUE;
+  /** The offset from an array reference to element zero */
+  public static final Offset ARRAY_BASE_OFFSET;
+  /** Global debugging switch */
+  public static final boolean DEBUG;
+
+  /*
+   * VM-specific functionality captured in a series of singleton classs
+   */
+  @Untraced
+  public static final ActivePlan activePlan;
+  @Untraced
+  public static final Assert assertions;
+  @Untraced
+  public static final Barriers barriers;
+  @Untraced
+  public static final Collection collection;
+  @Untraced
+  public static final Config config;
+  @Untraced
+  public static final Memory memory;
+  @Untraced
+  public static final ObjectModel objectModel;
+  @Untraced
+  public static final ReferenceProcessor weakReferences;
+  @Untraced
+  public static final ReferenceProcessor softReferences;
+  @Untraced
+  public static final ReferenceProcessor phantomReferences;
+  @Untraced
+  public static final FinalizableProcessor finalizableProcessor;
+  @Untraced
+  public static final Scanning scanning;
+  @Untraced
+  public static final Statistics statistics;
+  @Untraced
+  public static final Strings strings;
+  @Untraced
+  public static final TraceInterface traceInterface;
+  @Untraced
+  public static final MMTk_Events events;
+  @Untraced
+  public static final Debug debugging;
+
+  /*
+   * The remainder is does the static initialization of the
+   * above, reflectively binding to the appropriate host jvm
+   * classes.
+   */
+  private static final Factory factory;
+  private static final String vmFactory;
+
+  /**
+   * This class initializer establishes a VM-specific factory class
+   * using reflection, and then uses that to create VM-specific concrete
+   * instances of all of the vm classes, initializing the singltons in
+   * this class.  Finally the constants declared in this class are
+   * initialized using the VM-specific singletons.
+   */
+  static {
+    /* Identify the VM-specific factory using reflection */
+    vmFactory = System.getProperty("mmtk.hostjvm");
+    Factory xfa = null;
+    try {
+      xfa = (Factory) Class.forName(vmFactory).newInstance();
+    } catch (Exception e) {
+      e.printStackTrace();
+      System.exit(-1);     // we must *not* go on if the above has failed
+    }
+    factory = xfa;
+
+    /* Now instantiate the singletons using the factory */
+    activePlan = factory.newActivePlan();
+    assertions = factory.newAssert();
+    barriers = factory.newBarriers();
+    collection = factory.newCollection();
+    memory = factory.newMemory();
+    objectModel = factory.newObjectModel();
+    Options.set = factory.getOptionSet();
+    weakReferences = factory.newReferenceProcessor(ReferenceProcessor.Semantics.WEAK);
+    softReferences = factory.newReferenceProcessor(ReferenceProcessor.Semantics.SOFT);
+    phantomReferences = factory.newReferenceProcessor(ReferenceProcessor.Semantics.PHANTOM);
+    finalizableProcessor = factory.newFinalizableProcessor();
+    scanning = factory.newScanning();
+    statistics = factory.newStatistics();
+    strings = factory.newStrings();
+    traceInterface = factory.newTraceInterface();
+    events = factory.newEvents();
+    debugging = factory.newDebug();
+    config = new Config(factory.newBuildTimeConfig());
+
+    /* Now initialize the constants using the vm-specific singletons */
+    VERIFY_ASSERTIONS = Assert.verifyAssertionsTrapdoor(assertions);
+    HEAP_START = Memory.heapStartTrapdoor(memory);
+    HEAP_END = Memory.heapEndTrapdoor(memory);
+    AVAILABLE_START = Memory.availableStartTrapdoor(memory);
+    AVAILABLE_END = Memory.availableEndTrapdoor(memory);
+    LOG_BYTES_IN_ADDRESS = Memory.logBytesInAddressTrapdoor(memory);
+    LOG_BYTES_IN_WORD = Memory.logBytesInWordTrapdoor(memory);
+    LOG_BYTES_IN_PAGE = Memory.logBytesInPageTrapdoor(memory);
+    LOG_MIN_ALIGNMENT = Memory.logMinAlignmentTrapdoor(memory);
+    MAX_ALIGNMENT_SHIFT = Memory.maxAlignmentShiftTrapdoor(memory);
+    MAX_BYTES_PADDING = Memory.maxBytesPaddingTrapdoor(memory);
+    ALIGNMENT_VALUE = Memory.alignmentValueTrapdoor(memory);
+    ARRAY_BASE_OFFSET = ObjectModel.arrayBaseOffsetTrapdoor(objectModel);
+    DEBUG = Debug.isEnabledTrapdoor(debugging);
+  }
+
+  /**
+   * Create a new Lock instance using the appropriate VM-specific
+   * concrete Lock sub-class.
+   *
+   * @see Lock
+   *
+   * @param name The string to be associated with this lock instance
+   * @return A concrete VM-specific Lock instance.
+   */
+  public static Lock newLock(String name) {
+    return factory.newLock(name);
+  }
+
+  /**
+   * Create a new SynchronizedCounter instance using the appropriate
+   * VM-specific concrete SynchronizedCounter sub-class.
+   *
+   * @see SynchronizedCounter
+   *
+   * @return A concrete VM-specific SynchronizedCounter instance.
+   */
+  public static SynchronizedCounter newSynchronizedCounter() {
+    return factory.newSynchronizedCounter();
+  }
+
+  /**********************************************************************
+   * GCspy methods
+   */
+
+  /**
+   * Create a new Util instance using the appropriate
+   * VM-specific concrete Util sub-class.
+   *
+   * @see Util
+   *
+   * @return A concrete VM-specific Util instance.
+   */
+  public static Util newGCspyUtil() {
+    return factory.newGCspyUtil();
+  }
+
+  /**
+   * Create a new ServerInterpreter instance using the appropriate
+   * VM-specific concrete ServerInterpreter sub-class.
+   *
+   * @see ServerInterpreter
+   *
+   * @return A concrete VM-specific ServerInterpreter instance.
+   */
+  public static ServerInterpreter newGCspyServerInterpreter() {
+    return factory.newGCspyServerInterpreter();
+  }
+
+  /**
+   * Create a new ServerInterpreter instance using the appropriate
+   * VM-specific concrete ServerInterpreter sub-class.
+   *
+   * @see ServerInterpreter
+   *
+   * @return A concrete VM-specific ServerInterpreter instance.
+   */
+  public static ServerSpace newGCspyServerSpace(
+      ServerInterpreter serverInterpreter,
+      String serverName,
+      String driverName,
+      String title,
+      String blockInfo,
+      int tileNum,
+      String unused,
+      boolean mainSpace) {
+    return factory.newGCspyServerSpace(serverInterpreter, serverName, driverName,
+                                       title, blockInfo, tileNum, unused,
+                                       mainSpace);
+  }
+
+  /**
+   * Create a new ByteStream instance using the appropriate
+   * VM-specific concrete ByteStream sub-class.
+   *
+   * @param driver        The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   * @see IntStream
+   *
+   * @return A concrete VM-specific ByteStream instance.
+   */
+  public static ByteStream newGCspyByteStream(
+      AbstractDriver driver,
+      String name,
+      byte minValue,
+      byte maxValue,
+      byte zeroValue,
+      byte defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary) {
+    return factory.newGCspyByteStream(driver, name, minValue,  maxValue,
+                                     zeroValue, defaultValue, stringPre, stringPost,
+                                     presentation, paintStyle, indexMaxStream,
+                                     colour, summary);
+  }
+
+  /**
+   * Create a new IntStream instance using the appropriate
+   * VM-specific concrete IntStream sub-class.
+   *
+   * @param driver        The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   * @see IntStream
+   *
+   * @return A concrete VM-specific IntStream instance.
+   */
+  public static IntStream newGCspyIntStream(
+      AbstractDriver driver,
+      String name,
+      int minValue,
+      int maxValue,
+      int zeroValue,
+      int defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary) {
+    return factory.newGCspyIntStream(driver, name, minValue,  maxValue,
+                                     zeroValue, defaultValue, stringPre, stringPost,
+                                     presentation, paintStyle, indexMaxStream,
+                                     colour, summary);
+  }
+
+  /**
+   * Create a new ShortStream instance using the appropriate
+   * VM-specific concrete ShortStream sub-class.
+   *
+   * @param driver        The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   * @see IntStream
+   *
+   * @return A concrete VM-specific IntStream instance.
+   */
+  public static ShortStream newGCspyShortStream(
+      AbstractDriver driver,
+      String name,
+      short minValue,
+      short maxValue,
+      short zeroValue,
+      short defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary) {
+    return factory.newGCspyShortStream(driver, name, minValue,  maxValue,
+                                     zeroValue, defaultValue, stringPre, stringPost,
+                                     presentation, paintStyle, indexMaxStream,
+                                     colour, summary);
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ByteStream.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ByteStream.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ByteStream.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ByteStream.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,147 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.GCspy;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.*;
+
+/**
+ * Set up a GCspy Stream with data type BYTE_TYPE
+ */
+
+ at Uninterruptible public abstract class ByteStream extends Stream {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private byte[] data;          // The stream data
+  private byte defaultValue;    // The default value for the data items
+
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Construct a new GCspy stream of BYTE_TYPE
+   * @param driver          The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   */
+  public ByteStream(
+         AbstractDriver driver,
+         String name,
+         byte minValue,
+         byte maxValue,
+         byte zeroValue,
+         byte defaultValue,
+         String stringPre,
+         String stringPost,
+         int presentation,
+         int paintStyle,
+         int indexMaxStream,
+         Color colour,
+         boolean summary) {
+
+    super(driver, StreamConstants.BYTE_TYPE, name,
+          minValue, maxValue, zeroValue, defaultValue,
+          stringPre, stringPost, presentation, paintStyle,
+          indexMaxStream, colour, summary);
+
+    data = (byte[])GCspy.util.createDataArray(new byte[0], driver.getMaxTileNum());
+    this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Reset all data in this stream to default values.
+   */
+  public void resetData() {
+    for (int i = 0; i < data.length; i++)
+      data[i] = defaultValue;
+  }
+
+
+  /**
+   * Distribute a value across a sequence of tiles. This handles the case
+   * when when an object spans two or more tiles and its value is to be
+   * attributed to each tile proportionally.
+   *
+   * @param start the index of the starting tile
+   * @param remainder the value left in the starting tile
+   * @param blockSize the size of each tile
+   * @param value the value to distribute
+   */
+  public void distribute(int start, byte remainder, int blockSize, byte value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(remainder <= blockSize);
+    if (value <= remainder) {  // fits in this tile
+      data[start] += value;
+      //checkspace(start, value, "scanObject fits in first tile");
+    } else {
+      data[start] += remainder;
+      //checkspace(start, remainder, "scanObject remainder put in first tile");
+      value -= remainder;
+      start++;
+      while (value >= blockSize) {
+        data[start] += blockSize;
+        //checkspace(start, blockSize, "scanObject subsequent tile");
+        value -= blockSize;
+        start++;
+      }
+      data[start] += value;
+      //checkspace(start, value, "scanObject last tile");
+    }
+  }
+
+  /**
+   * Increment the value of a tile.
+   * @param index the index
+   * @param value the increment
+   */
+  public void increment(int index, byte value) { data[index] += value; }
+
+  /**
+   * Send the data and summary for this stream.
+   * @param event The event
+   * @param numTiles The number of tiles to send (which may be less than maxTileNum)
+   * @see #ByteStream
+   */
+  public void send(int event, int numTiles) {
+    if (DEBUG) {
+      Log.write("sending "); Log.write(numTiles); Log.writeln(" int values");
+    }
+    serverSpace.stream(streamId, numTiles);
+    for (int index = 0; index < numTiles; index++)
+      serverSpace.streamByteValue(data[index]);
+    serverSpace.streamEnd();
+    sendSummary();
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/IntStream.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/IntStream.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/IntStream.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/IntStream.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,147 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.GCspy;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.*;
+
+/**
+ * Set up a GCspy Stream with data type INT_TYPE.
+ */
+ at Uninterruptible public abstract class IntStream extends Stream {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private int[] data;           // The stream data
+  private int defaultValue;     // The default value for the data items
+
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Construct a new GCspy stream of INT_TYPE
+   * @param driver          The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   */
+  public IntStream(
+         AbstractDriver driver,
+         String name,
+         int minValue,
+         int maxValue,
+         int zeroValue,
+         int defaultValue,
+         String stringPre,
+         String stringPost,
+         int presentation,
+         int paintStyle,
+         int indexMaxStream,
+         Color colour,
+         boolean summary) {
+
+    super(driver, StreamConstants.INT_TYPE, name,
+          minValue, maxValue, zeroValue, defaultValue,
+          stringPre, stringPost, presentation, paintStyle,
+          indexMaxStream, colour, summary);
+
+    data = (int[])GCspy.util.createDataArray(new int[0], driver.getMaxTileNum());
+    this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Reset all data in this stream to default values.
+   */
+  public void resetData() {
+    for (int i = 0; i < data.length; i++)
+      data[i] = defaultValue;
+  }
+
+
+  /**
+   * Distribute a value across a sequence of tiles. This handles the case
+   * when when an object spans two or more tiles and its value is to be
+   * attributed to each tile proportionally.
+   *
+   * @param start the index of the starting tile
+   * @param remainder the value left in the starting tile
+   * @param blockSize the size of each tile
+   * @param value the value to distribute
+   */
+  public void distribute(int start, int remainder, int blockSize, int value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(remainder <= blockSize);
+    if (value <= remainder) {  // fits in this tile
+      data[start] += value;
+      //checkspace(start, value, "scanObject fits in first tile");
+    } else {
+      data[start] += remainder;
+      //checkspace(start, remainder, "scanObject remainder put in first tile");
+      value -= remainder;
+      start++;
+      while (value >= blockSize) {
+        data[start] += blockSize;
+        //checkspace(start, blockSize, "scanObject subsequent tile");
+        value -= blockSize;
+        start++;
+      }
+      data[start] += value;
+      //checkspace(start, value, "scanObject last tile");
+    }
+  }
+
+  /**
+   * Increment the value of a tile.
+   * @param index the index
+   * @param value the increment
+   */
+  public void increment(int index, int value) { data[index] += value; }
+
+  /**
+   * Send the data and summary for this stream.
+   * @param event The event
+   * @param numTiles The number of tiles to send (which may be less than maxTileNum)
+   */
+  public void send(int event, int numTiles) {
+    if (DEBUG) {
+      Log.write("sending "); Log.write(numTiles); Log.writeln(" int values");
+    }
+
+    serverSpace.stream(streamId, numTiles);
+    for (int index = 0; index < numTiles; index++)
+      serverSpace.streamIntValue(data[index]);
+    serverSpace.streamEnd();
+
+    sendSummary();
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerInterpreter.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerInterpreter.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerInterpreter.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerInterpreter.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,124 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.Address;
+
+/**
+ * Abstract class for the GCspy server interpreter
+ *
+ * Implementing classes will mostly forward calls to the C gcspy library.
+ */
+ at Uninterruptible public abstract class ServerInterpreter {
+
+  protected static final int MAX_LEN = 64 * 1024; // Buffer size
+  protected static final int MAX_SPACES = 32;     // Maximum number of spaces
+  protected static boolean initialised = false;
+
+  protected ServerSpace[] spaces;                 // The server's spaces
+  protected Address server;                       // a pointer to the c server, gcspy_main_server_t server
+
+  protected static final boolean DEBUG = false;
+
+  /**
+   * Create a new ServerInterpreter singleton.
+   * @param name The name of the server
+   * @param port The number of the port on which to communicate
+   * @param verbose Whether the server is to run verbosely
+   */
+  @Interruptible
+  public abstract void init(String name, int port, boolean verbose);
+
+  /**
+   * Add an event to the ServerInterpreter.
+   * @param num the event number
+   * @param name the event name
+   */
+  public abstract void addEvent(int num, String name);
+
+  /**
+   * Set the general info for the ServerInterpreter.
+   * @param info the information
+   */
+  public abstract void setGeneralInfo(String info);
+
+  /**
+   * Get a pointer to the C server, gcspy_main_server_t.
+   * This address is used in alll calls to the server in the C library.
+   * @return the address of the server
+   */
+  public Address getServerAddress() { return server; }
+
+  /**
+   * Add a GCspy ServerSpace to the ServerInterpreter.
+   * This method returns a unique space ID for the ServerSpace
+   * (again used in calls to the C library).
+   *
+   * @param space the ServerSpace to add
+   * @return a unique id for this space
+   * @exception IndexOutOfBoundsException on attempt to add more than
+   * MAX_SPACES spaces
+   */
+  @Interruptible
+  public int addSpace(ServerSpace space) {
+    int id = 0;
+    while (id < MAX_SPACES) {
+      if (spaces[id] == null) {
+        spaces[id] = space;
+        return id;
+      }
+      id++;
+    }
+    throw new IndexOutOfBoundsException(
+        "Too many spaces to add to interpreter.\nSet MAX_SPACES to higher value in ServerInterpreter.");
+  }
+
+  /**
+   * Start the server, running its main loop in a pthread.
+   * @param wait Whether to wait for the client to connect
+   */
+  public abstract void startServer(boolean wait);
+
+  /**
+   * Are we connected to a GCspy client?
+   * @param event The current event
+   * @return true if we are connected
+   */
+  public abstract boolean isConnected(int event);
+
+  /**
+   * Start compensation timer so that time spent gathering data is
+   * not confused with the time spent in the application and the VM.
+   */
+  public abstract void startCompensationTimer();
+
+  /**
+   * Stop compensation timer so that time spent gathering data is
+   * not confused with the time spent in the application and the VM.r
+   */
+  public abstract void stopCompensationTimer();
+
+  /**
+   * Indicate that we are at a server safe point (e.g. the end of a GC).
+   * This is a point at which the server can pause, play one, etc.
+   * @param event The current event
+   */
+  public abstract void serverSafepoint(int event);
+
+  /**
+   * Discover the smallest header size for objects.
+   * @return the size in bytes
+   */
+  public abstract int computeHeaderSize();
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerSpace.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerSpace.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerSpace.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ServerSpace.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,160 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Abstract class for the GCspy Space abstraction.
+ *
+ * Implementing classes will largely forward calls to the gcspy C library.
+ */
+ at Uninterruptible public abstract class ServerSpace {
+
+  /****************************************************************************
+   *
+   * Class variables
+   */
+  protected static final String DEFAULT_UNUSED_STRING = "NOT USED";       // The "unused" string
+
+  /****************************************************************************
+  *
+  * Instance variables
+  */
+  protected int spaceId;         // the space's ID
+  protected Address driver;      // a pointer to the C driver, gcspy_gc_drivert *driver;
+  protected static final boolean DEBUG = false;
+
+
+  /**
+   * Get a pointer to the native driver
+   * @return The address of the C driver, gcspy_gc_drivert *, used in all calls
+   * to the C library.
+   */
+  Address getDriverAddress() {
+    return driver;
+  }
+
+  /**
+   * Tell the native driver the tile name.
+   * @param i the number of the tile
+   * @param start the starting address of the tile
+   * @param end the end address
+   */
+  public abstract void setTilename(int i, Address start, Address end);
+
+  /**
+   * Tell the native driver the tile name.
+   * @param i the number of the tile
+   * @param format the name of the tile, a format string
+   * @param value The value for the format string
+   */
+  public abstract void setTilename(int i, Address format, long value);
+
+  /**
+   * Tell the native driver the tile names.
+   * @param i the number of the tile
+   * @param format The name, including format tags
+   * @param value The value for the format string
+   */
+  public abstract void setTilename(int i, String format, long value);
+
+  /**
+   * Tell the C driver to resize
+   * @param size the new driver size
+   */
+  public abstract void resize(int size);
+
+  /**
+   * Start a transmission
+   */
+  public abstract void startCommunication();
+
+  /**
+   * Add a stream to the native driver
+   * @param id the stream's ID
+   * @return the address of the C gcspy_gc_stream_t
+   */
+  public abstract Address addStream(int id);
+
+  /**
+   * Start transmitting a stream.
+   * @param id The stream's ID
+   * @param len The number of items in the stream
+   */
+  public abstract void stream(int id, int len);
+
+  /**
+   * Send a byte
+   * @param value The byte
+   */
+  public abstract void streamByteValue(byte value);
+
+  /**
+   * Send a short
+   * @param value The short
+   */
+  public abstract void streamShortValue(short value);
+
+  /**
+   * Send an int
+   * @param value The int
+   */
+  public abstract void streamIntValue(int value);
+
+  /**
+   * End of this stream
+   */
+  public abstract void streamEnd();
+
+  /**
+   * Start to send a summary
+   * @param id The stream's ID
+   * @param len The number of items to be sent
+   */
+  public abstract void summary(int id, int len);
+
+  /**
+   * Send a summary value
+   * @param val The value
+   */
+  public abstract void summaryValue(int val);
+
+  /**
+   * End the summary
+   */
+  public abstract void summaryEnd();
+
+  /**
+   * Send all the control info for the space
+   * @param space The GCspy driver for this space
+   * @param tileNum The number of tiles
+   */
+  public abstract void sendControls(AbstractDriver space, int tileNum);
+
+  /**
+   * Send info for this space
+   * @param info A pointer to the information (held as C string)
+   */
+  public abstract void spaceInfo(Address info);
+
+  /**
+   * End the transmission (for this event)
+   */
+  public void endCommunication() {
+    if (DEBUG) Log.write("endComm\n");
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ShortStream.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ShortStream.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ShortStream.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/ShortStream.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,146 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.GCspy;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.*;
+
+/**
+ * Set up a GCspy Stream with data type SHORT_TYPE.
+ */
+ at Uninterruptible public abstract class ShortStream extends Stream {
+
+  /****************************************************************************
+   *
+   * Instance variables
+   */
+  private short[] data;         // The stream data
+  private short defaultValue;   // The default value for the data items
+
+  /****************************************************************************
+   *
+   * Initialization
+   */
+
+  /**
+   * Construct a new GCspy stream of SHORT_TYPE
+   * @param driver          The driver that owns this Stream
+   * @param name           The name of the stream (e.g. "Used space")
+   * @param minValue       The minimum value for any item in this stream.
+   *                       Values less than this will be represented as "minValue-"
+   * @param maxValue       The maximum value for any item in this stream.
+   *                       Values greater than this will be represented as "maxValue+"
+   * @param zeroValue      The zero value for this stream
+   * @param defaultValue   The default value for this stream
+   * @param stringPre      A string to prefix values (e.g. "Used: ")
+   * @param stringPost     A string to suffix values (e.g. " bytes.")
+   * @param presentation   How a stream value is to be presented.
+   * @param paintStyle     How the value is to be painted.
+   * @param indexMaxStream The index of the maximum stream if the presentation is *_VAR.
+   * @param colour         The default colour for tiles of this stream
+   */
+  public ShortStream(
+         AbstractDriver driver,
+         String name,
+         short minValue,
+         short maxValue,
+         short zeroValue,
+         short defaultValue,
+         String stringPre,
+         String stringPost,
+         int presentation,
+         int paintStyle,
+         int indexMaxStream,
+         Color colour,
+         boolean summary) {
+
+    super(driver, StreamConstants.SHORT_TYPE, name,
+          minValue, maxValue, zeroValue, defaultValue,
+          stringPre, stringPost, presentation, paintStyle,
+          indexMaxStream, colour, summary);
+
+    data = (short[])GCspy.util.createDataArray(new short[0], driver.getMaxTileNum());
+    this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Reset all data in this stream to default values.
+   */
+  public void resetData() {
+    for (int i = 0; i < data.length; i++)
+      data[i] = defaultValue;
+  }
+
+
+  /**
+   * Distribute a value across a sequence of tiles. This handles the case
+   * when when an object spans two or more tiles and its value is to be
+   * attributed to each tile proportionally.
+   *
+   * @param start the index of the starting tile
+   * @param remainder the value left in the starting tile
+   * @param blockSize the size of each tile
+   * @param value the value to distribute
+   */
+  public void distribute(int start, short remainder, int blockSize, short value) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(remainder <= blockSize);
+    if (value <= remainder) {  // fits in this tile
+      data[start] += value;
+      //checkspace(start, value, "scanObject fits in first tile");
+    } else {
+      data[start] += remainder;
+      //checkspace(start, remainder, "scanObject remainder put in first tile");
+      value -= remainder;
+      start++;
+      while (value >= blockSize) {
+        data[start] += blockSize;
+        //checkspace(start, blockSize, "scanObject subsequent tile");
+        value -= blockSize;
+        start++;
+      }
+      data[start] += value;
+      //checkspace(start, value, "scanObject last tile");
+    }
+  }
+
+  /**
+   * Increment the value of a tile.
+   * @param index the index
+   * @param value the increment
+   */
+  public void increment(int index, short value) { data[index] += value; }
+
+  /**
+   * Send the data and summary for this stream.
+   * @param event The event
+   * @param numTiles The number of tiles to send (which may be less than maxTileNum)
+   */
+  public void send(int event, int numTiles) {
+    if (DEBUG) {
+      Log.write("sending "); Log.write(numTiles); Log.writeln(" int values");
+    }
+    serverSpace.stream(streamId, numTiles);
+    for (int index = 0; index < numTiles; index++)
+      serverSpace.streamShortValue(data[index]);
+    serverSpace.streamEnd();
+
+    // send the summary
+    sendSummary();
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Stream.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Stream.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Stream.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Stream.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,217 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.mmtk.utility.Log;
+import org.mmtk.utility.gcspy.Color;
+import org.mmtk.utility.gcspy.StreamConstants;
+import org.mmtk.utility.gcspy.drivers.AbstractDriver;
+import org.mmtk.vm.VM;
+import org.vmmagic.pragma.*;
+import org.vmmagic.unboxed.Address;
+
+/**
+ *
+ * Abstract class for a GCspy Stream.
+ * Implementing classes will mostly forward calls
+ * to the gcspy C library
+ */
+
+ at Uninterruptible public abstract class Stream {
+
+  /****************************************************************************
+  *
+  * Instance variables
+  */
+
+  /**
+   * The address of the C stream, gcspy_gc_stream_t *stream, used in all calls
+   * to the C library
+   */
+  protected Address stream;
+
+  /** The owning GCspy space */
+  protected ServerSpace serverSpace;
+
+  /** The stream's ID */
+  protected int streamId;
+
+  /**
+   * A summary has 1 or 2 values depending on presentation style
+   * (PERCENT* styles require 2 values).
+   */
+  protected int summaryLen;
+
+  /** The first summary value */
+  protected int summary0;
+
+  /** The second summary value (if any) */
+  protected int summary1;
+
+  private int min; // The minimum value for tiles
+
+  private int max; // The maximum value for tiles
+
+  /** use summaries? */
+  protected boolean summaryEnabled;
+
+  /** the presentation style */
+  protected int presentation;
+
+  protected static final boolean DEBUG = false;
+
+  /**
+   * Construct a new GCspy stream.
+   *
+   * @param driver The AbstractDriver that owns this Stream
+   * @param dataType The stream's data type, one of BYTE_TYPE, SHORT_TYPE or INT_TYPE
+   * @param name The name of the stream (e.g. "Used space")
+   * @param minValue The minimum value for any item in this stream. Values less than
+   *                 this will be represented as "minValue-"
+   * @param maxValue The maximum value for any item in this stream. Values greater than
+   *                 this will be represented as "maxValue+"
+   * @param zeroValue The zero value for this stream
+   * @param defaultValue The default value for this stream
+   * @param stringPre A string to prefix values (e.g. "Used: ")
+   * @param stringPost A string to suffix values (e.g. " bytes.")
+   * @param presentation How a stream value is to be presented.
+   * @param paintStyle How the value is to be painted.
+   * @param indexMaxStream The index for the maximum stream if the presentation is *_VAR.
+   * @param colour The default colour for tiles of this stream
+   * @param summary Is a summary enabled?
+   */
+  protected Stream(
+      AbstractDriver driver,
+      int dataType,
+      String name,
+      int minValue,
+      int maxValue,
+      int zeroValue,
+      int defaultValue,
+      String stringPre,
+      String stringPost,
+      int presentation,
+      int paintStyle,
+      int indexMaxStream,
+      Color colour,
+      boolean summary) {
+
+    serverSpace = driver.getServerSpace();
+    summaryEnabled = summary;
+    this.presentation = presentation;
+    if (summary)
+      setupSummary(presentation);
+    min = minValue;
+    max = maxValue;
+
+    driver.addStream(this);
+    if (DEBUG) {
+      Log.write("Adding stream ");
+      Log.write(name);
+      Log.writeln(" id=", streamId);
+    }
+  }
+
+
+  /**
+   * Set the stream address and id (called by AbstractDriver.addStream).
+   * @param id the id
+   * @param str the address of the gcspy C gcspy_gc_stream_t *stream
+   */
+  public void setStream(int id, Address str) {
+    streamId = id;
+    stream = str;
+  }
+
+  /**
+   * Return the minimum value expected for this stream.
+   * @return the minimum value
+   */
+  public int getMinValue() { return min; }
+
+  /**
+   * Return the maximum value expected for this stream.
+   * @return the maximum value
+   */
+  public int getMaxValue() { return max; }
+
+  /**
+   * Setup the summary array.
+   * @param presentation the presentation style
+   */
+  @Interruptible
+  private void setupSummary(int presentation) {
+    switch (presentation) {
+      case StreamConstants.PRESENTATION_PLAIN:
+      case StreamConstants.PRESENTATION_PLUS:
+      case StreamConstants.PRESENTATION_MAX_VAR:
+      case StreamConstants.PRESENTATION_ENUM:
+        summaryLen = 1;
+        break;
+      case StreamConstants.PRESENTATION_PERCENT:
+      case StreamConstants.PRESENTATION_PERCENT_VAR:
+        summaryLen = 2;
+        break;
+      default:
+        VM.assertions._assert(false);
+    }
+  }
+
+  /**
+   * Set the summary value for presentation styles with just one value
+   * @param value0 the value
+   */
+  public void setSummary(int value0) {
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(presentation != StreamConstants.PRESENTATION_PERCENT &&
+                            presentation != StreamConstants.PRESENTATION_PERCENT_VAR);
+    summary0 = value0;
+  }
+
+  /**
+   * Set the summary values for presentation styles with two values (i.e.
+   * PRESENTATION_PERCENT and PRESENTATION_PERCENT_VAR).
+   * @param value0 the numerator value
+   * @param value1 the denominator value
+   */
+  public void setSummary(int value0, int value1) {
+    if (VM.VERIFY_ASSERTIONS)
+      VM.assertions._assert(presentation == StreamConstants.PRESENTATION_PERCENT ||
+                            presentation == StreamConstants.PRESENTATION_PERCENT_VAR);
+    summary0 = value0;
+    summary1 = value1;
+  }
+
+  /**
+   * Send the data for this stream.
+   * @param event the event.
+   * @param numTiles the number of tiles to send.
+   */
+  public abstract void send(int event, int numTiles);
+
+  /**
+   * Send the summary data for this stream.
+   */
+  public void sendSummary() {
+    if (summaryEnabled) {
+      serverSpace.summary(streamId, summaryLen);
+      serverSpace.summaryValue(summary0);
+      if (summaryLen == 2)
+        serverSpace.summaryValue(summary1);
+      serverSpace.summaryEnd();
+    }
+  }
+
+}
+
+

Added: vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Util.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Util.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Util.java (added)
+++ vmkit/trunk/mmtk/java/src/org/mmtk/vm/gcspy/Util.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,166 @@
+/*
+ *  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.mmtk.vm.gcspy;
+
+import org.mmtk.utility.Log;
+import org.vmmagic.unboxed.*;
+import org.vmmagic.pragma.*;
+
+/**
+ * Abstract class that provides generally useful
+ * methods.
+ */
+ at Uninterruptible public abstract class Util {
+
+  /**
+   * Allocate an array of bytes with malloc
+   *
+   * @param size The size to allocate
+   * @return The start address of the memory allocated in C space
+   * @see #free
+  */
+  public abstract Address malloc(int size);
+
+  /**
+   * Free an array of bytes previously allocated with malloc
+   *
+   * @param addr The address of some memory previously allocated with malloc
+   * @see #malloc
+   */
+  public abstract void free(Address addr);
+
+  /**
+   * Dump a range in format [start,end)
+   *
+   * @param start The start of the range
+   * @param end The end of the range
+   */
+  public static void dumpRange(Address start, Address end) {
+    Log.write("["); Log.write(start);
+    Log.write(","); Log.write(end);
+    Log.write(')');
+  }
+
+  /**
+   * Convert a String to a 0-terminated array of bytes
+   *
+   * @param str The string to convert
+   * @return The address of a null-terminated array in C-space
+   */
+  public abstract Address getBytes(String str);
+
+  /**
+   * Pretty print a size, converting from bytes to kilo- or mega-bytes as appropriate
+   *
+   * @param buffer The buffer (in C space) in which to place the formatted size
+   * @param size The size in bytes
+   */
+  public abstract void formatSize(Address buffer, int size);
+
+  /**
+   * Pretty print a size, converting from bytes to kilo- or mega-bytes as appropriate
+   *
+   * @param format A format string
+   * @param bufsize The size of a buffer large enough to hold the formatted result
+   * @param size The size in bytes
+   */
+  public abstract Address formatSize(String format, int bufsize, int size);
+
+//  public abstract Address formatSize(String format, int bufsize, int size);
+
+  /**
+   * Place a string representation of a long in an array of bytes
+   * without incurring allocation
+   *
+   * @param buffer The byte array
+   * @param value The long to convert
+   * @return The length of the string representation of the integer
+   *         -1 indicates some problem (e.g the char buffer was too small)
+   */
+  public static int numToBytes(byte[] buffer, long value) {
+    return numToBytes(buffer, value, 10);
+  }
+
+  /**
+   * Place a string representation of a long in an array of bytes
+   * without incurring allocation
+   *
+   * @param buffer The byte array
+   * @param value The long to convert
+   * @param radix the base to use for conversion
+   * @return The length of the string representation of the integer
+   *         -1 indicates some problem (e.g the char buffer was too small)
+   */
+  public static int numToBytes(byte[] buffer, long value, int radix) {
+
+    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
+      radix = 10;
+
+    if (value == 0) {
+      buffer[0] = (byte)'0';
+      return 1;
+    }
+
+    boolean negative;
+    long longValue;
+    int count;
+    if (!(negative = (value < 0))) {
+      longValue = -value;
+      count = 1;
+    } else {
+      longValue = value;
+      count = 2;
+    }
+
+    long j = longValue;
+    while ((j /= radix) != 0) count++;
+    if (count > buffer.length)
+      return -1; // overflow
+
+    int i = count;
+    do {
+      int ch = (int) -(longValue % radix);
+      if (ch > 9)
+        ch -= (10 - (int) 'a');
+      else
+        ch += (int) '0';
+      buffer [--i] = (byte) ch;
+    } while ((longValue /= radix) != 0);
+    if (negative) buffer [0] = (byte)'-';
+
+    return count;
+
+  }
+
+  /**
+   * sprintf(char *str, char *format, char* value)
+   *
+   * @param str The destination 'string' (memory in C space)
+   * @param format The format 'string' (memory in C space)
+   * @param value The value 'string' (memory in C space)
+   * @return The number of characters printed (as returned by C's sprintf
+   */
+  public abstract int sprintf(Address str, Address format, Address value);
+
+  /**
+   * Create an array of a particular type.
+   * The easiest way to use this is:
+   *     Foo[] x = (Foo [])Stream.createDataArray(new Foo[0], numElements);
+   * @param templ a data array to use as a template
+   * @param numElements number of elements in new array
+   * @return the new array
+   */
+  @Interruptible
+  public abstract Object createDataArray(Object templ, int numElements);
+}
+

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/Intrinsic.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/Intrinsic.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/Intrinsic.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/Intrinsic.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,40 @@
+/*
+ *  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.vmmagic;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+
+/**
+ * An intrinsic method is a method that is built in (that is, intrinsic) to the compiler
+ * rather than part of a class library. Intrinsic methods are an escape hatch to provide
+ * "magic" that is inexpressible int the Java programming language. A compiler intrinsic
+ * will usually generate a specific code sequence that is inlined and optimized as part
+ * by the compiler. Unless an intrinsic method is expected to be executed in a non-intrinsic
+ * aware compiler, the body of the method should be empty.
+ *
+ * <p>If the Intrinsic annotation is applied to a method then then the method is a compiler
+ * intrinsic. If the Intrinsic annotation is applied to a class then all the methods of
+ * the class AND all subclasses are intrinsic.</p>
+ *
+ * <p>NOTE: At the current time the Intrinsic annotation is only used for documentation
+ * purposes but in the near future it is expected that the semantics of the annotation will
+ * be enforced by the compiler.</p>
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE,ElementType.METHOD})
+ at Inherited
+public @interface Intrinsic { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/Pragma.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/Pragma.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/Pragma.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/Pragma.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,38 @@
+/*
+ *  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.vmmagic;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+
+/**
+ * A Pragma is a mechanism for supplying information to the compiler to alter the code it
+ * generates for a method. A Pragma is similar to an {@link org.vmmagic.Intrinsic}
+ * but it does not provide any behaviour but provides information to the compiler that modifies
+ * optimizations, calling conventions and activation frame layout.
+ *
+ * <p>If the Pragma annotation is applied to a method then then the method is a handled specially
+ * by the compiler. If the Pragma annotation is applied to a class then then all the methods in that
+ * class are handled specially by the compiler.</p>
+ *
+ * <p>NOTE: At the current time the Pragma annotation is only used for documentation
+ * purposes but in the near future it is expected that the semantics of the annotation will
+ * be enforced by the compiler.</p>
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE,ElementType.METHOD})
+ at Inherited
+public @interface Pragma { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/Unboxed.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/Unboxed.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/Unboxed.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/Unboxed.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,44 @@
+/*
+ *  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.vmmagic;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+
+/**
+ * The Unboxed annotation marks a type as unboxed. Besides the primitive types, all Java values
+ * are boxed types. Conceptually, they are represented by a pointer to a heap object. However,
+ * an unboxed type is represented by the value itself. All methods on an unboxed type are
+ * {@link Intrinsic}s.
+ *
+ * <p>As an unboxed type is not a regular java object there are a few constraints on the way unboxed
+ * types are handled;</p>
+ * <ul>
+ *   <li>All methods are {@link Intrinsic} and thus there can be no virtual methods.</li>
+ *   <li>An unboxed type can not be synchronized on.</li>
+ *   <li>An unboxed type has no hashcode.</li>
+ *   <li>An unboxed type MUST NOT be passed where an object is expected or when two overloaded methods
+ *       can only be distinguished by by Object vs unboxed parameter type.</li>
+ * </ul>
+ *
+ * <p>NOTE: At the current time the Unboxed annotation is only used for documentation
+ * purposes but in the near future it is expected that the semantics of the annotation will
+ * be enforced by the compiler.</p>
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+ at Inherited
+public @interface Unboxed { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineNoRegisters.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineNoRegisters.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineNoRegisters.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineNoRegisters.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * Some methods shouldn't use registers for locals and stack values.
+ * E.g. CollectorThread can't relocate refs in registers of its own.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface BaselineNoRegisters { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineSaveLSRegisters.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineSaveLSRegisters.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineSaveLSRegisters.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/BaselineSaveLSRegisters.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * Methods with this pragma that are BaselineCompiled should save in its prologue, ALL registers that
+ * can be used to store local and stack registers in any BaselineCompiled method. Used by OSR.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface BaselineSaveLSRegisters { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/DynamicBridge.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/DynamicBridge.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/DynamicBridge.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/DynamicBridge.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,37 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * Methods of a class that implements this interface are treated specially
+ * by the compilers.
+ *
+ * <p>Instead of saving just the non-volatile registers used by the method into
+ * the register save area of the method's stackframe, the compiler generates
+ * code to save *all* GPR and FPR registers except GPR0, FPR0, JTOC, and FP.
+ *
+ * <p>Methods of a class that implement this interface may not return.
+ *    (it is assumed that execution is resumed via a call to Magic.dynamicBridgeTo)
+ *
+ * @see org.jikesrvm.runtime.Magic#dynamicBridgeTo(org.jikesrvm.ArchitectureSpecific.CodeArray)
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+ at Pragma
+public @interface DynamicBridge { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Entrypoint.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Entrypoint.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Entrypoint.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Entrypoint.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,29 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * The entrypoint annotation indicates that the method or field is
+ * directly accessed by the compiler. We cache resolved values for
+ * these elements in Entrypoints.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD, ElementType.FIELD})
+ at Pragma
+public @interface Entrypoint { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Inline.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Inline.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Inline.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Inline.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,63 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma indicates that a particular method should always be inlined
+ * by the optimizing compiler.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface Inline {
+  /**
+   * Enumeration defining when to inline
+   */
+  public enum When {
+    /**
+     * Always inline, regardless of arguments
+     */
+    Always,
+    /**
+     * Inline when all the arguments are constants
+     */
+    AllArgumentsAreConstant,
+    /**
+     * Inline when the specified arguments are constants
+     */
+    ArgumentsAreConstant,
+    /**
+     * Inline when the VM is built without Assertions (VM.VerifyAssertions == false).
+     * Note: It would be nicer to have the more general ExpressionIsTrue annotation,
+     * but the argument expression to the annotation is restricted to be a fairly
+     * trivial constant, and that isn't enough to handle how VM.VERIFY_ASSERTIONS
+     * is defined in MMTk.
+     */
+    AssertionsDisabled
+  }
+  /**
+   * When to inline, default When.Always
+   */
+  When value() default When.Always;
+  /**
+   * Arguments that must be constant to cause inlining. NB for static methods 0
+   * is the first argument whilst for virtual methods 0 is this
+   */
+  int[] arguments() default {};
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Interruptible.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Interruptible.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Interruptible.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Interruptible.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,48 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * By default all Java code is interruptible, that is scheduling or garbage
+ * collection may occur at points within the code. Code can be marked as
+ * {@link Unpreemptible} or {@link Uninterruptible}, that instructs the JVM to
+ * avoid garbage collection and thread scheduling. The {@link Uninterruptible}
+ * annotation disallows any operation that may cause garbage collection or
+ * thread scheduling, for example memory allocation. The {@link Unpreemptible}
+ * annotation doesn't disallow operations that can cause garbage collection or
+ * scheduling, but instructs the JVM to avoid inserting such operations during a
+ * block of code.
+ *
+ * In the internals of a VM most code wants to be {@link Uninterruptible}.
+ * However, code involved in scheduling and locking will cause context switches,
+ * and creating exception objects may trigger garbage collection, this code is
+ * therefore {@link Unpreemptible}.
+ *
+ * This pragma is used to declare that a particular method is interruptible. It
+ * is used to override the class-wide pragma {@link Uninterruptible}.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface Interruptible {
+  /**
+   * @return Explanation of why code needs to be interruptible
+   */
+  String value() default "";
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/LogicallyUninterruptible.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/LogicallyUninterruptible.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/LogicallyUninterruptible.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/LogicallyUninterruptible.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,51 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * A pragma that can be used to declare that a particular method is logically
+ * uninterruptible even though it contains bytecodes that are actually
+ * interruptible.
+ *
+ * The effect of this pragma is to suppress warning messages about violations of
+ * uninterruptiblity when compiling a method that throws this exception. There
+ * are two cases in which using the pragma is justified.
+ * <ul>
+ * <li> Uninterruptibility is ensured via some other mechanism. For example, the
+ * method explicitly disables threadswitching around the interruptible regions
+ * (VM.sysWrite on String). Or the interruptible regions are not reachable when
+ * the VM is running (various VM.sysWrite that check VM.runningVM).
+ * <li> The interruptible regions represent an 'error' condition that will never
+ * be executed unless the VM is already in the process of reporting an error,
+ * for example RuntimeEntrypoints.raiseClassCastException.
+ * <ul>
+ * Extreme care must be exercised when using this pragma since it suppresses the
+ * checking of uninterruptibility.
+ * <p>
+ * Use of this pragma is being phased out since it lumps together two possible
+ * special cases. Use either {@link Unpreemptible} or
+ * {@link UninterruptibleNoWarn} instead.
+ * {@link <a href="http://jira.codehaus.org/browse/RVM-115">RVM-115</a>} for more
+ * context.
+ * @deprecated
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface LogicallyUninterruptible { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NativeBridge.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NativeBridge.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NativeBridge.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NativeBridge.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,32 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * Methods of a class that implements this interface are treated specially
+ * by the compilers:
+ *  -They are only called from C or C++ program
+ *  -The compiler will generate the necessary prolog to insert a glue stack
+ *   frame to map from the native stack/register convention to RVM's convention
+ *  -It is an error to call these methods from Java
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+ at Pragma
+public @interface NativeBridge { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoBoundsCheck.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoBoundsCheck.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoBoundsCheck.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoBoundsCheck.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma indicates that a particular method should never have bounds
+ * checks generated.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface NoBoundsCheck { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoEscapes.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoEscapes.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoEscapes.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoEscapes.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+
+/**
+ * Use this annotation to mark methods that won't cause their reference arguments
+ * to escape. If we can convert the object referenced in to registers then the
+ * method marked with this annotation will be removed.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface NoEscapes { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoInline.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoInline.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoInline.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoInline.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma indicates that a particular method should never be inlined
+ * by the optimizing compiler.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface NoInline { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoNullCheck.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoNullCheck.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoNullCheck.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoNullCheck.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma indicates that a particular method should never have null checks
+ * generated.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface NoNullCheck { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoOptCompile.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoOptCompile.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoOptCompile.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NoOptCompile.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,29 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma indicates that a particular method should never be
+ * compiled by the optimizing compiler. It also implies that the
+ * method will never be inlined by the optimizing compiler.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Pragma
+public @interface NoOptCompile { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMoving.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMoving.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMoving.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMoving.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+
+/**
+ * Use this annotation to mark types that must never move. This is intended for
+ * a very small set of VM internal types that are accessed without knowledge of the
+ * memory manager. This includes code, that is CALLed and fields that are loaded
+ * directly (such as Untraced fields).
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface NonMoving { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMovingAllocation.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMovingAllocation.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMovingAllocation.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/NonMovingAllocation.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,27 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+
+/**
+ * Use this annotation to mark methods for which all allocation must never
+ * move. This is intended for a very small set of VM internal methods that
+ * specifically require these semantics.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+public @interface NonMovingAllocation { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Preemptible.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Preemptible.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Preemptible.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Preemptible.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,48 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * By default all Java code is interruptible, that is scheduling or garbage
+ * collection may occur at points within the code. Code can be marked as
+ * {@link Unpreemptible} or {@link Uninterruptible}, that instructs the JVM to
+ * avoid garbage collection and thread scheduling. The {@link Uninterruptible}
+ * annotation disallows any operation that may cause garbage collection or
+ * thread scheduling, for example memory allocation. The {@link Unpreemptible}
+ * annotation doesn't disallow operations that can cause garbage collection or
+ * scheduling, but instructs the JVM to avoid inserting such operations during a
+ * block of code.
+ *
+ * In the internals of a VM most code wants to be {@link Uninterruptible}.
+ * However, code involved in scheduling and locking will cause context switches,
+ * and creating exception objects may trigger garbage collection, this code is
+ * therefore {@link Unpreemptible}.
+ *
+ * This pragma is used to declare that a particular method is preemptible. It
+ * is used to override the class-wide pragma {@link Unpreemptible}.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Pragma
+public @interface Preemptible {
+  /**
+   * @return Explanation of why code needs to be preemptible
+   */
+  String value() default "";
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Pure.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Pure.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Pure.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Pure.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,31 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma is used to indicate a method has no side effects. Use this pragma
+ * with care as it can cause compile time invocation of the method it is placed
+ * on. This pragma is used to imply weak purity of a method, and as such cannot
+ * remove calls to pure methods - as they may throw exceptions.
+ * {@link <a href="http://jira.codehaus.org/browse/RVM-503">RVM-503</a>}.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD})
+ at Pragma
+public @interface Pure { /* annotation has no value */ }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RawStorage.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RawStorage.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RawStorage.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RawStorage.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,36 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * When applied to class this annotation indicates that the data component
+ * of this field consists of an intrisically managed chunk of raw memory of
+ * the specified size. This is used as the basic building block for native
+ * width types.
+ *
+ * To construct types larger than those possible with RawStorage, simply
+ * construct an type with multiple (Unboxed) fields.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE})
+ at Pragma
+public @interface RawStorage {
+  boolean lengthInWords();
+  int length();
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimeFinal.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimeFinal.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimeFinal.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimeFinal.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,32 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma is used to indicate a field will be final in the running VM. We
+ * can't indicate all fields are final as some are used in the boot strap
+ * process.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.FIELD})
+ at Pragma
+public @interface RuntimeFinal {
+  /** The value of the field. Currently only boolean values can be RuntimeFinal. */
+  boolean value();
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimePure.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimePure.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimePure.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/RuntimePure.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,36 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma is a variant of Pure that is used to mark methods that have a
+ * special behaviour at boot image writing time and are Pure at runtime
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD})
+ at Pragma
+public @interface RuntimePure {
+  /** Enumeration of the special boot image return values */
+  public enum ReturnValue {
+    /** the return value is unavailable until runtime*/
+    Unavailable
+  }
+  /** What value should be returned */
+  ReturnValue value() default ReturnValue.Unavailable;
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SaveVolatile.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SaveVolatile.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SaveVolatile.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SaveVolatile.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,30 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * Methods of a class that implements this interface
+ * are treated specially by the machine code compiler:
+ * the method prologue saves all the volatile registers
+ * and the method epilogue restores all the volatile registers
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+ at Pragma
+public @interface SaveVolatile { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SpecializedMethodInvoke.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SpecializedMethodInvoke.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SpecializedMethodInvoke.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SpecializedMethodInvoke.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,30 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * This pragma indicates that a particular method is a specialized
+ * method invocation point, and could be optimized as such.
+ *
+ * All such methods must be static.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Pragma
+public @interface SpecializedMethodInvoke { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SynchronizedObject.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SynchronizedObject.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SynchronizedObject.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SynchronizedObject.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,29 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.vmmagic.Pragma;
+
+/**
+ * This interface designates an object which should always be allocated a
+ * thin lock, since it is likely to be synchronized.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+ at Pragma
+public @interface SynchronizedObject {
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SysCallNative.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SysCallNative.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SysCallNative.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/SysCallNative.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,32 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * An annotation for static native methods to show that they should be
+ * compiled as system calls. A system call is a lightweight call to a
+ * C function that doesn't set up the JNI environment and is therefore
+ * cheaper than JNI. The first argument to the function is the address
+ * of the C function to run.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD})
+ at Pragma
+public @interface SysCallNative {
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Uninterruptible.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Uninterruptible.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Uninterruptible.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Uninterruptible.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,64 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * By default all Java code is interruptible, that is scheduling or garbage
+ * collection may occur at points within the code. Code can be marked as
+ * {@link Unpreemptible} or {@link Uninterruptible}, that instructs the JVM to
+ * avoid garbage collection and thread scheduling. The {@link Uninterruptible}
+ * annotation disallows any operation that may cause garbage collection or
+ * thread scheduling, for example memory allocation. The {@link Unpreemptible}
+ * annotation doesn't disallow operations that can cause garbage collection or
+ * scheduling, but instructs the JVM to avoid inserting such operations during a
+ * block of code.
+ *
+ * In the internals of a VM most code wants to be {@link Uninterruptible}.
+ * However, code involved in scheduling and locking will cause context switches,
+ * and creating exception objects may trigger garbage collection, this code is
+ * therefore {@link Unpreemptible}.
+ *
+ * Any method that is marked as uninterruptible is treated specially by the
+ * machine code compiler:
+ *
+ * (1) the normal thread switch test that would be emitted in the method
+ * prologue is omitted.
+ *
+ * (2) the stack overflow test that would be emitted in the method prologue is
+ * omitted.
+ *
+ * (3) calls to preemptible code causes warnings.
+ *
+ * (4) bytecodes that can cause interruption cause warnings.
+ *
+ * (5) uninterruptible code will be generated assuming no RuntimeExceptions are
+ * raised and without any GC maps (since by definition there can be noGC if
+ * control is not lost).
+ *
+ * This is the inverse of {@link Interruptible}.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Pragma
+public @interface Uninterruptible {
+  /**
+   * @return Explanation of why code needs to be uninterruptible
+   */
+  String value() default "";
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UninterruptibleNoWarn.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UninterruptibleNoWarn.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UninterruptibleNoWarn.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UninterruptibleNoWarn.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,35 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * A pragma that has the same direct effect as {@link Uninterruptible}
+ * but also suppresses checking of uninterruptibility violations for
+ * the method. This should be used with care and is only justified
+ * for code only executed when creating the boot image.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Pragma
+public @interface UninterruptibleNoWarn {
+  /**
+   * @return Explanation of why uninterruptible warnings are disabled
+   */
+  String value() default "";
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Unpreemptible.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Unpreemptible.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Unpreemptible.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Unpreemptible.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,58 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * By default all Java code is interruptible, that is scheduling or garbage
+ * collection may occur at points within the code. Code can be marked as
+ * {@link Unpreemptible} or {@link Uninterruptible}, that instructs the JVM to
+ * avoid garbage collection and thread scheduling. The {@link Uninterruptible}
+ * annotation disallows any operation that may cause garbage collection or
+ * thread scheduling, for example memory allocation. The {@link Unpreemptible}
+ * annotation doesn't disallow operations that can cause garbage collection or
+ * scheduling, but instructs the JVM to avoid inserting such operations during a
+ * block of code.
+ *
+ * In the internals of a VM most code wants to be {@link Uninterruptible}.
+ * However, code involved in scheduling and locking will cause context switches,
+ * and creating exception objects may trigger garbage collection, this code is
+ * therefore {@link Unpreemptible}.
+ *
+ * Any method that is marked as unpreemptible is treated specially by the
+ * machine code compiler:
+ *
+ * (1) the normal thread switch test that would be emitted in the method
+ * prologue is omitted.
+ *
+ * (2) the stack overflow test that would be emitted in the method prologue is
+ * omitted.
+ *
+ * (3) calls to preemptible code causes warnings.
+ *
+ * This is the inverse of {@link Preemptible}.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Pragma
+public @interface Unpreemptible {
+  /**
+   * @return Explanation of why code needs to be unpreemptible
+   */
+  String value() default "";
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UnpreemptibleNoWarn.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UnpreemptibleNoWarn.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UnpreemptibleNoWarn.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/UnpreemptibleNoWarn.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,33 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import org.vmmagic.Pragma;
+
+/**
+ * A special case of {@link Unpreemptible} where the code may call out to other
+ * interruptible routines.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Pragma
+public @interface UnpreemptibleNoWarn {
+  /**
+   * @return Explanation of why code needs to be unpreemptible
+   */
+  String value() default "";
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Untraced.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Untraced.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Untraced.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/pragma/Untraced.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,31 @@
+/*
+ *  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.vmmagic.pragma;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+
+/**
+ * Use this annotation to mark fields that are read without the knowledge of the
+ * memory management system. This means that barriers are not triggered and
+ * the reference is also not traced by the garbage collector.
+ *
+ * As annotations are loaded at class resolution time, fields marked with this
+ * annotation must be private so that no unresolved accesses are compiled to them with
+ * barriers.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.FIELD)
+public @interface Untraced { }

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Address.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Address.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Address.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Address.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,952 @@
+/*
+ *  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.vmmagic.unboxed;
+
+import org.vmmagic.Unboxed;
+import org.vmmagic.pragma.RawStorage;
+
+/**
+ * <b>Stub</b> implementation of an Address type, intended only to
+ * allow the core of MMTk to be compiled.  This <b>must</b> be
+ * replaced with a concrete implementation appropriate to a specific
+ * VM.
+ *
+ * The address type is used by the runtime system and collector to
+ * denote machine addresses.  We use a separate type instead of the
+ * Java int type for coding clarity,  machine-portability (it can map
+ * to 32 bit and 64 bit integral types), and access to unsigned
+ * operations (Java does not have unsigned int types).
+ */
+ at Unboxed
+ at RawStorage(lengthInWords = true, length = 1)
+public final class Address {
+
+  /****************************************************************************
+   *
+   * Special values
+   */
+
+  /**
+   * Return an <code>Address</code> instance that reflects the value
+   * zero.
+   *
+   * @return An address instance that reflects the value zero.
+   */
+  public static Address zero() {
+    return null;
+  }
+
+  /**
+   * Return <code>true</code> if this instance is zero.
+   *
+   * @return <code>true</code> if this instance is zero.
+   */
+  public boolean isZero() {
+    return false;
+  }
+
+  /**
+   * Return an <code>Address</code> instance that reflects the maximum
+   * allowable <code>Address</code> value.
+   *
+   * @return An <code>Address</code> instance that reflects the
+   * maximum allowable <code>Address</code> value.
+   */
+  public static Address max() {
+    return null;
+  }
+
+  /**
+   * Return <code>true</code> if this instance is the maximum
+   * allowable <code>Address</code> value.
+   *
+   * @return <code>true</code> if this instance is the maximum
+   * allowable <code>Address</code> valu.
+   */
+  public boolean isMax() {
+    return false;
+  }
+
+  /****************************************************************************
+   *
+   * Conversions
+   */
+
+  /**
+   * Fabricate an <code>Address</code> instance from an integer, after
+   * sign extending the integer.
+   *
+   * @param address the integer from which to create an <code>Address</code>
+   *          instance
+   * @return An address instance
+   */
+  public static Address fromIntSignExtend(int address) {
+    return null;
+  }
+
+  /**
+   * Fabricate an <code>Address</code> instance from an integer, after
+   * zero extending the integer.
+   *
+   * @param address the integer from which to create an <code>Address</code>
+   *          instance
+   * @return An address instance
+   */
+  public static Address fromIntZeroExtend(int address) {
+    return null;
+  }
+
+  /**
+   * Fabricate an <code>Address</code> instance from an integer
+   *
+   * @param address the integer from which to create an <code>Address</code>
+   *          instance
+   * @return An address instance
+   */
+  public static Address fromLong(long address) {
+    return null;
+  }
+
+  /**
+   * Fabricate an <code>ObjectReference</code> instance from an
+   * <code>Address</code> instance.  It is the user's responsibility
+   * to ensure that the <code>Address</code> is suitable (i.e. it
+   * points to the object header, or satisfies any other VM-specific
+   * requirement for such a conversion).
+   *
+   * @return An <code>ObjectReference</code> instance.
+   */
+  public ObjectReference toObjectReference() {
+    return null;
+  }
+
+  /**
+   * Return an integer that reflects the value of this
+   * <code>Address</code> instance.
+   *
+   * @return An integer that reflects the value of this
+   * <code>Address</code> instance.
+   */
+  public int toInt() {
+    return 0;
+  }
+
+  /**
+   * Return an long that reflects the value of this
+   * <code>Address</code> instance.
+   *
+   * @return An long that reflects the value of this
+   * <code>Address</code> instance.
+   */
+  public long toLong() {
+    return 0;
+  }
+
+  /**
+   * Return a <code>Word</code> instance that reflects the value of
+   * this <code>Address</code> instance.
+   *
+   * @return A <code>Word</code> instance that reflects the value of
+   * this <code>Address</code> instance.
+   */
+  public Word toWord() {
+    return null;
+  }
+
+  /****************************************************************************
+   *
+   * Arithemtic operators
+   */
+
+  /**
+   * Add an integer to this <code>Address</code>, and return the sum.
+   *
+   * @param  v the value to be added to this <code>Address</code>
+   * @return An <code>Address</code> instance that reflects the result
+   * of the addition.
+   */
+  public Address plus(int v) {
+    return null;
+  }
+
+  /**
+   * Add an <code>Offset</code> to this <code>Address</code>, and
+   * return the sum.
+   *
+   * @param offset the <code>Offset</code> to be added to the address
+   * @return An <code>Address</code> instance that reflects the result
+   * of the addition.
+   */
+  public Address plus(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Add an <code>Extent</code> to this <code>Address</code>, and
+   * return the sum.
+   *
+   * @param extent the <code>Extent</code> to be added to this
+   * <code>Address</code>
+   * @return An <code>Address</code> instance that reflects the result
+   * of the addition.
+   */
+  public Address plus(Extent extent) {
+    return null;
+  }
+
+  /**
+   * Subtract an integer from this <code>Address</code>, and return
+   * the result.
+   *
+   * @param v the integer to be subtracted from this
+   * <code>Address</code>.
+   * @return An <code>Address</code> instance that reflects the result
+   * of the subtraction.
+   */
+  public Address minus(int v) {
+    return null;
+  }
+
+  /**
+   * Subtract an <code>Offset</code> from this <code>Address</code>, and
+   * return the result.
+   *
+   * @param offset the <code>Offset</code> to be subtracted from this
+   *          <code>Address</code>.
+   * @return An <code>Address</code> instance that reflects the result
+   * of the subtraction.
+   */
+  public Address minus(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Subtract an <code>Extent</code> from this <code>Address</code>, and
+   * return the result.
+   *
+   * @param extent the <code>Extent</code> to be subtracted from this
+   *          <code>Address</code>.
+   * @return An <code>Address</code> instance that reflects the result
+   * of the subtraction.
+   */
+  public Address minus(Extent extent) {
+    return null;
+  }
+
+  /**
+   * Compute the difference between two <code>Address</code>es and
+   * return the result.
+   *
+   * @param addr2 the <code>Address</code> to be subtracted from this
+   *          <code>Address</code>.
+   * @return An <code>Offset</code> instance that reflects the result
+   * of the subtraction.
+   */
+  public Offset diff(Address addr2) {
+    return null;
+  }
+
+  /****************************************************************************
+   *
+   * Boolean operators
+   */
+
+  /**
+   * Return true if this <code>Address</code> instance is <i>less
+   * than</i> <code>addr2</code>.
+   *
+   * @param addr2 the <code>Address</code> to be compared to this
+   *          <code>Address</code>.
+   * @return true if this <code>Address</code> instance is <i>less
+   * than</i> <code>addr2</code>.
+   */
+  public boolean LT(Address addr2) {
+    return false;
+  }
+
+  /**
+   * Return true if this <code>Address</code> instance is <i>less
+   * than or equal to</i> <code>addr2</code>.
+   *
+   * @param addr2 the <code>Address</code> to be compared to this
+   *          <code>Address</code>.
+   * @return true if this <code>Address</code> instance is <i>less
+   * than or equal to</i> <code>addr2</code>.
+   */
+  public boolean LE(Address addr2) {
+    return false;
+  }
+
+  /**
+   * Return true if this <code>Address</code> instance is <i>greater
+   * than</i> <code>addr2</code>.
+   *
+   * @param addr2 the <code>Address</code> to be compared to this
+   *          <code>Address</code>.
+   * @return true if this <code>Address</code> instance is <i>greater
+   * than</i> <code>addr2</code>.
+   */
+  public boolean GT(Address addr2) {
+    return false;
+  }
+
+  /**
+   * Return true if this <code>Address</code> instance is <i>greater
+   * than or equal to</i> <code>addr2</code>.
+   *
+   * @param addr2 the <code>Address</code> to be compared to this
+   *          <code>Address</code>.
+   * @return true if this <code>Address</code> instance is <i>greater
+   * than or equal to</i> <code>addr2</code>.
+   */
+  public boolean GE(Address addr2) {
+    return false;
+  }
+
+  /**
+   * Return true if this <code>Address</code> instance is <i>equal
+   * to</i> <code>addr2</code>.
+   *
+   * @param addr2 the <code>Address</code> to be compared to this
+   *          <code>Address</code>.
+   * @return true if this <code>Address</code> instance is <i>equal
+   * to</i> <code>addr2</code>.
+   */
+  public boolean EQ(Address addr2) {
+    return false;
+  }
+
+  /**
+   * Return true if this <code>Address</code> instance is <i>not equal
+   * to</i> <code>addr2</code>.
+   *
+   * @param addr2 the <code>Address</code> to be compared to this
+   *          <code>Address</code>.
+   * @return true if this <code>Address</code> instance is <i>not
+   * equal to</i> <code>addr2</code>.
+   */
+  public boolean NE(Address addr2) {
+    return false;
+  }
+
+  /****************************************************************************
+   *
+   * Software prefetch operators etc
+   */
+
+  /**
+   * Prefetch a cache-line, architecture-independent
+   */
+  public void prefetch() {
+  }
+
+  /****************************************************************************
+   *
+   * Memory access operators
+   */
+
+  /**
+   * Loads a reference from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public ObjectReference loadObjectReference() {
+    return null;
+  }
+
+  /**
+   * Loads a reference from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public ObjectReference loadObjectReference(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Loads a byte from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public byte loadByte() {
+    return (byte) 0;
+  }
+
+  /**
+   * Loads a byte from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public byte loadByte(Offset offset) {
+    return (byte) 0;
+  }
+
+  /**
+   * Loads a char from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public char loadChar() {
+    return (char) 0;
+  }
+
+  /**
+   * Loads a char from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public char loadChar(Offset offset) {
+    return (char) 0;
+  }
+
+  /**
+   * Loads a short from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public short loadShort() {
+    return (short) 0;
+  }
+
+  /**
+   * Loads a short from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public short loadShort(Offset offset) {
+    return (short) 0;
+  }
+
+  /**
+   * Loads a float from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public float loadFloat() {
+    return (float) 0;
+  }
+
+  /**
+   * Loads a float from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public float loadFloat(Offset offset) {
+    return (float) 0;
+  }
+
+  /**
+   * Loads an int from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public int loadInt() {
+    return 0;
+  }
+
+  /**
+   * Loads an int from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public int loadInt(Offset offset) {
+    return 0;
+  }
+
+
+  /**
+   * Loads a long from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public long loadLong() {
+    return 0L;
+  }
+
+  /**
+   * Loads a long from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public long loadLong(Offset offset) {
+    return 0L;
+  }
+
+  /**
+   * Loads a double from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read value
+   */
+  public double loadDouble() {
+    return 0;
+  }
+
+  /**
+   * Loads a double from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read value
+   */
+  public double loadDouble(Offset offset) {
+    return 0;
+  }
+
+
+  /**
+   * Loads an address value from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read address value.
+   */
+  public Address loadAddress() {
+    return null;
+  }
+
+  /**
+   * Loads an address value from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read address value.
+   */
+  public Address loadAddress(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Loads a word value from the memory location pointed to by the
+   * current instance.
+   *
+   * @return the read word value.
+   */
+  public Word loadWord() {
+    return null;
+  }
+
+  /**
+   * Loads a word value from the memory location pointed to by the
+   * current instance.
+   *
+   * @param offset the offset to the value.
+   * @return the read word value.
+   */
+  public Word loadWord(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Stores the address value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The address value to store.
+   */
+  public void store(ObjectReference value) {
+  }
+
+  /**
+   * Stores the object reference value in the memory location pointed
+   * to by the current instance.
+   *
+   * @param value The object reference value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(ObjectReference value, Offset offset) {
+  }
+
+  /**
+   * Stores the address value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The address value to store.
+   */
+  public void store(Address value) {
+  }
+
+  /**
+   * Stores the address value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The address value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(Address value, Offset offset) {
+  }
+
+  /**
+   * Stores the float value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The float value to store.
+   */
+  public void store(float value) {
+  }
+
+  /**
+   * Stores the float value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The float value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(float value, Offset offset) {
+  }
+
+  /**
+   * Stores the word value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The word value to store.
+   */
+  public void store(Word value) {
+  }
+
+  /**
+   * Stores the word value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The word value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(Word value, Offset offset) {
+  }
+
+  /**
+   * Stores the byte value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The byte value to store.
+   */
+  public void store(byte value) {
+  }
+
+  /**
+   * Stores the byte value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value The byte value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(byte value, Offset offset) {
+  }
+
+
+  /**
+   * Stores an int value in memory location pointed to by the
+   * current instance.
+   *
+   * @param value The int value to store.
+   */
+  public void store(int value) {
+  }
+
+  /**
+   * Stores an int value in memory location pointed to by the
+   * current instance.
+   *
+   * @param value The int value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(int value, Offset offset) {
+  }
+
+  /**
+   * Stores a double value in memory location pointed to by the
+   * current instance.
+   *
+   * @param value The double value to store.
+   */
+  public void store(double value) {
+  }
+
+  /**
+   * Stores a double value in memory location pointed to by the
+   * current instance.
+   *
+   * @param value The double value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(double value, Offset offset) {
+  }
+
+
+  /**
+   * Stores a double value in memory location pointed to by the
+   * current instance.
+   *
+   * @param value The double value to store.
+   */
+  public void store(long value) {
+  }
+
+  /**
+   * Stores a double value in memory location pointed to by the
+   * current instance.
+   *
+   * @param value The double value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(long value, Offset offset) {
+  }
+
+  /**
+   * Stores a char value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value the char value to store.
+   */
+  public void store(char value) {
+  }
+
+  /**
+   * Stores a char value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value the char value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(char value, Offset offset) {
+  }
+
+  /**
+   * Stores a short value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value the short value to store.
+   */
+  public void store(short value) {
+  }
+
+  /**
+   * Stores a short value in the memory location pointed to by the
+   * current instance.
+   *
+   * @param value the short value to store.
+   * @param offset the offset to the value.
+   */
+  public void store(short value, Offset offset) {
+  }
+
+  /****************************************************************************
+   *
+   * Atomic memory access operators (compare and swap)
+   */
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @return the old value to be passed to an attempt call.
+   */
+  public Word prepareWord() {
+    return null;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @param offset the offset to the value.
+   * @return the old value to be passed to an attempt call.
+   */
+  public Word prepareWord(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @return the old value to be passed to an attempt call.
+   */
+  public ObjectReference prepareObjectReference() {
+    return null;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @param offset the offset to the value.
+   * @return the old value to be passed to an attempt call.
+   */
+  public ObjectReference prepareObjectReference(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @return the old value to be passed to an attempt call.
+   */
+  public Address prepareAddress() {
+    return null;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @param offset the offset to the value.
+   * @return the old value to be passed to an attempt call.
+   */
+  public Address prepareAddress(Offset offset) {
+    return null;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @return the old value to be passed to an attempt call.
+   */
+  public int prepareInt() {
+    return 0;
+  }
+
+  /**
+   * Prepare for an atomic store operation. This must be associated with
+   * a related call to attempt.
+   *
+   * @param offset the offset to the value.
+   * @return the old value to be passed to an attempt call.
+   */
+  public int prepareInt(Offset offset) {
+    return 0;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(int old, int value) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @param offset the offset to the value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(int old, int value, Offset offset) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(Word old, Word value) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @param offset the offset to the value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(Word old, Word value, Offset offset) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(ObjectReference old, ObjectReference value) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @param offset the offset to the value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(ObjectReference old, ObjectReference value,
+      Offset offset) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(Address old, Address value) {
+    return false;
+  }
+
+  /**
+   * Attempt an atomic store operation. This must be associated with a
+   * related call to prepare.
+   *
+   * @param old the old value.
+   * @param value the new value.
+   * @param offset the offset to the value.
+   * @return true if the attempt was successful.
+   */
+  public boolean attempt(Address old, Address value, Offset offset) {
+    return false;
+  }
+
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/AddressArray.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/AddressArray.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/AddressArray.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/AddressArray.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.vmmagic.unboxed;
+
+public final class AddressArray {
+
+  private final Address[] data;
+
+  private AddressArray(int size) {
+    data = new Address[size];
+    Address zero = Address.zero();
+    for(int i=0; i<size;i++) {
+      data[i] = zero;
+    }
+  }
+
+  public static AddressArray create(int size) {
+    return new AddressArray(size);
+  }
+
+  public Address get(int index) {
+    return data[index];
+  }
+
+  public void set(int index, Address v) {
+    data[index] = v;
+  }
+
+  public int length() {
+    return data.length;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Extent.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Extent.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Extent.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Extent.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,93 @@
+/*
+ *  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.vmmagic.unboxed;
+
+import org.vmmagic.Unboxed;
+import org.vmmagic.pragma.RawStorage;
+
+ at Unboxed
+ at RawStorage(lengthInWords = true, length = 1)
+public final class Extent {
+  public static Extent fromIntSignExtend(int address) {
+    return null;
+  }
+
+  public static Extent fromIntZeroExtend(int address) {
+    return null;
+  }
+
+  public static Extent zero() {
+    return null;
+  }
+
+  public static Extent one() {
+    return null;
+  }
+
+  public static Extent max() {
+    return null;
+  }
+
+  public int toInt() {
+    return 0;
+  }
+
+  public long toLong() {
+    return 0L;
+  }
+
+  public Word toWord() {
+    return null;
+  }
+
+  public Extent plus(int byteSize) {
+    return null;
+  }
+
+  public Extent plus(Extent byteSize) {
+    return null;
+  }
+
+  public Extent minus(int byteSize) {
+    return null;
+  }
+
+  public Extent minus(Extent byteSize) {
+    return null;
+  }
+
+  public boolean LT(Extent extent2) {
+    return false;
+  }
+
+  public boolean LE(Extent extent2) {
+    return false;
+  }
+
+  public boolean GT(Extent extent2) {
+    return false;
+  }
+
+  public boolean GE(Extent extent2) {
+    return false;
+  }
+
+  public boolean EQ(Extent extent2) {
+    return false;
+  }
+
+  public boolean NE(Extent extent2) {
+    return false;
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ExtentArray.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ExtentArray.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ExtentArray.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ExtentArray.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.vmmagic.unboxed;
+
+public final class ExtentArray {
+
+  private final Extent[] data;
+
+  private ExtentArray(int size) {
+    data = new Extent[size];
+    Extent zero = Extent.zero();
+    for(int i=0; i<size;i++) {
+      data[i] = zero;
+    }
+  }
+
+  public static ExtentArray create(int size) {
+    return new ExtentArray(size);
+  }
+
+  public Extent get(int index) {
+    return data[index];
+  }
+
+  public void set(int index, Extent v) {
+    data[index] = v;
+  }
+
+  public int length() {
+    return data.length;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReference.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReference.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReference.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReference.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,72 @@
+/*
+ *  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.vmmagic.unboxed;
+
+import org.vmmagic.Unboxed;
+
+/**
+ * The object reference type is used by the runtime system and collector to
+ * represent a type that holds a reference to a single object.
+ * We use a separate type instead of the Java Object type for coding clarity,
+ * to make a clear distinction between objects the VM is written in, and
+ * objects that the VM is managing. No operations that can not be completed in
+ * pure Java should be allowed on Object.
+ */
+ at Unboxed
+public final class ObjectReference {
+
+  /**
+   * The object field.
+   */
+  @SuppressWarnings("unused")
+  private Object data;
+
+  /**
+   * Convert from an object to a reference.
+   * @param obj The object
+   * @return The corresponding reference
+   */
+  public static ObjectReference fromObject(Object obj) {
+    return null;
+  }
+
+  /**
+   * Return a null reference
+   */
+  public static ObjectReference nullReference() {
+    return null;
+  }
+
+  /**
+   * Convert from an reference to an object. Note: this is a JikesRVM
+   * specific extension to vmmagic.
+   * @return The object
+   */
+  public Object toObject() {
+    return null;
+  }
+
+  /**
+   * Get a heap address for the object.
+   */
+  public Address toAddress() {
+    return null;
+  }
+
+  /**
+   * Is this a null reference?
+   */
+  public boolean isNull() {
+    return false;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReferenceArray.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReferenceArray.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReferenceArray.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/ObjectReferenceArray.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.vmmagic.unboxed;
+
+public final class ObjectReferenceArray {
+
+  private final ObjectReference[] data;
+
+  private ObjectReferenceArray(int size) {
+    data = new ObjectReference[size];
+    ObjectReference nullRef = ObjectReference.nullReference();
+    for(int i=0; i<size;i++) {
+      data[i] = nullRef;
+    }
+  }
+
+  public static ObjectReferenceArray create(int size) {
+    return new ObjectReferenceArray(size);
+  }
+
+  public ObjectReference get(int index) {
+    return data[index];
+  }
+
+  public void set(int index, ObjectReference v) {
+    data[index] = v;
+  }
+
+  public int length() {
+    return data.length;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Offset.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Offset.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Offset.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Offset.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,97 @@
+/*
+ *  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.vmmagic.unboxed;
+
+import org.vmmagic.Unboxed;
+import org.vmmagic.pragma.RawStorage;
+
+/**
+ * To be commented
+ */
+ at Unboxed
+ at RawStorage(lengthInWords = true, length = 1)
+public final class Offset {
+
+  public static Offset fromIntSignExtend(int address) {
+    return null;
+  }
+
+  public static Offset fromIntZeroExtend(int address) {
+    return null;
+  }
+
+  public static Offset zero() {
+    return null;
+  }
+
+  public static Offset max() {
+    return null;
+  }
+
+  public int toInt() {
+    return 0;
+  }
+
+  public long toLong() {
+    return 0L;
+  }
+
+  public Word toWord() {
+    return null;
+  }
+
+  public Offset plus(int byteSize) {
+    return null;
+  }
+
+  public Offset minus(int byteSize) {
+    return null;
+  }
+
+  public Offset minus(Offset off2) {
+    return null;
+  }
+
+  public boolean EQ(Offset off2) {
+    return false;
+  }
+
+  public boolean NE(Offset off2) {
+    return false;
+  }
+
+  public boolean sLT(Offset off2) {
+    return false;
+  }
+
+  public boolean sLE(Offset off2) {
+    return false;
+  }
+
+  public boolean sGT(Offset off2) {
+    return false;
+  }
+
+  public boolean sGE(Offset off2) {
+    return false;
+  }
+
+  public boolean isZero() {
+    return false;
+  }
+
+  public boolean isMax() {
+    return false;
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/OffsetArray.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/OffsetArray.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/OffsetArray.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/OffsetArray.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.vmmagic.unboxed;
+
+public final class OffsetArray {
+
+  private final Offset[] data;
+
+  private OffsetArray(int size) {
+    data = new Offset[size];
+    Offset zero = Offset.zero();
+    for(int i=0; i<size;i++) {
+      data[i] = zero;
+    }
+  }
+
+  public static OffsetArray create(int size) {
+    return new OffsetArray(size);
+  }
+
+  public Offset get(int index) {
+    return data[index];
+  }
+
+  public void set(int index, Offset v) {
+    data[index] = v;
+  }
+
+  public int length() {
+    return data.length;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Word.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Word.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Word.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/Word.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,319 @@
+/*
+ *  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.vmmagic.unboxed;
+
+import org.vmmagic.Unboxed;
+import org.vmmagic.pragma.RawStorage;
+
+/**
+ * (Mistakes in) comments by Robin Garner
+ * @see Address
+ */
+ at Unboxed
+ at RawStorage(lengthInWords = true, length = 1)
+public final class Word {
+
+  /**
+   * Convert an into to a word.  On 64-bit machines, sign-extend the
+   * high order bit.
+   *
+   * @param val
+   * @return A word instance whose value is val, sign-extended on 64 bit machines
+   */
+  public static Word fromIntSignExtend(int val) {
+    return null;
+  }
+
+  /**
+   * Convert an int to a word.  On 64-bit machines, zero-extend the
+   * high order bit.
+   *
+   * @param val
+   * @return A word instance whose value is val, zero-extended on 64 bit machines
+   */
+  public static Word fromIntZeroExtend(int val) {
+    return null;
+  }
+
+  /**
+   * Convert a long to a word.  On 64-bit this is a no-op.
+   * TODO document behaviour on 32-bit.  Truncate ?
+   *
+   * @param val
+   * @return A word instance whose value is val on 32 bit machine this truncates the upper 32 bits.
+   */
+  public static Word fromLong(long val) {
+    return null;
+  }
+
+  /**
+   * The Word constant 0.
+   * Equivalent to Word.fromIntSignExtend(0), but more readable.
+   *
+   * @return the Word constant 0.
+   */
+  public static Word zero() {
+    return null;
+  }
+
+  /**
+   * The Word constant 1.
+   * Equivalent to Word.fromIntSignExtend(1), but more readable.
+   *
+   * @return the Word constant 1.
+   */
+  public static Word one() {
+    return null;
+  }
+
+  /**
+   * The maximum representable Word value.  Words are unsigned, so this is
+   * a word full of 1s, 32/64-bit safe.
+   *
+   * @return the maximum representable Word value
+   */
+  public static Word max() {
+    return null;
+  }
+
+  /**
+   * Type-cast to an int, truncating on 64-bit platforms.
+   *
+   * @return an int, with the same value as the word on 32 bit platforms; truncates on 64 bit platforms.
+   */
+  public int toInt() {
+    return 0;
+  }
+
+  /**
+   * Type-cast to a long, zero-extending on a 32-bit platform.
+   * @return a long, with the same value as the word (zero extends on 32 bit platforms).
+   */
+  public long toLong() {
+    return 0L;
+  }
+
+  /** Type-cast to an address. */
+  public Address toAddress() {
+    return null;
+  }
+
+  /** Type-cast to an offset */
+  public Offset toOffset() {
+    return null;
+  }
+
+  /** Type-cast to an extent */
+  public Extent toExtent() {
+    return null;
+  }
+
+  /**
+   * Add two words
+   *
+   * @param w2
+   * @return The word whose value is this+w2
+   */
+  public Word plus(Word w2) {
+    return null;
+  }
+
+  /**
+   * Add an offset to a word
+   * @param w2
+   * @return The word whose value is this+w2
+   */
+  public Word plus(Offset w2) {
+    return null;
+  }
+
+  /**
+   * Add an extent to a word
+   * @param w2
+   * @return The word whose value is this+w2
+   */
+  public Word plus(Extent w2) {
+    return null;
+  }
+
+  /**
+   * Subtract two words
+   * @param w2
+   * @return The word whose value is this-w2
+   */
+  public Word minus(Word w2) {
+    return null;
+  }
+
+  /**
+   * Subtract an offset from a word
+   * @param w2
+   * @return The word whose value is this-w2
+   */
+  public Word minus(Offset w2) {
+    return null;
+  }
+
+  /**
+   * Subtract an extent from a word.
+   * @param w2
+   * @return The word whose value is this-w2
+   */
+  public Word minus(Extent w2) {
+    return null;
+  }
+
+  /**
+   * Test for zero.  Equivalent to .EQ(Word.zero())
+   * @return return true if this is equal to Word.zero(), false otherwise
+   */
+  public boolean isZero() {
+    return false;
+  }
+
+  /**
+   * Test for zero.  Equivalent to .EQ(Word.max())
+   * @return true if this is equal to Word.max(), false otherwise
+   */
+  public boolean isMax() {
+    return false;
+  }
+
+  /**
+   * Less-than comparison
+   * @param addr2
+   * @return true if this <code>Word</code> instance is <i>less than</i> <code>addr2</code>
+   */
+  public boolean LT(Word addr2) {
+    return false;
+  }
+
+  /**
+   * Less-than or equal comparison
+   * @param w2
+   * @return true if this <code>Word</code> instance is <i>less than or equal to</i> <code>w2</code>
+   */
+  public boolean LE(Word w2) {
+    return false;
+  }
+
+  /**
+   * Greater-than comparison
+   * @param w2
+   * @return true if this <code>Word</code> instance is <i>greater than</i> <code>w2</code>
+   */
+  public boolean GT(Word w2) {
+    return false;
+  }
+
+  /**
+   * Greater-than or equal comparison
+   * @param w2
+   * @return true if this <code>Word</code> instance is <i>greater than or equal to</i> <code>w2</code>
+   */
+  public boolean GE(Word w2) {
+    return false;
+  }
+
+  /**
+   * Equality comparison
+   * @param w2
+   * @return true if this <code>Word</code> instance is <i>equal to</i> <code>w2</code>
+   */
+  public boolean EQ(Word w2) {
+    return false;
+  }
+
+  /**
+   * Not-equal comparison
+   * @param w2
+   * @return true if this <code>Word</code> instance is <i>not equal to</i> <code>w2</code>
+   */
+  public boolean NE(Word w2) {
+    return false;
+  }
+
+  /**
+   * Bit-wise and of two words.
+   * @param w2
+   * @return The word whose value is the bitwise and of this and w2
+   */
+  public Word and(Word w2) {
+    return null;
+  }
+
+  /**
+   * Bit-wise or of two words.
+   * @param w2
+   * @return The word whose value is the bitwise not of this and w2
+   */
+  public Word or(Word w2) {
+    return null;
+  }
+
+  /**
+   * Bit-wise complement of a word.
+   * @return the bitwise complement of this
+   */
+  public Word not() {
+    return null;
+  }
+
+  /**
+   * Bit-wise exclusive or of two words.
+   * @param w2
+   * @return The word whose value is the bitwise xor of this and w2
+   */
+  public Word xor(Word w2) {
+    return null;
+  }
+
+  /**
+   * Left-shift a word. Shifts of a size greater than the Word are undefined and
+   * have an architecture and compiler specific behaviour. On Intel the shift
+   * amount ignores the most significant bits, for example for a 32bit Word 1
+   * << 32 == 1, the result will be 0 on PowerPC. Shifts may or may not be
+   * combined by the compiler, this yields differing behaviour, for example for a
+   * 32bit Word 1 <<32 may or may not equal 1 << 16 << 16.
+   *
+   * @param amt the amount to shift by
+   * @return new Word shifted by the given amount
+   */
+  public Word lsh(int amt) {
+    return null;
+  }
+
+  /**
+   * Logical right-shift a word. Shifts of a size greater than the Word are undefined and
+   * have an architecture and compiler specific behaviour see also {@link #lsh(int)}.
+   *
+   * @param amt the amount to shift by
+   * @return new Word shifted by the given amount
+   */
+  public Word rshl(int amt) {
+    return null;
+  }
+
+  /**
+   * Arithmetic right-shift a word. Shifts of a size greater than the Word are undefined and
+   * have an architecture and compiler specific behaviour see also {@link #lsh(int)}.
+   * Arithmetic right-shift a word.  Equivalent to the integer <code>>></code> operator
+   *
+   * @param amt the amount to shift by
+   * @return new Word shifted by the given amount
+   */
+  public Word rsha(int amt) {
+    return null;
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/WordArray.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/WordArray.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/WordArray.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmmagic/unboxed/WordArray.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+/*
+ *  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.vmmagic.unboxed;
+
+public final class WordArray {
+
+  private final Word[] data;
+
+  private WordArray(int size) {
+    data = new Word[size];
+    Word zero = Word.zero();
+    for(int i=0; i<size;i++) {
+      data[i] = zero;
+    }
+  }
+
+  public static WordArray create(int size) {
+    return new WordArray(size);
+  }
+
+  public Word get(int index) {
+    return data[index];
+  }
+
+  public void set(int index, Word v) {
+    data[index] = v;
+  }
+
+  public int length() {
+    return data.length;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/AddressOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/AddressOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/AddressOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/AddressOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,80 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Address;
+
+/**
+ * An option with a simple integer value.
+ */
+public class AddressOption extends Option {
+  // values
+  protected Address defaultValue;
+  protected Address value;
+
+  /**
+   * Create a new int option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultValue The default value of the option.
+   */
+  protected AddressOption(OptionSet set, String name, String desc, Address defaultValue) {
+    super(set, ADDRESS_OPTION, name, desc);
+    this.value = this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Read the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public Address getValue() {
+    return this.value;
+  }
+
+  /**
+   * Read the default value of the option.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public Address getDefaultValue() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. This method also calls the validate method to allow
+   * subclasses to perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(int value) {
+    this.value = Address.fromIntZeroExtend(value);
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultValue(Address value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/BooleanOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/BooleanOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/BooleanOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/BooleanOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,79 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * Base class for boolean options.
+ */
+public class BooleanOption extends Option {
+  // values
+  protected boolean defaultValue;
+  protected boolean value;
+
+  /**
+   * Create a new boolean option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultValue The default value of the option.
+   */
+  protected BooleanOption(OptionSet set, String name, String desc, boolean defaultValue) {
+    super(set, BOOLEAN_OPTION, name, desc);
+    this.value = this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Read the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public boolean getValue() {
+    return this.value;
+  }
+
+  /**
+   * Read the default value of the option.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public boolean getDefaultValue() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. This method also calls the validate method to allow
+   * subclasses to perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(boolean value) {
+    this.value = value;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultValue(boolean value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/EnumOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/EnumOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/EnumOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/EnumOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,142 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * An option that is a selection of several strings. The mapping
+ * between strings and integers is determined using indexes into
+ * a string array.
+ *
+ * Enumerations are case sensitive.
+ */
+public class EnumOption extends Option {
+  // values
+  protected int defaultValue;
+  protected int value;
+  protected String[] values;
+
+  /**
+   * Create a new enumeration option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param description The purpose of the option.
+   * @param values A mapping of int to string for the enum.
+   * @param defaultValue The default value of the option.
+   */
+  protected EnumOption(OptionSet set, String name, String description, String[] values, String defaultValue) {
+    super(set, ENUM_OPTION, name, description);
+    this.values = values;
+    this.value = this.defaultValue = findValue(defaultValue);
+  }
+
+  /**
+   * Search for a string in the enumeration.
+   *
+   * @return The index of the passed string.
+   */
+  private int findValue(String string) {
+    for (int i = 0; i < values.length; i++) {
+      if (values[i].equals(string)) {
+        return i;
+      }
+    }
+    fail("Invalid Enumeration Value");
+    return -1;
+  }
+
+  /**
+   * Read the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public int getValue() {
+    return this.value;
+  }
+
+  /**
+   * Read the string for the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public String getValueString() {
+    return this.values[this.value];
+  }
+
+  /**
+   * Read the default value of the option.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public int getDefaultValue() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Read the string for the default value of the option.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public String getDefaultValueString() {
+    return this.values[this.defaultValue];
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. This method also calls the validate method to allow
+   * subclasses to perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(int value) {
+    this.value = value;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Look up the value for a string and update the value of the option
+   * accordingly, echoing the change if the echoOptions option is set.
+   * This method also calls the validate method to allow subclasses to
+   * perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(String value) {
+    setValue(findValue(value));
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultValue(String value) {
+    this.value = this.defaultValue = findValue(value);
+  }
+
+  /**
+   * Return the array of allowed enumeration values.
+   *
+   * @return The values array.
+   */
+  public String[] getValues() {
+    return this.values;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/FloatOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/FloatOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/FloatOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/FloatOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,79 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * An option that has a simple single precision floating point value.
+ */
+public class FloatOption extends Option {
+  // values
+  protected float defaultValue;
+  protected float value;
+
+  /**
+   * Create a new float option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultValue The default value of the option.
+   */
+  protected FloatOption(OptionSet set, String name, String desc, float defaultValue) {
+    super(set, FLOAT_OPTION, name, desc);
+    this.value = this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Read the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public float getValue() {
+    return this.value;
+  }
+
+  /**
+   * Read the default value of the option
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public float getDefaultValue() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. This method also calls the validate method to allow
+   * subclasses to perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(float value) {
+    this.value = value;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultValue(float value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/IntOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/IntOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/IntOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/IntOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,79 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * An option with a simple integer value.
+ */
+public class IntOption extends Option {
+  // values
+  protected int defaultValue;
+  protected int value;
+
+  /**
+   * Create a new int option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultValue The default value of the option.
+   */
+  protected IntOption(OptionSet set, String name, String desc, int defaultValue) {
+    super(set, INT_OPTION, name, desc);
+    this.value = this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Read the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public int getValue() {
+    return this.value;
+  }
+
+  /**
+   * Read the default value of the option.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public int getDefaultValue() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. This method also calls the validate method to allow
+   * subclasses to perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(int value) {
+    this.value = value;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultValue(int value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/MicrosecondsOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/MicrosecondsOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/MicrosecondsOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/MicrosecondsOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,101 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * A time option that stores values at a microsecond granularity.
+ */
+public class MicrosecondsOption extends Option {
+  // values
+  protected int defaultValue;
+  protected int value;
+
+  /**
+   * Create a new microsecond option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultUs The default value of the option (usec).
+   */
+  protected MicrosecondsOption(OptionSet set, String name, String desc, int defaultUs) {
+    super(set, MICROSECONDS_OPTION, name, desc);
+    this.value = this.defaultValue = defaultUs;
+  }
+
+  /**
+   * Read the current value of the option in microseconds.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public int getMicroseconds() {
+    return this.value;
+  }
+
+  /**
+   * Read the current value of the option in milliseconds.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public int getMilliseconds() {
+    return this.value / 1000;
+  }
+
+  /**
+   * Read the default value of the option in microseconds.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public int getDefaultMicroseconds() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Read the default value of the option in milliseconds.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public int getDefaultMilliseconds() {
+    return this.defaultValue / 1000;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. An error occurs if the value is negative, and then the
+   * validate method is called to allow subclasses to perform any additional
+   * validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setMicroseconds(int value) {
+    failIf(value < 0, "Unreasonable " + this.getName() + " value");
+    this.value = value;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultMicrosends(int value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/Option.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/Option.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/Option.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/Option.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,176 @@
+/*
+ *  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.vmutil.options;
+
+/**
+ * The abstract base class for all options. This class also has
+ * the static interfaces to access the options system to set
+ * option values.
+ *
+ * All options within the system should have a unique name. No
+ * two options shall have a name that is the same when a case
+ * insensitive comparison between the names with spaces removed
+ * is performed. Only basic alphanumeric characters and spaces
+ * are allowed.
+ *
+ * The VM is required to provide a one way mapping function that
+ * takes the name and creates a VM style name, such as mapping
+ * "No Finalizer" to noFinalizer. The VM may not remove any letters
+ * when performing this mapping but may remove spaces and change
+ * the case of any character.
+ */
+public abstract class Option {
+  // Option types
+  public static final int BOOLEAN_OPTION = 1;
+  public static final int STRING_OPTION = 2;
+  public static final int ENUM_OPTION = 3;
+  public static final int INT_OPTION = 4;
+  public static final int PAGES_OPTION = 6;
+  public static final int MICROSECONDS_OPTION = 7;
+  public static final int FLOAT_OPTION = 8;
+  public static final int ADDRESS_OPTION = 9;
+
+  /**
+   * The possible output formats
+   */
+  public static final int READABLE = 0;
+  public static final int RAW = 1;
+  public static final int XML = 2;
+
+  // Per option values
+  private int type;
+  private String name;
+  private String description;
+  private String key;
+  private Option next;
+
+  protected OptionSet set;
+
+  /**
+   * Construct a new option. This also calls the VM to map the option's
+   * name into a unique option key and links it onto the option list.
+   *
+   * @param set The option set this option belongs to.
+   * @param type The option type as defined in this class.
+   * @param name The unique name of the option.
+   * @param description A short description of the option and purpose.
+   */
+  protected Option(OptionSet set, int type, String name, String description) {
+    this.type = type;
+    this.name = name;
+    this.description = description;
+    this.set = set;
+    this.key = set.register(this, name);
+  }
+
+  /**
+   * Return the VM determined key for an option
+   *
+   * @return The key.
+   */
+  public String getKey() {
+    return this.key;
+  }
+
+  /**
+   * Update the next pointer in the Option chain.
+   */
+  void setNext(Option o) {
+    next = o;
+  }
+
+  /**
+   * Return the next option in the linked list.
+   *
+   * @return The next option or null if this is the last option.
+   */
+  public Option getNext() {
+    return this.next;
+  }
+
+  /**
+   * Return the name for the option.
+   *
+   * @return The option name.
+   */
+  public String getName() {
+    return this.name;
+  }
+
+  /**
+   * Return the option description.
+   *
+   * @return The option description.
+   */
+  public String getDescription() {
+    return this.description;
+  }
+
+  /**
+   * Return the type of the option.
+   *
+   * @return The option type.
+   */
+  public int getType() {
+    return this.type;
+  }
+
+  /**
+   * This is a validation method that can be implemented by leaf option
+   * classes to provide additional validation. This should not be implemented
+   * at other levels within the heirarchy to avoid confusion. The validate
+   * method works against the current value of the option (post-set).
+   */
+  protected void validate() {}
+
+  /**
+   * A fatal error occurred during the setting of an option. This method
+   * calls into the VM and is required to cause the system to stop.
+   *
+   * @param message The error message associated with the failure.
+   */
+  protected void fail(String message) {
+    set.fail(this, message);
+  }
+
+  /**
+   * Fail if a specified condition is met.
+   *
+   * @param condition The condition that indicates failure.
+   * @param message The error message associated with the failure.
+   */
+  protected void failIf(boolean condition, String message) {
+    if (condition) set.fail(this, message);
+  }
+
+  /**
+   * A non-fatal error occurred during the setting of an option. This method
+   * calls into the VM and shall not cause the system to stop.
+   *
+   * @param message The message associated with the warning.
+   */
+  protected void warn(String message) {
+    set.warn(this, message);
+  }
+
+  /**
+   * Warn if a specified condition is met.
+   *
+   * @param condition The condition that indicates warning.
+   * @param message The message associated with the warning.
+   */
+  protected void warnIf(boolean condition, String message) {
+    if (condition) set.warn(this, message);
+  }
+}
+

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/OptionSet.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/OptionSet.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/OptionSet.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/OptionSet.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,203 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.*;
+
+/**
+ * The abstract base class for all option sets.
+ *
+ * Concrete instantiations of this class include logic
+ *
+ * All options within the system should have a unique name. No
+ * two options shall have a name that is the same when a case
+ * insensitive comparison between the names with spaces removed
+ * is performed. Only basic alphanumeric characters and spaces
+ * are allowed.
+ *
+ * The VM is required to provide a one way mapping function that
+ * takes the name and creates a VM style name, such as mapping
+ * "No Finalizer" to noFinalizer. The VM may not remove any letters
+ * when performing this mapping but may remove spaces and change
+ * the case of any character.
+ */
+public abstract class OptionSet {
+  private Option head;
+  private Option tail;
+  private boolean loggingChanges;
+
+  /**
+   * Initialize the option set so that options can be created.
+   */
+  protected OptionSet() {
+    head = null;
+    tail = null;
+    loggingChanges = false;
+  }
+
+  /**
+   * Register the option to this set, computing its key in the process.
+   *
+   * @param o The option to register.
+   */
+  final String register(Option o, String name) {
+    if (tail == null) {
+      tail = head = o;
+    } else {
+      tail.setNext(o);
+      tail = o;
+    }
+    return computeKey(name);
+  }
+
+  /**
+   * Using the VM determined key, look up the corresponding option,
+   * or return null if an option can not be found.
+   *
+   * @param key The (unique) option key.
+   * @return The option, or null.
+   */
+  public final Option getOption(String key) {
+    Option o = getFirst();
+    while (o != null) {
+      if (o.getKey().equals(key)) {
+        return o;
+      }
+      o = o.getNext();
+    }
+    return null;
+  }
+
+  /**
+   * Return the first option. This can be used with the getNext method to
+   * iterate through the options.
+   *
+   * @return The first option, or null if no options exist.
+   */
+  public final Option getFirst() {
+    return head;
+  }
+
+  public void logChange(Option o) {
+    if (loggingChanges) {
+      logString("Option Update: ");
+      log(o);
+    }
+  }
+
+  /**
+   * Log the option value in plain text.
+   *
+   * @param o The option to log.
+   */
+  public void log(Option o) {
+    logString("Option '");
+    logString(o.getKey());
+    logString("' = ");
+    logValue(o, false);
+    logNewLine();
+  }
+
+  /**
+   * Log the option value in Xml.
+   *
+   * @param o The option to log.
+   */
+  public void logXml(Option o) {
+    logString("<option name=\"");
+    logString(o.getKey());
+    logString("\" value=\"");
+    logValue(o, true);
+    logString("\"/>");
+    logNewLine();
+  }
+
+  /**
+   * Log the option values in Xml.
+   */
+  public void logXml() {
+    logString("<options>");
+    logNewLine();
+
+    for(Option o = getFirst(); o != null; o = o.getNext()) {
+      logXml(o);
+    }
+
+    logString("</options>");
+    logNewLine();
+  }
+
+  /**
+   * Format and log an option value.
+   *
+   * @param o The option.
+   * @param forXml Is this part of xml output?
+   */
+  protected abstract void logValue(Option o, boolean forXml);
+
+  /**
+   * Log a string.
+   */
+  protected abstract void logString(String s);
+
+  /**
+   * Print a new line.
+   */
+  protected abstract void logNewLine();
+
+  /**
+   * Determine the VM specific key for a given option name. Option names are
+   * space delimited with capitalised words (e.g. "GC Verbosity Level").
+   *
+   * @param name The option name.
+   * @return The VM specific key.
+   */
+  protected abstract String computeKey(String name);
+
+  /**
+   * A non-fatal error occurred during the setting of an option. This method
+   * calls into the VM and shall not cause the system to stop.
+   *
+   * @param o The responsible option.
+   * @param message The message associated with the warning.
+   */
+  protected abstract void warn(Option o, String message);
+
+  /**
+   * A fatal error occurred during the setting of an option. This method
+   * calls into the VM and is required to cause the system to stop.
+   *
+   * @param o The responsible option.
+   * @param message The error message associated with the failure.
+   */
+  protected abstract void fail(Option o, String message);
+
+  /**
+   * Convert bytes into pages, rounding up if necessary.
+   *
+   * @param bytes The number of bytes.
+   * @return The corresponding number of pages.
+   */
+  @Uninterruptible
+  protected abstract int bytesToPages(Extent bytes);
+
+  /**
+   * Convert from pages into bytes.
+   * @param pages the number of pages.
+   * @return The corresponding number of bytes.
+   */
+  @Uninterruptible
+  protected abstract Extent pagesToBytes(int pages);
+}
+

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/PagesOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/PagesOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/PagesOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/PagesOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,114 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.Extent;
+
+/**
+ * A memory option that stores values as a whole number of pages.
+ */
+public class PagesOption extends Option {
+  // values
+  protected int defaultValue;
+  protected int value;
+
+  /**
+   * Create a new pages option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultPages The default value of the option.
+   */
+  protected PagesOption(OptionSet set, String name, String desc, int defaultPages) {
+    super(set, PAGES_OPTION, name, desc);
+    this.value = this.defaultValue = defaultPages;
+  }
+
+  /**
+   * Read the current value of the option in pages.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public int getPages() {
+    return this.value;
+  }
+
+  /**
+   * Read the current value of the option in bytes.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public Extent getBytes() {
+    return set.pagesToBytes(this.value);
+  }
+
+  /**
+   * Read the default value of the option in bytes.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public Extent getDefaultBytes() {
+    return set.pagesToBytes(this.defaultValue);
+  }
+
+  /**
+   * Read the default value of the option in pages.
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public int getDefaultPages() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if logChanges is set.
+   * A warning is raised if the value is not a whole multiple of pages, and
+   * then the validate method is called to allow subclasses to perform any
+   * additional validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setBytes(Extent value) {
+    int pages = set.bytesToPages(value);
+    warnIf(value.NE(set.pagesToBytes(pages)), "Value rounded up to a whole number of pages");
+    setPages(pages);
+  }
+
+  /**
+   * Update the value of the option, echoing the change if logChanges is set.
+   * The validate method is called to allow subclasses to perform any additional
+   * validation.
+   *
+   * @param pages The new value for the option.
+   */
+  public void setPages(int pages) {
+    this.value = pages;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultPages(int value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/java/src/org/vmutil/options/StringOption.java
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/java/src/org/vmutil/options/StringOption.java?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/java/src/org/vmutil/options/StringOption.java (added)
+++ vmkit/trunk/mmtk/java/src/org/vmutil/options/StringOption.java Thu Jul 16 06:26:34 2009
@@ -0,0 +1,79 @@
+/*
+ *  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.vmutil.options;
+
+import org.vmmagic.pragma.Uninterruptible;
+
+/**
+ * An option that has a simple string value.
+ */
+public class StringOption extends Option {
+  // values
+  protected String defaultValue;
+  protected String value;
+
+  /**
+   * Create a new string option.
+   *
+   * @param set The option set this option belongs to.
+   * @param name The space separated name for the option.
+   * @param desc The purpose of the option
+   * @param defaultValue The default value of the option.
+   */
+  protected StringOption(OptionSet set, String name, String desc, String defaultValue) {
+    super(set, STRING_OPTION, name, desc);
+    this.value = this.defaultValue = defaultValue;
+  }
+
+  /**
+   * Read the current value of the option.
+   *
+   * @return The option value.
+   */
+  @Uninterruptible
+  public String getValue() {
+    return this.value;
+  }
+
+  /**
+   * Read the default value of the option
+   *
+   * @return The default value.
+   */
+  @Uninterruptible
+  public String getDefaultValue() {
+    return this.defaultValue;
+  }
+
+  /**
+   * Update the value of the option, echoing the change if the echoOptions
+   * option is set. This method also calls the validate method to allow
+   * subclasses to perform any required validation.
+   *
+   * @param value The new value for the option.
+   */
+  public void setValue(String value) {
+    this.value = value;
+    validate();
+    set.logChange(this);
+  }
+
+  /**
+   * Modify the default value of the option.
+   *
+   * @param value The new default value for the option.
+   */
+  public void setDefaultValue(String value) {
+    this.value = this.defaultValue = value;
+  }
+}

Added: vmkit/trunk/mmtk/magic/LowerJavaRT.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/magic/LowerJavaRT.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/magic/LowerJavaRT.cpp (added)
+++ vmkit/trunk/mmtk/magic/LowerJavaRT.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,73 @@
+//===-- LowerJavaRT.cpp - Remove references to RT classes and functions  --===//
+//
+//                            The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+
+#include "jnjvm/JnjvmModule.h"
+
+#include <iostream>
+
+using namespace llvm;
+
+namespace {
+
+  class VISIBILITY_HIDDEN LowerJavaRT : public ModulePass {
+  public:
+    static char ID;
+    LowerJavaRT() : ModulePass((intptr_t)&ID) { }
+
+    virtual bool runOnModule(Module &M);
+  private:
+  };
+  char LowerJavaRT::ID = 0;
+  static RegisterPass<LowerJavaRT> X("LowerJavaRT",
+                                     "Remove references to RT");
+
+bool LowerJavaRT::runOnModule(Module& M) {
+  bool Changed = true;
+
+  for (Module::iterator I = M.begin(), E = M.end(); I != E;) {
+    GlobalValue& GV = *I;
+    ++I;
+    if (!strncmp(GV.getName().c_str(), "JnJVM_java", 10) ||
+        !strncmp(GV.getName().c_str(), "java", 4)) {
+      GV.replaceAllUsesWith(M.getContext().getNullValue(GV.getType()));
+      GV.eraseFromParent();
+    }
+  }
+
+  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
+       I != E;) {
+    GlobalValue& GV = *I;
+    ++I;
+    if (!strncmp(GV.getName().c_str(), "JnJVM_java", 10) ||
+        !strncmp(GV.getName().c_str(), "java", 4)) {
+      GV.replaceAllUsesWith(M.getContext().getNullValue(GV.getType()));
+      GV.eraseFromParent();
+    }
+  }
+
+
+  return Changed;
+}
+
+
+ModulePass* createLowerJavaRT() {
+  return new LowerJavaRT();
+}
+
+}

Added: vmkit/trunk/mmtk/magic/LowerMagic.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/magic/LowerMagic.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/magic/LowerMagic.cpp (added)
+++ vmkit/trunk/mmtk/magic/LowerMagic.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,1132 @@
+//===----- LowerConstantCalls.cpp - Changes arrayLength calls  --------------===//
+//
+//                               JnJVM
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+
+#include <iostream>
+
+using namespace llvm;
+
+namespace vmmagic {
+
+  class VISIBILITY_HIDDEN LowerMagic : public FunctionPass {
+  public:
+    static char ID;
+    LowerMagic() : FunctionPass((intptr_t)&ID) { }
+
+    virtual bool runOnFunction(Function &F);
+  private:
+  };
+  char LowerMagic::ID = 0;
+  static RegisterPass<LowerMagic> X("LowerMagic",
+                                    "Lower magic calls");
+
+static const char* AddressClass = "JnJVM_org_vmmagic_unboxed_Address_";
+static const char* AddressZeroMethod = 0;
+static const char* AddressIsZeroMethod;
+static const char* AddressMaxMethod;
+static const char* AddressIsMaxMethod;
+static const char* AddressFromIntSignExtendMethod;
+static const char* AddressFromIntZeroExtendMethod;
+static const char* AddressFromLongMethod;
+static const char* AddressToObjectReferenceMethod;
+static const char* AddressToIntMethod;
+static const char* AddressToLongMethod;
+static const char* AddressToWordMethod;
+static const char* AddressPlusIntMethod;
+static const char* AddressPlusOffsetMethod;
+static const char* AddressPlusExtentMethod;
+static const char* AddressMinusIntMethod;
+static const char* AddressMinusOffsetMethod;
+static const char* AddressMinusExtentMethod;
+static const char* AddressDiffMethod;
+static const char* AddressLTMethod;
+static const char* AddressLEMethod;
+static const char* AddressGTMethod;
+static const char* AddressGEMethod;
+static const char* AddressEQMethod;
+static const char* AddressNEMethod;
+static const char* AddressPrefetchMethod;
+static const char* AddressLoadObjectReferenceMethod;
+static const char* AddressLoadObjectReferenceAtOffsetMethod;
+static const char* AddressLoadByteMethod;
+static const char* AddressLoadByteAtOffsetMethod;
+static const char* AddressLoadCharMethod;
+static const char* AddressLoadCharAtOffsetMethod;
+static const char* AddressLoadShortMethod;
+static const char* AddressLoadShortAtOffsetMethod;
+static const char* AddressLoadFloatMethod;
+static const char* AddressLoadFloatAtOffsetMethod;
+static const char* AddressLoadIntMethod;
+static const char* AddressLoadIntAtOffsetMethod;
+static const char* AddressLoadLongMethod;
+static const char* AddressLoadLongAtOffsetMethod;
+static const char* AddressLoadDoubleMethod;
+static const char* AddressLoadDoubleAtOffsetMethod;
+static const char* AddressLoadAddressMethod;
+static const char* AddressLoadAddressAtOffsetMethod;
+static const char* AddressLoadWordMethod;
+static const char* AddressLoadWordAtOffsetMethod;
+static const char* AddressStoreObjectReferenceMethod;
+static const char* AddressStoreObjectReferenceAtOffsetMethod;
+static const char* AddressStoreAddressMethod;
+static const char* AddressStoreAddressAtOffsetMethod;
+static const char* AddressStoreFloatMethod;
+static const char* AddressStoreFloatAtOffsetMethod;
+static const char* AddressStoreWordMethod;
+static const char* AddressStoreWordAtOffsetMethod;
+static const char* AddressStoreByteMethod;
+static const char* AddressStoreByteAtOffsetMethod;
+static const char* AddressStoreIntMethod;
+static const char* AddressStoreIntAtOffsetMethod;
+static const char* AddressStoreDoubleMethod;
+static const char* AddressStoreDoubleAtOffsetMethod;
+static const char* AddressStoreLongMethod;
+static const char* AddressStoreLongAtOffsetMethod;
+static const char* AddressStoreCharMethod;
+static const char* AddressStoreCharAtOffsetMethod;
+static const char* AddressStoreShortMethod;
+static const char* AddressStoreShortAtOffsetMethod;
+static const char* AddressPrepareWordMethod;
+static const char* AddressPrepareWordAtOffsetMethod;
+static const char* AddressPrepareObjectReferenceMethod;
+static const char* AddressPrepareObjectReferenceAtOffsetMethod;
+static const char* AddressPrepareAddressMethod;
+static const char* AddressPrepareAddressAtOffsetMethod;
+static const char* AddressPrepareIntMethod;
+static const char* AddressPrepareIntAtOffsetMethod;
+static const char* AddressAttemptIntMethod;
+static const char* AddressAttemptIntAtOffsetMethod;
+static const char* AddressAttemptWordMethod;
+static const char* AddressAttemptWordAtOffsetMethod;
+static const char* AddressAttemptObjectReferenceMethod;
+static const char* AddressAttemptObjectReferenceAtOffsetMethod;
+static const char* AddressAttemptAddressMethod;
+static const char* AddressAttemptAddressAtOffsetMethod;
+
+static const char* ExtentClass = "JnJVM_org_vmmagic_unboxed_Extent_";
+static const char* ExtentToWordMethod = 0;
+static const char* ExtentFromIntSignExtendMethod;
+static const char* ExtentFromIntZeroExtendMethod;
+static const char* ExtentZeroMethod;
+static const char* ExtentOneMethod;
+static const char* ExtentMaxMethod;
+static const char* ExtentToIntMethod;
+static const char* ExtentToLongMethod;
+static const char* ExtentPlusIntMethod;
+static const char* ExtentPlusExtentMethod;
+static const char* ExtentMinusIntMethod;
+static const char* ExtentMinusExtentMethod;
+static const char* ExtentLTMethod;
+static const char* ExtentLEMethod;
+static const char* ExtentGTMethod;
+static const char* ExtentGEMethod;
+static const char* ExtentEQMethod;
+static const char* ExtentNEMethod;
+
+static const char* ObjectReferenceClass = 
+  "JnJVM_org_vmmagic_unboxed_ObjectReference_";
+static const char* ObjectReferenceFromObjectMethod = 0;
+static const char* ObjectReferenceNullReferenceMethod;
+static const char* ObjectReferenceToObjectMethod;
+static const char* ObjectReferenceToAddressMethod;
+static const char* ObjectReferenceIsNullMethod;
+
+static const char* OffsetClass = "JnJVM_org_vmmagic_unboxed_Offset_";
+static const char* OffsetFromIntSignExtendMethod = 0;
+static const char* OffsetFromIntZeroExtendMethod;
+static const char* OffsetZeroMethod;
+static const char* OffsetMaxMethod;
+static const char* OffsetToIntMethod;
+static const char* OffsetToLongMethod;
+static const char* OffsetToWordMethod;
+static const char* OffsetPlusIntMethod;
+static const char* OffsetMinusIntMethod;
+static const char* OffsetMinusOffsetMethod;
+static const char* OffsetEQMethod;
+static const char* OffsetNEMethod;
+static const char* OffsetSLTMethod;
+static const char* OffsetSLEMethod;
+static const char* OffsetSGTMethod;
+static const char* OffsetSGEMethod;
+static const char* OffsetIsZeroMethod;
+static const char* OffsetIsMaxMethod;
+
+static const char* WordClass = "JnJVM_org_vmmagic_unboxed_Word_";
+static const char* WordFromIntSignExtendMethod = 0;
+static const char* WordFromIntZeroExtendMethod;
+static const char* WordFromLongMethod;
+static const char* WordZeroMethod;
+static const char* WordOneMethod;
+static const char* WordMaxMethod;
+static const char* WordToIntMethod;
+static const char* WordToLongMethod;
+static const char* WordToAddressMethod;
+static const char* WordToOffsetMethod;
+static const char* WordToExtentMethod;
+static const char* WordPlusWordMethod;
+static const char* WordPlusOffsetMethod;
+static const char* WordPlusExtentMethod;
+static const char* WordMinusWordMethod;
+static const char* WordMinusOffsetMethod;
+static const char* WordMinusExtentMethod;
+static const char* WordIsZeroMethod;
+static const char* WordIsMaxMethod;
+static const char* WordLTMethod;
+static const char* WordLEMethod;
+static const char* WordGTMethod;
+static const char* WordGEMethod;
+static const char* WordEQMethod;
+static const char* WordNEMethod;
+static const char* WordAndMethod;
+static const char* WordOrMethod;
+static const char* WordNotMethod;
+static const char* WordXorMethod;
+static const char* WordLshMethod;
+static const char* WordRshlMethod;
+static const char* WordRshaMethod;
+
+static Function* CASPtr;
+static Function* CASInt;
+
+static void initialiseFunctions(Module* M) {
+  if (!AddressZeroMethod) {
+    AddressZeroMethod = "JnJVM_org_vmmagic_unboxed_Address_zero__";
+    AddressMaxMethod = "JnJVM_org_vmmagic_unboxed_Address_max__";
+    AddressStoreObjectReferenceMethod = "JnJVM_org_vmmagic_unboxed_Address_store__Lorg_vmmagic_unboxed_ObjectReference_2";
+    AddressLoadObjectReferenceMethod = "JnJVM_org_vmmagic_unboxed_Address_loadObjectReference__";
+    AddressLoadAddressMethod = "JnJVM_org_vmmagic_unboxed_Address_loadAddress__";
+    AddressLoadWordMethod = "JnJVM_org_vmmagic_unboxed_Address_loadWord__";
+    AddressDiffMethod = "JnJVM_org_vmmagic_unboxed_Address_diff__Lorg_vmmagic_unboxed_Address_2";
+    AddressPlusOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_plus__Lorg_vmmagic_unboxed_Offset_2";
+    AddressStoreAddressMethod = "JnJVM_org_vmmagic_unboxed_Address_store__Lorg_vmmagic_unboxed_Address_2";
+    AddressPlusIntMethod = "JnJVM_org_vmmagic_unboxed_Address_plus__I";
+    AddressLTMethod = "JnJVM_org_vmmagic_unboxed_Address_LT__Lorg_vmmagic_unboxed_Address_2";
+    AddressGEMethod = "JnJVM_org_vmmagic_unboxed_Address_GE__Lorg_vmmagic_unboxed_Address_2";
+    AddressStoreWordMethod = "JnJVM_org_vmmagic_unboxed_Address_store__Lorg_vmmagic_unboxed_Word_2";
+    AddressToObjectReferenceMethod = "JnJVM_org_vmmagic_unboxed_Address_toObjectReference__";
+    AddressToWordMethod = "JnJVM_org_vmmagic_unboxed_Address_toWord__";
+    AddressPrepareWordMethod = "JnJVM_org_vmmagic_unboxed_Address_prepareWord__";
+    AddressAttemptWordAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_attempt__Lorg_vmmagic_unboxed_Word_2Lorg_vmmagic_unboxed_Word_2Lorg_vmmagic_unboxed_Offset_2";
+    AddressPrepareWordAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_prepareWord__Lorg_vmmagic_unboxed_Offset_2";
+    AddressLoadWordAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_loadWord__Lorg_vmmagic_unboxed_Offset_2";
+    AddressStoreWordAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_store__Lorg_vmmagic_unboxed_Word_2Lorg_vmmagic_unboxed_Offset_2";
+    AddressPlusExtentMethod = "JnJVM_org_vmmagic_unboxed_Address_plus__Lorg_vmmagic_unboxed_Extent_2";
+    AddressIsZeroMethod = "JnJVM_org_vmmagic_unboxed_Address_isZero__";
+    AddressStoreAddressAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_store__Lorg_vmmagic_unboxed_Address_2Lorg_vmmagic_unboxed_Offset_2";
+    AddressGTMethod = "JnJVM_org_vmmagic_unboxed_Address_GT__Lorg_vmmagic_unboxed_Address_2";
+    AddressLoadAddressAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_loadAddress__Lorg_vmmagic_unboxed_Offset_2";
+    AddressEQMethod = "JnJVM_org_vmmagic_unboxed_Address_EQ__Lorg_vmmagic_unboxed_Address_2";
+    AddressLoadObjectReferenceAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_loadObjectReference__Lorg_vmmagic_unboxed_Offset_2";
+    AddressLEMethod = "JnJVM_org_vmmagic_unboxed_Address_LE__Lorg_vmmagic_unboxed_Address_2";
+    AddressAttemptWordMethod = "JnJVM_org_vmmagic_unboxed_Address_attempt__Lorg_vmmagic_unboxed_Word_2Lorg_vmmagic_unboxed_Word_2";
+    AddressNEMethod = "JnJVM_org_vmmagic_unboxed_Address_NE__Lorg_vmmagic_unboxed_Address_2";
+    AddressToLongMethod = "JnJVM_org_vmmagic_unboxed_Address_toLong__";
+    AddressMinusExtentMethod = "JnJVM_org_vmmagic_unboxed_Address_minus__Lorg_vmmagic_unboxed_Extent_2";
+    AddressLoadShortAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_loadShort__Lorg_vmmagic_unboxed_Offset_2";
+    AddressStoreShortAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_store__SLorg_vmmagic_unboxed_Offset_2";
+    AddressLoadShortMethod = "JnJVM_org_vmmagic_unboxed_Address_loadShort__";
+    AddressStoreShortMethod = "JnJVM_org_vmmagic_unboxed_Address_store__S";
+    AddressLoadByteMethod = "JnJVM_org_vmmagic_unboxed_Address_loadByte__";
+    AddressLoadIntMethod = "JnJVM_org_vmmagic_unboxed_Address_loadInt__";
+    AddressStoreIntMethod = "JnJVM_org_vmmagic_unboxed_Address_store__I";
+    AddressStoreByteMethod = "JnJVM_org_vmmagic_unboxed_Address_store__B";
+    AddressLoadByteAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_loadByte__Lorg_vmmagic_unboxed_Offset_2";
+    AddressMinusIntMethod = "JnJVM_org_vmmagic_unboxed_Address_minus__I";
+    AddressLoadIntAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_loadInt__Lorg_vmmagic_unboxed_Offset_2";
+    AddressStoreByteAtOffsetMethod = "JnJVM_org_vmmagic_unboxed_Address_store__BLorg_vmmagic_unboxed_Offset_2";
+    AddressFromIntZeroExtendMethod = "JnJVM_org_vmmagic_unboxed_Address_fromIntZeroExtend__I";
+    AddressToIntMethod = "JnJVM_org_vmmagic_unboxed_Address_toInt__";
+    
+    ExtentToWordMethod = "JnJVM_org_vmmagic_unboxed_Extent_toWord__";
+    ExtentMinusExtentMethod = "JnJVM_org_vmmagic_unboxed_Extent_minus__Lorg_vmmagic_unboxed_Extent_2";
+    ExtentPlusExtentMethod = "JnJVM_org_vmmagic_unboxed_Extent_plus__Lorg_vmmagic_unboxed_Extent_2";
+    ExtentPlusIntMethod = "JnJVM_org_vmmagic_unboxed_Extent_plus__I";
+    ExtentMinusIntMethod = "JnJVM_org_vmmagic_unboxed_Extent_minus__I";
+    ExtentFromIntZeroExtendMethod = "JnJVM_org_vmmagic_unboxed_Extent_fromIntZeroExtend__I";
+    ExtentFromIntSignExtendMethod = "JnJVM_org_vmmagic_unboxed_Extent_fromIntSignExtend__I";
+    ExtentOneMethod = "JnJVM_org_vmmagic_unboxed_Extent_one__";
+    ExtentNEMethod = "JnJVM_org_vmmagic_unboxed_Extent_NE__Lorg_vmmagic_unboxed_Extent_2";
+    ExtentZeroMethod = "JnJVM_org_vmmagic_unboxed_Extent_zero__";
+    ExtentToLongMethod = "JnJVM_org_vmmagic_unboxed_Extent_toLong__";
+    ExtentToIntMethod = "JnJVM_org_vmmagic_unboxed_Extent_toInt__";
+    ExtentEQMethod = "JnJVM_org_vmmagic_unboxed_Extent_EQ__Lorg_vmmagic_unboxed_Extent_2";
+    ExtentGTMethod = "JnJVM_org_vmmagic_unboxed_Extent_GT__Lorg_vmmagic_unboxed_Extent_2";
+    ExtentLTMethod = "JnJVM_org_vmmagic_unboxed_Extent_LT__Lorg_vmmagic_unboxed_Extent_2";
+    ExtentMaxMethod = "JnJVM_org_vmmagic_unboxed_Extent_max__";
+
+    ObjectReferenceFromObjectMethod = "JnJVM_org_vmmagic_unboxed_ObjectReference_fromObject__Ljava_lang_Object_2";
+    ObjectReferenceToObjectMethod = "JnJVM_org_vmmagic_unboxed_ObjectReference_toObject__";
+    ObjectReferenceNullReferenceMethod = "JnJVM_org_vmmagic_unboxed_ObjectReference_nullReference__";
+    ObjectReferenceToAddressMethod = "JnJVM_org_vmmagic_unboxed_ObjectReference_toAddress__";
+    ObjectReferenceIsNullMethod = "JnJVM_org_vmmagic_unboxed_ObjectReference_isNull__";
+
+    WordOrMethod = "JnJVM_org_vmmagic_unboxed_Word_or__Lorg_vmmagic_unboxed_Word_2";
+    WordRshlMethod = "JnJVM_org_vmmagic_unboxed_Word_rshl__I";
+    WordToIntMethod = "JnJVM_org_vmmagic_unboxed_Word_toInt__";
+    WordNotMethod = "JnJVM_org_vmmagic_unboxed_Word_not__";
+    WordZeroMethod = "JnJVM_org_vmmagic_unboxed_Word_zero__";
+    WordOneMethod = "JnJVM_org_vmmagic_unboxed_Word_one__";
+    WordAndMethod = "JnJVM_org_vmmagic_unboxed_Word_and__Lorg_vmmagic_unboxed_Word_2";
+    WordToAddressMethod = "JnJVM_org_vmmagic_unboxed_Word_toAddress__";
+    WordLshMethod = "JnJVM_org_vmmagic_unboxed_Word_lsh__I";
+    WordMinusWordMethod = "JnJVM_org_vmmagic_unboxed_Word_minus__Lorg_vmmagic_unboxed_Word_2";
+    WordLTMethod = "JnJVM_org_vmmagic_unboxed_Word_LT__Lorg_vmmagic_unboxed_Word_2";
+    WordPlusWordMethod = "JnJVM_org_vmmagic_unboxed_Word_plus__Lorg_vmmagic_unboxed_Word_2";
+    WordLEMethod = "JnJVM_org_vmmagic_unboxed_Word_LE__Lorg_vmmagic_unboxed_Word_2";
+    WordGEMethod = "JnJVM_org_vmmagic_unboxed_Word_GE__Lorg_vmmagic_unboxed_Word_2";
+    WordEQMethod = "JnJVM_org_vmmagic_unboxed_Word_EQ__Lorg_vmmagic_unboxed_Word_2";
+    WordNEMethod = "JnJVM_org_vmmagic_unboxed_Word_NE__Lorg_vmmagic_unboxed_Word_2";
+    WordFromIntSignExtendMethod = "JnJVM_org_vmmagic_unboxed_Word_fromIntSignExtend__I";
+    WordIsZeroMethod = "JnJVM_org_vmmagic_unboxed_Word_isZero__";
+    WordXorMethod = "JnJVM_org_vmmagic_unboxed_Word_xor__Lorg_vmmagic_unboxed_Word_2";
+    WordFromIntZeroExtendMethod = "JnJVM_org_vmmagic_unboxed_Word_fromIntZeroExtend__I";
+    WordToExtentMethod = "JnJVM_org_vmmagic_unboxed_Word_toExtent__";
+    WordMinusExtentMethod = "JnJVM_org_vmmagic_unboxed_Word_minus__Lorg_vmmagic_unboxed_Extent_2";
+    WordToLongMethod = "JnJVM_org_vmmagic_unboxed_Word_toLong__";
+    WordMaxMethod = "JnJVM_org_vmmagic_unboxed_Word_max__";
+    WordToOffsetMethod = "JnJVM_org_vmmagic_unboxed_Word_toOffset__";
+    WordGTMethod = "JnJVM_org_vmmagic_unboxed_Word_GT__Lorg_vmmagic_unboxed_Word_2";
+
+
+    OffsetSLTMethod = "JnJVM_org_vmmagic_unboxed_Offset_sLT__Lorg_vmmagic_unboxed_Offset_2";
+    OffsetFromIntSignExtendMethod = "JnJVM_org_vmmagic_unboxed_Offset_fromIntSignExtend__I";
+    OffsetSGTMethod = "JnJVM_org_vmmagic_unboxed_Offset_sGT__Lorg_vmmagic_unboxed_Offset_2";
+    OffsetPlusIntMethod = "JnJVM_org_vmmagic_unboxed_Offset_plus__I";
+    OffsetZeroMethod = "JnJVM_org_vmmagic_unboxed_Offset_zero__";
+    OffsetToWordMethod = "JnJVM_org_vmmagic_unboxed_Offset_toWord__";
+    OffsetFromIntZeroExtendMethod = "JnJVM_org_vmmagic_unboxed_Offset_fromIntZeroExtend__I";
+    OffsetSGEMethod = "JnJVM_org_vmmagic_unboxed_Offset_sGE__Lorg_vmmagic_unboxed_Offset_2";
+    OffsetToIntMethod = "JnJVM_org_vmmagic_unboxed_Offset_toInt__";
+    OffsetToLongMethod = "JnJVM_org_vmmagic_unboxed_Offset_toLong__";
+    OffsetIsZeroMethod = "JnJVM_org_vmmagic_unboxed_Offset_isZero__";
+    OffsetMinusIntMethod = "JnJVM_org_vmmagic_unboxed_Offset_minus__I";
+    OffsetSLEMethod = "JnJVM_org_vmmagic_unboxed_Offset_sLE__Lorg_vmmagic_unboxed_Offset_2";
+    OffsetEQMethod = "JnJVM_org_vmmagic_unboxed_Offset_EQ__Lorg_vmmagic_unboxed_Offset_2";
+    OffsetMinusOffsetMethod = "JnJVM_org_vmmagic_unboxed_Offset_minus__Lorg_vmmagic_unboxed_Offset_2";
+  }
+}
+
+#include <iostream>
+
+static bool removePotentialNullCheck(BasicBlock* Cur, Value* Obj) {
+  BasicBlock* BB = Cur->getUniquePredecessor();
+  LLVMContext* Context = Cur->getParent()->getContext();
+  if (BB) {
+    Instruction* T = BB->getTerminator();
+    if (dyn_cast<BranchInst>(T) && T != BB->begin()) {
+      BasicBlock::iterator BIE = BB->end();
+      --BIE; // Terminator
+      --BIE; // Null test
+      if (ICmpInst* IE = dyn_cast<ICmpInst>(BIE)) {
+        if (IE->getPredicate() == ICmpInst::ICMP_EQ &&
+            IE->getOperand(0) == Obj &&
+            IE->getOperand(1) == Context->getNullValue(Obj->getType())) {
+          BIE->replaceAllUsesWith(ConstantInt::getFalse());
+          BIE->eraseFromParent();
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+bool LowerMagic::runOnFunction(Function& F) {
+  Module* globalModule = F.getParent();
+  LLVMContext& Context = globalModule->getContext();
+  bool Changed = false;
+  const llvm::Type* pointerSizeType = 
+    globalModule->getPointerSize() == llvm::Module::Pointer32 ?
+      Type::Int32Ty : Type::Int64Ty;
+  
+  initialiseFunctions(globalModule);
+  if (!CASPtr || CASPtr->getParent() != globalModule) {
+    if (pointerSizeType == Type::Int32Ty) {
+      CASPtr = globalModule->getFunction("llvm.atomic.cmp.swap.i32.p0i32");
+    } else {
+      CASPtr = globalModule->getFunction("llvm.atomic.cmp.swap.i64.p0i64");
+    }
+    CASInt = globalModule->getFunction("llvm.atomic.cmp.swap.i32.p0i32");
+  }
+
+  for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; BI++) { 
+    BasicBlock *Cur = BI; 
+    for (BasicBlock::iterator II = Cur->begin(), IE = Cur->end(); II != IE;) {
+      Instruction *I = II;
+      II++;
+      CallSite Call = CallSite::get(I);
+      Instruction* CI = Call.getInstruction();
+      if (CI) {
+        Value* V = Call.getCalledValue();
+        if (Function* FCur = dyn_cast<Function>(V)) {
+          const char* name = FCur->getNameStart();
+          unsigned len = FCur->getNameLen();
+          if (len > strlen(AddressClass) && 
+              !memcmp(AddressClass, name, strlen(AddressClass))) {
+            
+            Changed = true;
+            // Remove the null check
+            if (Call.arg_begin() != Call.arg_end()) {
+              removePotentialNullCheck(Cur, Call.getArgument(0));
+            }
+
+            if (!strcmp(FCur->getNameStart(), AddressZeroMethod)) {
+              Constant* N = Context.getNullValue(FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressMaxMethod)) {
+              ConstantInt* M = Context.getConstantInt(Type::Int64Ty, (uint64_t)-1);
+              Constant* N = ConstantExpr::getIntToPtr(M, FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressStoreObjectReferenceMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreAddressMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreShortMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreByteMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreIntMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreWordMethod)) {
+              Value* Addr = Call.getArgument(0);
+              Value* Obj = Call.getArgument(1);
+              const llvm::Type* Ty = PointerType::getUnqual(Obj->getType());
+              Addr = new BitCastInst(Addr, Ty, "", CI);
+              new StoreInst(Obj, Addr, CI);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressLoadObjectReferenceMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadAddressMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadWordMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadShortMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadByteMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadIntMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressPrepareWordMethod)) {
+              Value* Addr = Call.getArgument(0);
+              const Type* Ty = PointerType::getUnqual(FCur->getReturnType());
+              Addr = new BitCastInst(Addr, Ty, "", CI);
+              Value* LD = new LoadInst(Addr, "", CI);
+              CI->replaceAllUsesWith(LD);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressDiffMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressMinusExtentMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressPlusOffsetMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressPlusIntMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressMinusIntMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressLTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_ULT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressGTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_UGT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressEQMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressNEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_NE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressLEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_ULE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressGEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_UGE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressToObjectReferenceMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressToWordMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new BitCastInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressAttemptWordAtOffsetMethod)) {
+              Value* Ptr = Call.getArgument(0);
+              Value* Old = Call.getArgument(1);
+              Value* Val = Call.getArgument(2);
+              Value* Offset = Call.getArgument(3);
+
+              Ptr = new PtrToIntInst(Ptr, pointerSizeType, "", CI);
+              Offset = new PtrToIntInst(Offset, pointerSizeType, "", CI);
+              Ptr = BinaryOperator::CreateAdd(Ptr, Offset, "", CI);
+              const Type* Ty = PointerType::getUnqual(pointerSizeType);
+              Ptr = new IntToPtrInst(Ptr, Ty, "", CI);
+              Old = new PtrToIntInst(Old, pointerSizeType, "", CI);
+              Val = new PtrToIntInst(Val, pointerSizeType, "", CI);
+              
+              Value* Args[3] = { Ptr, Old, Val };
+              Value* res = CallInst::Create(CASPtr, Args, Args + 3, "", CI);
+              res = new ICmpInst(CI, ICmpInst::ICMP_EQ, res, Old, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressAttemptWordMethod)) {
+              Value* Ptr = Call.getArgument(0);
+              Value* Old = Call.getArgument(1);
+              Value* Val = Call.getArgument(2);
+
+              const Type* Ty = PointerType::getUnqual(pointerSizeType);
+              Ptr = new BitCastInst(Ptr, Ty, "", CI);
+              Old = new PtrToIntInst(Old, pointerSizeType, "", CI);
+              Val = new PtrToIntInst(Val, pointerSizeType, "", CI);
+              
+              Value* Args[3] = { Ptr, Old, Val };
+              Value* res = CallInst::Create(CASPtr, Args, Args + 3, "", CI);
+              res = new ICmpInst(CI, ICmpInst::ICMP_EQ, res, Old, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressPrepareWordAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadWordAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadAddressAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadObjectReferenceAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadByteAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadIntAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressLoadShortAtOffsetMethod)) {
+              Value* Ptr = Call.getArgument(0);
+              Value* Offset = Call.getArgument(1);
+
+              Ptr = new PtrToIntInst(Ptr, pointerSizeType, "", CI);
+              Offset = new PtrToIntInst(Offset, pointerSizeType, "", CI);
+              Ptr = BinaryOperator::CreateAdd(Ptr, Offset, "", CI);
+              const Type* Ty = PointerType::getUnqual(FCur->getReturnType());
+              Ptr = new IntToPtrInst(Ptr, Ty, "", CI);
+              Value* res = new LoadInst(Ptr, "", CI);
+
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressStoreWordAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreAddressAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreByteAtOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), AddressStoreShortAtOffsetMethod)) {
+              Value* Ptr = Call.getArgument(0);
+              Value* Val = Call.getArgument(1);
+              Value* Offset = Call.getArgument(2);
+
+              Ptr = new PtrToIntInst(Ptr, pointerSizeType, "", CI);
+              Offset = new PtrToIntInst(Offset, pointerSizeType, "", CI);
+              Ptr = BinaryOperator::CreateAdd(Ptr, Offset, "", CI);
+              const Type* Ty = PointerType::getUnqual(Val->getType());
+              Ptr = new IntToPtrInst(Ptr, Ty, "", CI);
+              new StoreInst(Val, Ptr, CI);
+
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressPlusExtentMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressIsZeroMethod)) {
+              Value* Val = Call.getArgument(0);
+              Constant* N = Context.getNullValue(Val->getType());
+              Value* Res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val, N, "");
+              Res = new ZExtInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressToLongMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int64Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressFromIntZeroExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new ZExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), AddressToIntMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int32Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else {
+              fprintf(stderr, "Implement me %s\n", name);
+              abort();
+            }
+
+          } else if (len > strlen(ExtentClass) && 
+              !memcmp(ExtentClass, name, strlen(ExtentClass))) {
+            
+            Changed = true;
+            // Remove the null check
+            if (Call.arg_begin() != Call.arg_end()) {
+              removePotentialNullCheck(Cur, Call.getArgument(0));
+            }
+
+            if (!strcmp(FCur->getNameStart(), ExtentToWordMethod)) {
+              CI->replaceAllUsesWith(Call.getArgument(0));
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentMinusExtentMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentPlusExtentMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentPlusIntMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentMinusIntMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentFromIntZeroExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new ZExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentFromIntSignExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new SExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentOneMethod)) {
+              Constant* N = Context.getConstantInt(pointerSizeType, 1);
+              N = ConstantExpr::getIntToPtr(N, FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentNEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_NE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentEQMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentGTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_UGT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentLTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_ULT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentZeroMethod)) {
+              Constant* N = Context.getNullValue(FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentToLongMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int64Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentToIntMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int32Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ExtentMaxMethod)) {
+              ConstantInt* M = Context.getConstantInt(Type::Int64Ty, (uint64_t)-1);
+              Constant* N = ConstantExpr::getIntToPtr(M, FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else {
+              fprintf(stderr, "Implement me %s\n", name);
+              abort();
+            }
+          } else if (len > strlen(OffsetClass) && 
+              !memcmp(OffsetClass, name, strlen(OffsetClass))) {
+            
+            Changed = true;
+            // Remove the null check
+            if (Call.arg_begin() != Call.arg_end()) {
+              removePotentialNullCheck(Cur, Call.getArgument(0));
+            }
+            
+            if (!strcmp(FCur->getNameStart(), OffsetSLTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_SLT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetToWordMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new BitCastInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetZeroMethod)) {
+              Constant* N = Context.getNullValue(FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetSGTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_SGT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetSGEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_SGE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetSLEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_SLE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetEQMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetFromIntSignExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new SExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetFromIntZeroExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new ZExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetPlusIntMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetToIntMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int32Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetToLongMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int64Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetIsZeroMethod)) {
+              Value* Val = Call.getArgument(0);
+              Constant* N = Context.getNullValue(Val->getType());
+              Value* Res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val, N, "");
+              Res = new ZExtInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetMinusIntMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), OffsetMinusOffsetMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else {
+              fprintf(stderr, "Implement me %s\n", name);
+              abort();
+            }
+          } else if (len > strlen(ObjectReferenceClass) && 
+            !memcmp(ObjectReferenceClass, name, strlen(ObjectReferenceClass))) {
+           
+            Changed = true;
+            // Remove the null check
+            if (Call.arg_begin() != Call.arg_end()) {
+              removePotentialNullCheck(Cur, Call.getArgument(0));
+            }
+
+            if (!strcmp(FCur->getNameStart(), ObjectReferenceNullReferenceMethod)) {
+              Constant* N = Context.getNullValue(FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ObjectReferenceFromObjectMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new BitCastInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ObjectReferenceToAddressMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new BitCastInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ObjectReferenceToObjectMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new BitCastInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), ObjectReferenceIsNullMethod)) {
+              Value* Val = Call.getArgument(0);
+              Constant* N = Context.getNullValue(Val->getType());
+              Value* Res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val, N, "");
+              Res = new ZExtInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else {
+              fprintf(stderr, "Implement me %s\n", name);
+              abort();
+            }
+          } else if (len > strlen(WordClass) && 
+              !memcmp(WordClass, name, strlen(WordClass))) {
+           
+            Changed = true;
+            // Remove the null check
+            if (Call.arg_begin() != Call.arg_end()) {
+              removePotentialNullCheck(Cur, Call.getArgument(0));
+            }
+             
+            if (!strcmp(FCur->getNameStart(), WordOrMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* Res = BinaryOperator::CreateOr(Val1, Val2, "", CI);
+              Res = new IntToPtrInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordAndMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* Res = BinaryOperator::CreateAnd(Val1, Val2, "", CI);
+              Res = new IntToPtrInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordXorMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* Res = BinaryOperator::CreateXor(Val1, Val2, "", CI);
+              Res = new IntToPtrInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordRshlMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* Res = BinaryOperator::CreateLShr(Val1, Val2, "", CI);
+              Res = new IntToPtrInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordLshMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              if (Val2->getType() != pointerSizeType)
+                Val2 = new ZExtInst(Val2, pointerSizeType, "", CI);
+              Value* Res = BinaryOperator::CreateShl(Val1, Val2, "", CI);
+              Res = new IntToPtrInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordToIntMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int32Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordNotMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, pointerSizeType, "", CI);
+              Constant* M1 = Context.getConstantInt(pointerSizeType, -1);
+              Value* Res = BinaryOperator::CreateXor(Val, M1, "", CI);
+              Res = new IntToPtrInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordZeroMethod)) {
+              Constant* N = Context.getNullValue(FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordOneMethod)) {
+              Constant* N = Context.getConstantInt(pointerSizeType, 1);
+              N = ConstantExpr::getIntToPtr(N, FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordToAddressMethod) ||
+                       !strcmp(FCur->getNameStart(), WordToOffsetMethod) ||
+                       !strcmp(FCur->getNameStart(), WordToExtentMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new BitCastInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordMinusWordMethod) ||
+                       !strcmp(FCur->getNameStart(), WordMinusExtentMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateSub(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordPlusWordMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = BinaryOperator::CreateAdd(Val1, Val2, "", CI);
+              res = new IntToPtrInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordLTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_ULT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordLEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_ULE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordGEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_UGE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordEQMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordGTMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_UGT, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordNEMethod)) {
+              Value* Val1 = Call.getArgument(0);
+              Value* Val2 = Call.getArgument(1);
+              Val1 = new PtrToIntInst(Val1, pointerSizeType, "", CI);
+              Val2 = new PtrToIntInst(Val2, pointerSizeType, "", CI);
+              Value* res = new ICmpInst(CI, ICmpInst::ICMP_NE, Val1, Val2, "");
+              res = new ZExtInst(res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordFromIntSignExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new SExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordFromIntZeroExtendMethod)) {
+              Value* Val = Call.getArgument(0);
+              if (pointerSizeType != Type::Int32Ty)
+                Val = new ZExtInst(Val, pointerSizeType, "", CI);
+              Val = new IntToPtrInst(Val, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordIsZeroMethod)) {
+              Value* Val = Call.getArgument(0);
+              Constant* N = Context.getNullValue(Val->getType());
+              Value* Res = new ICmpInst(CI, ICmpInst::ICMP_EQ, Val, N, "");
+              Res = new ZExtInst(Res, FCur->getReturnType(), "", CI);
+              CI->replaceAllUsesWith(Res);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordToLongMethod)) {
+              Value* Val = Call.getArgument(0);
+              Val = new PtrToIntInst(Val, Type::Int64Ty, "", CI);
+              CI->replaceAllUsesWith(Val);
+              CI->eraseFromParent();
+            } else if (!strcmp(FCur->getNameStart(), WordMaxMethod)) {
+              ConstantInt* M = Context.getConstantInt(Type::Int64Ty, (uint64_t)-1);
+              Constant* N = ConstantExpr::getIntToPtr(M, FCur->getReturnType());
+              CI->replaceAllUsesWith(N);
+              CI->eraseFromParent();
+            } else {
+              fprintf(stderr, "Implement me %s\n", name);
+              abort();
+            }
+          }
+        }
+      }
+    }
+  }
+  return Changed;
+}
+
+
+FunctionPass* createLowerMagicPass() {
+  return new LowerMagic();
+}
+
+}

Added: vmkit/trunk/mmtk/magic/Makefile
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/magic/Makefile?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/magic/Makefile (added)
+++ vmkit/trunk/mmtk/magic/Makefile Thu Jul 16 06:26:34 2009
@@ -0,0 +1,16 @@
+##===- mmtk/magic/Makefile ---------------------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+LIBRARYNAME = MMTKMagic
+LOADABLE_MODULE = 1
+USEDLIBS =
+
+include $(LEVEL)/Makefile.common
+

Added: vmkit/trunk/mmtk/mmtk-j3/ActivePlan.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/ActivePlan.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/ActivePlan.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/ActivePlan.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,22 @@
+//===------ ActivePlan.cpp - Implementation of the ActivePlan class  ------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" JavaObject* Java_org_j3_mmtk_ActivePlan_getNextMutator__ (JavaObject* A) {
+  return 0;
+}
+
+extern "C" void Java_org_j3_mmtk_ActivePlan_resetMutatorIterator__ (JavaObject* A) {
+  return;
+}
+
+extern "C" void Java_org_j3_mmtk_ActivePlan_collectorCount__ () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/Assert.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Assert.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Assert.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Assert.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,14 @@
+//===----------- Assert.cpp - Implementation of the Assert class  ---------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_Assert_dumpStack__ () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/Collection.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Collection.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Collection.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Collection.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,54 @@
+//===------- Collection.cpp - Implementation of the Collection class  -----===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void JnJVM_org_mmtk_plan_Plan_setCollectionTriggered__();
+
+extern "C" void JnJVM_org_j3_config_Selected_00024Collector_staticCollect__();
+
+extern "C" void JnJVM_org_mmtk_plan_Plan_collectionComplete__();
+
+
+extern "C" bool Java_org_j3_mmtk_Collection_isEmergencyAllocation__ (JavaObject* C) {
+  return false;
+}
+
+extern "C" void Java_org_j3_mmtk_Collection_reportAllocationSuccess__ (JavaObject* C) {
+}
+
+
+extern "C" void Java_org_j3_mmtk_Collection_triggerCollection__I (JavaObject* C, int why) {
+  JnJVM_org_mmtk_plan_Plan_setCollectionTriggered__();
+  JnJVM_org_j3_config_Selected_00024Collector_staticCollect__();
+  JnJVM_org_mmtk_plan_Plan_collectionComplete__();
+}
+
+extern "C" int Java_org_j3_mmtk_Collection_rendezvous__I (JavaObject* C, int where) {
+  return 1;
+}
+
+extern "C" int Java_org_j3_mmtk_Collection_maximumCollectionAttempt__ (JavaObject* C) {
+  return 1;
+}
+
+extern "C" void Java_org_j3_mmtk_Collection_prepareCollector__Lorg_mmtk_plan_CollectorContext_2 (JavaObject* C, JavaObject* CC) {
+}
+
+
+extern "C" void Java_org_j3_mmtk_Collection_joinCollection__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_reportPhysicalAllocationFailed__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_triggerAsyncCollection__I () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_noThreadsInGC__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_prepareMutator__Lorg_mmtk_plan_MutatorContext_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_activeGCThreads__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_activeGCThreadOrdinal__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Collection_requestMutatorFlush__ () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/FinalizableProcessor.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/FinalizableProcessor.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/FinalizableProcessor.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/FinalizableProcessor.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,26 @@
+//===- FinalizableProcessor.cpp -------------------------------------------===//
+//===- Implementation of the FinalizableProcessor class  ------------------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_FinalizableProcessor_clear__ () {
+  abort();
+}
+
+extern "C" void
+Java_org_j3_mmtk_FinalizableProcessor_forward__Lorg_mmtk_plan_TraceLocal_2Z () {
+  abort();
+}
+
+extern "C" void
+Java_org_j3_mmtk_FinalizableProcessor_scan__Lorg_mmtk_plan_TraceLocal_2Z () {
+}

Added: vmkit/trunk/mmtk/mmtk-j3/Lock.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Lock.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Lock.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Lock.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,28 @@
+//===----------- Lock.cpp - Implementation of the Lock class  -------------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+#include "mvm/Threads/Locks.h"
+
+using namespace jnjvm;
+
+struct Lock {
+  JavaObject base;
+  mvm::SpinLock spin;
+};
+
+
+extern "C" void Java_org_j3_mmtk_Lock_acquire__(Lock* l) {
+  l->spin.acquire();
+}
+extern "C" void Java_org_j3_mmtk_Lock_check__I () { abort(); }
+
+extern "C" void Java_org_j3_mmtk_Lock_release__(Lock* l) {
+  l->spin.release();
+}

Added: vmkit/trunk/mmtk/mmtk-j3/Makefile
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Makefile?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Makefile (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Makefile Thu Jul 16 06:26:34 2009
@@ -0,0 +1,18 @@
+##===- mmtk/magic/Makefile ---------------------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+LIBRARYNAME = MMTKRuntime
+LOADABLE_MODULE = 1
+USEDLIBS =
+
+CXX.Flags += -I$(PROJ_OBJ_DIR)/../../lib/JnJVM/VMCore
+
+include $(LEVEL)/Makefile.common
+

Added: vmkit/trunk/mmtk/mmtk-j3/Memory.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Memory.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Memory.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Memory.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,76 @@
+//===------------ Memory.cpp - Implementation of the Memory class  --------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sys/mman.h>
+
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+extern "C" uintptr_t Java_org_j3_mmtk_Memory_getHeapStartConstant__ () {
+  return (uintptr_t)0x30000000;
+}
+
+extern "C" uintptr_t Java_org_j3_mmtk_Memory_getHeapEndConstant__ () {
+  return (uintptr_t)0x80000000;
+}
+
+extern "C" uintptr_t Java_org_j3_mmtk_Memory_getAvailableStartConstant__ () {
+  return (uintptr_t)0x30000000;
+}
+
+extern "C" uintptr_t Java_org_j3_mmtk_Memory_getAvailableEndConstant__ () {
+  return (uintptr_t)0x80000000;
+}
+
+extern "C" sint32
+Java_org_j3_mmtk_Memory_dzmmap__Lorg_vmmagic_unboxed_Address_2I(JavaObject* M,
+                                                                void* start,
+                                                                sint32 size) {
+#if defined (__MACH__)
+  uint32 flags = MAP_PRIVATE | MAP_ANON | MAP_FIXED;
+#else
+  uint32 flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
+#endif
+  void* baseAddr = mmap((void*)start, size, PROT_READ | PROT_WRITE, flags,
+                        -1, 0);
+  if (baseAddr == MAP_FAILED) {
+    perror("mmap");
+    abort();
+  }
+
+  return 0;
+}
+
+extern "C" void
+Java_org_j3_mmtk_Memory_mprotect__Lorg_vmmagic_unboxed_Address_2I () {
+  abort();
+}
+
+extern "C" void
+Java_org_j3_mmtk_Memory_munprotect__Lorg_vmmagic_unboxed_Address_2I () {
+  abort();
+}
+
+extern "C" void
+Java_org_j3_mmtk_Memory_zero__Lorg_vmmagic_unboxed_Address_2Lorg_vmmagic_unboxed_Extent_2(JavaObject* M,
+                                                                                          void* addr,
+                                                                                          uintptr_t len) {
+  memset(addr, 0, len);
+}
+
+extern "C" void
+Java_org_j3_mmtk_Memory_zeroPages__Lorg_vmmagic_unboxed_Address_2I () {
+  abort();
+}
+
+extern "C" void
+Java_org_j3_mmtk_Memory_dumpMemory__Lorg_vmmagic_unboxed_Address_2II () {
+  abort();
+}

Added: vmkit/trunk/mmtk/mmtk-j3/ObjectModel.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/ObjectModel.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/ObjectModel.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/ObjectModel.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,51 @@
+//===---- ObjectModel.cpp - Implementation of the ObjectModel class  ------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" intptr_t Java_org_j3_mmtk_ObjectModel_getArrayBaseOffset__ () {
+  return sizeof(JavaObject) + sizeof(ssize_t);
+}
+
+extern "C" intptr_t Java_org_j3_mmtk_ObjectModel_GC_1HEADER_1OFFSET__ () {
+  return sizeof(void*);
+}
+
+extern "C" uintptr_t Java_org_j3_mmtk_ObjectModel_readAvailableBitsWord__Lorg_vmmagic_unboxed_ObjectReference_2 (JavaObject* OM, JavaObject* obj) {
+  return ((uintptr_t*)obj)[1];
+}
+
+extern "C" void Java_org_j3_mmtk_ObjectModel_writeAvailableBitsWord__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Word_2 (JavaObject* OM, JavaObject* obj, uintptr_t val) {
+  ((uintptr_t*)obj)[1] = val;
+}
+
+extern "C" void Java_org_j3_mmtk_ObjectModel_copy__Lorg_vmmagic_unboxed_ObjectReference_2I () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_copyTo__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Address_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getReferenceWhenCopiedTo__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Address_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getObjectEndAddress__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getSizeWhenCopied__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getAlignWhenCopied__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getAlignOffsetWhenCopied__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getCurrentSize__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getNextObject__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getObjectFromStartAddress__Lorg_vmmagic_unboxed_Address_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getTypeDescriptor__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_getArrayLength__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_isArray__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_isPrimitiveArray__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_attemptAvailableBits__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Word_2Lorg_vmmagic_unboxed_Word_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_prepareAvailableBits__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_writeAvailableByte__Lorg_vmmagic_unboxed_ObjectReference_2B () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_readAvailableByte__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_objectStartRef__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_refToAddress__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_isAcyclic__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_ObjectModel_dumpObject__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/ReferenceProcessor.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/ReferenceProcessor.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/ReferenceProcessor.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/ReferenceProcessor.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,20 @@
+//===-------- ReferenceProcessor.cpp --------------------------------------===//
+//===-------- Implementation of the Selected class  -----------------------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_ReferenceProcessor_scan__Lorg_mmtk_plan_TraceLocal_2Z () {
+}
+
+extern "C" void Java_org_j3_mmtk_ReferenceProcessor_forward__Lorg_mmtk_plan_TraceLocal_2Z () { abort(); }
+extern "C" void Java_org_j3_mmtk_ReferenceProcessor_clear__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_ReferenceProcessor_countWaitingReferences__ () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/Scanning.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Scanning.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Scanning.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Scanning.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,29 @@
+//===-------- Scanning.cpp - Implementation of the Scanning class  --------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_Scanning_computeThreadRoots__Lorg_mmtk_plan_TraceLocal_2 () {
+}
+
+extern "C" void Java_org_j3_mmtk_Scanning_computeGlobalRoots__Lorg_mmtk_plan_TraceLocal_2 () {
+}
+
+extern "C" void Java_org_j3_mmtk_Scanning_computeStaticRoots__Lorg_mmtk_plan_TraceLocal_2 () {
+}
+
+extern "C" void Java_org_j3_mmtk_Scanning_resetThreadCounter__ () {
+}
+
+extern "C" void Java_org_j3_mmtk_Scanning_scanObject__Lorg_mmtk_plan_TransitiveClosure_2Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_Scanning_specializedScanObject__ILorg_mmtk_plan_TransitiveClosure_2Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_Scanning_precopyChildren__Lorg_mmtk_plan_TraceLocal_2Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_Scanning_preCopyGCInstances__Lorg_mmtk_plan_TraceLocal_2 () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/Selected.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Selected.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Selected.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Selected.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+//===-------- Selected.cpp - Implementation of the Selected class  --------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaArray.h"
+#include "JavaClass.h"
+#include "JavaObject.h"
+#include "JavaThread.h"
+
+using namespace jnjvm;
+
+#if 1
+
+extern "C" JavaObject* org_j3_config_Selected_4Mutator_static;
+extern "C" JavaObject* org_j3_config_Selected_4Collector_static;
+
+
+extern "C" JavaObject* Java_org_j3_config_Selected_00024Collector_get__() {
+  JavaObject* obj = org_j3_config_Selected_4Collector_static;
+  return obj;
+}
+
+extern "C" JavaObject* Java_org_j3_config_Selected_00024Mutator_get__() {
+  JavaObject* obj = org_j3_config_Selected_4Mutator_static;
+  return obj;
+}
+
+
+#else
+extern "C" JavaObject* Java_org_j3_config_Selected_00024Collector_get__() {
+  return 0;
+}
+
+extern "C" JavaObject* Java_org_j3_config_Selected_00024Mutator_get__() {
+  return 0;
+}
+#endif

Added: vmkit/trunk/mmtk/mmtk-j3/Statistics.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Statistics.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Statistics.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Statistics.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,25 @@
+//===----- Statistics.cpp - Implementation of the Statistics class  -------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_Statistics_perfCtrInit__I (JavaObject* S) {
+  // Implement me
+}
+
+extern "C" int64_t Java_org_j3_mmtk_Statistics_cycles__ () {
+  return 0;
+}
+
+extern "C" void Java_org_j3_mmtk_Statistics_getCollectionCount__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Statistics_nanoTime__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Statistics_perfCtrReadCycles__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_Statistics_perfCtrReadMetric__ () { abort(); }

Added: vmkit/trunk/mmtk/mmtk-j3/Strings.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/Strings.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/Strings.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/Strings.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,50 @@
+//===--------- Strings.cpp - Implementation of the Strings class  ---------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaArray.h"
+#include "JavaObject.h"
+#include "JavaString.h"
+#include "JavaThread.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_Strings_write___3CI(JavaObject* str,
+                                                     ArrayUInt16* msg,
+                                                     sint32 len) {
+  for (sint32 i = 0; i < len; ++i)
+    fprintf(stderr, "%c", msg->elements[i]);
+}
+
+extern "C" void Java_org_j3_mmtk_Strings_writeThreadId___3CI(JavaObject*str,
+                                                             ArrayUInt16* msg,
+                                                             sint32 len) {
+  
+  fprintf(stderr, "[%p] ", (void*)JavaThread::get());
+  
+  for (sint32 i = 0; i < len; ++i)
+    fprintf(stderr, "%c", msg->elements[i]);
+}
+
+
+extern "C" sint32
+Java_org_j3_mmtk_Strings_copyStringToChars__Ljava_lang_String_2_3CII(
+    JavaObject* obj, JavaString* str, ArrayUInt16* dst, uint32 dstBegin,
+    uint32 dstEnd) {
+
+  sint32 len = str->count;
+  sint32 n = (dstBegin + len <= dstEnd) ? len : (dstEnd - dstBegin);
+
+  for (sint32 i = 0; i < n; i++) {
+    dst->elements[dstBegin + i] = str->value->elements[str->offset + i];
+  }
+  
+  return n;
+ 
+}
+

Added: vmkit/trunk/mmtk/mmtk-j3/SynchronizedCounter.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/SynchronizedCounter.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/SynchronizedCounter.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/SynchronizedCounter.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,17 @@
+//===-------- SynchronizedCounter.cpp -------------------------------------===//
+//===-------- Implementation of the SynchronizedCounter class  ------------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_SynchronizedCounter_reset__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_SynchronizedCounter_increment__ () { abort(); }
+

Added: vmkit/trunk/mmtk/mmtk-j3/TraceInterface.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/TraceInterface.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/TraceInterface.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/TraceInterface.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,29 @@
+//===-- TraceInterface.cpp - Implementation of the TraceInterface class  --===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_mmtk_TraceInterface_gcEnabled__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_adjustSlotOffset__ZLorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Address_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_skipOwnFramesAndDump__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_updateDeathTime__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_setDeathTime__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Word_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_setLink__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_updateTime__Lorg_vmmagic_unboxed_Word_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getOID__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getDeathTime__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getLink__Lorg_vmmagic_unboxed_ObjectReference_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getBootImageLink__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getOID__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_setOID__Lorg_vmmagic_unboxed_Word_2 () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getHeaderSize__ () { abort(); }
+extern "C" void Java_org_j3_mmtk_TraceInterface_getHeaderEndOffset__ () { abort(); }
+

Added: vmkit/trunk/mmtk/mmtk-j3/VM.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/mmtk/mmtk-j3/VM.cpp?rev=75904&view=auto

==============================================================================
--- vmkit/trunk/mmtk/mmtk-j3/VM.cpp (added)
+++ vmkit/trunk/mmtk/mmtk-j3/VM.cpp Thu Jul 16 06:26:34 2009
@@ -0,0 +1,42 @@
+//===-------------- VM.cpp - Implementation of the VM class  --------------===//
+//
+//                              The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JavaObject.h"
+#include "JavaThread.h"
+
+using namespace jnjvm;
+
+extern "C" void Java_org_j3_runtime_VM_sysWrite__Lorg_vmmagic_unboxed_Extent_2 () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysWrite__Lorg_vmmagic_unboxed_Address_2 () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysWrite__F () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysWrite__I () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysWrite__Ljava_lang_String_2 () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysWriteln__ () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysWriteln__Ljava_lang_String_2 () { abort(); }
+extern "C" void Java_org_j3_runtime_VM__1assert__ZLjava_lang_String_2 () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysExit__I () { abort(); }
+extern "C" void Java_org_j3_runtime_VM_sysFail__Ljava_lang_String_2 () { abort(); }
+
+extern "C" void Java_org_j3_runtime_VM__1assert__Z (bool cond) {
+  
+  assert(cond);
+}
+
+extern "C" bool Java_org_j3_runtime_VM_buildFor64Addr__ () { 
+  return false;
+}
+
+extern "C" bool Java_org_j3_runtime_VM_buildForIA32__ () { 
+  return true;
+}
+
+extern "C" bool Java_org_j3_runtime_VM_verifyAssertions__ () {
+  return true;
+}
+





More information about the vmkit-commits mailing list