SF.net SVN: jikesrvm:[15732] rvmroot/trunk

View: New views
1 Messages — Rating Filter:   Alert me  

SF.net SVN: jikesrvm:[15732] rvmroot/trunk

by rgarner :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Revision: 15732
          http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15732&view=rev
Author:   rgarner
Date:     2009-07-22 07:44:58 +0000 (Wed, 22 Jul 2009)

Log Message:
-----------
Major revision of MMTk Harness, addressing RVM-839, RVM-840 and RVM-838 and with
a bunch of refactoring along the way.  Highlights include:
- Support for reference types, and associated test script
- Watch points for individual objects
- Sanity checker uses read barrier, making Poisoned collector work.
- Simulated Memory class refactored to avoid static initialization races
- Several synchronization bugs fixed
- Some refactoring of the schedulers

Modified Paths:
--------------
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java
    rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/BooleanType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/Field.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/IntType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/ObjectType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/StringType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/Type.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/TypeReference.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/VoidType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/options/HarnessOptionSet.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/HeapEntry.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/HeapSnapshot.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/Sanity.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/Traversal.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/Scheduler.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/JavaThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/JavaThreadModel.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/RawThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/RawThreadModel.java
    rvmroot/trunk/MMTk/harness/test-scripts/Lists.script
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Address.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Extent.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ObjectReference.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Offset.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Word.java
    rvmroot/trunk/bin/test-mmtk

Added Paths:
-----------
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/ReferenceType.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/options/SanityUsesReadBarrier.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/options/WatchObject.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/MMTkThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/CollectorContextThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/CollectorThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/MutatorThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/CollectorContextThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/CollectorThread.java
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/MutatorThread.java
    rvmroot/trunk/MMTk/harness/test-scripts/ReferenceTypes.script
    rvmroot/trunk/MMTk/harness/test-scripts/SpreadAlloc16.options
    rvmroot/trunk/MMTk/harness/test-scripts/SpreadAlloc16.script
    rvmroot/trunk/MMTk/harness/test-scripts/lang/phantomref.script
    rvmroot/trunk/MMTk/harness/test-scripts/lang/softref.script
    rvmroot/trunk/MMTk/harness/test-scripts/lang/weakref.script
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ArchitecturalWord.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ArchitecturalWord32.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ArchitecturalWord64.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/Architecture.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/MemoryConstants.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/MemoryPage.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/PageTable.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/SimulatedMemory.java
    rvmroot/trunk/bin/test-mmtk-selected

Removed Paths:
-------------
    rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ArchitecturalWord.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ArchitecturalWord32.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ArchitecturalWord64.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Architecture.java
    rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/SimulatedMemory.java

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -12,8 +12,11 @@
  */
 package org.mmtk.harness.vm;
 
+import java.util.concurrent.BlockingQueue;
+
 import org.mmtk.harness.Collector;
 import org.mmtk.harness.Mutator;
+import org.mmtk.harness.Mutators;
 import org.mmtk.harness.scheduler.Scheduler;
 import org.mmtk.plan.Plan;
 import org.mmtk.plan.CollectorContext;
@@ -29,7 +32,10 @@
 @Uninterruptible
 public final class ActivePlan extends org.mmtk.vm.ActivePlan {
 
-  /** Initialise static state */
+  /**
+   * Initialise static state
+   * @param prefix The name of the plan class (prefix for the associated classes)
+   */
   public static void init(String prefix) {
     try {
       constraints = (PlanConstraints)Class.forName(prefix + "Constraints").newInstance();
@@ -49,9 +55,6 @@
   /** The global constraints */
   public static PlanConstraints constraints;
 
-  /** Used for iterating over mutators */
-  private static int mutatorIndex;
-
   /** @return The active Plan instance. */
   @Override
   public Plan global() { return plan; };
@@ -76,9 +79,11 @@
   @Override
   public int collectorCount() { return Collector.count(); }
 
+  private BlockingQueue<Mutator> mutators = null;
+
   /** Reset the mutator iterator */
   @Override
-  public void resetMutatorIterator() { mutatorIndex = 0; }
+  public void resetMutatorIterator() { mutators = null; }
 
   /**
    * Return the next <code>MutatorContext</code> in a
@@ -91,8 +96,11 @@
   @Override
   public MutatorContext getNextMutator() {
     synchronized(ActivePlan.class) {
-      if (mutatorIndex >= Mutator.count()) return null;
-      return Mutator.get(mutatorIndex++).getContext();
+      if (mutators == null) {
+        mutators = Mutators.getAll();
+      }
     }
+    Mutator m = mutators.poll();
+    return m == null ? null : m.getContext();
   }
 }

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -14,6 +14,9 @@
 
 import org.vmmagic.pragma.Uninterruptible;
 
+/**
+ * MMTk Harness implementation of Assert
+ */
 @Uninterruptible
 public class Assert extends org.mmtk.vm.Assert {
 
@@ -29,6 +32,7 @@
    *
    * @param message the string to log
    */
+  @Override
   public void fail(String message) {
     throw new RuntimeException("Assertion Failed: " + message);
   }
@@ -40,6 +44,7 @@
    *
    * @param cond the condition to be checked
    */
+  @Override
   public void _assert(boolean cond) {
     if (!cond) fail("");
   }
@@ -52,6 +57,7 @@
    * @param cond the condition to be checked
    * @param message the message to print
    */
+  @Override
   public void _assert(boolean cond, String message) {
     if (!cond) fail(message);
   }
@@ -59,6 +65,7 @@
   /**
    * Print a stack trace
    */
+  @Override
   public void dumpStack() {
     new Exception().printStackTrace();
   }
@@ -70,11 +77,13 @@
    *
    * @return <code>true</code> if the virtual machine is running
    */
+  @Override
   public boolean runningVM() {
     return true;
   }
 
   /** @return true if assertions should be verified */
+  @Override
   protected boolean getVerifyAssertionsConstant() {
     return true;
   }

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -15,6 +15,9 @@
 import org.vmmagic.pragma.Uninterruptible;
 import org.vmmagic.unboxed.*;
 
+/**
+ * MMTk Harness implementation of Barriers interface
+ */
 @Uninterruptible
 public class Barriers extends org.mmtk.vm.Barriers {
   /**
@@ -27,6 +30,7 @@
    * @param index the index of the element to set
    * @param value the new value for the element
    */
+  @Override
   public void setArrayNoBarrier(Object [] dst, int index, Object value) {
     dst[index] = value;
   }
@@ -41,6 +45,7 @@
    * @param metaDataB Unused
    * @param mode The context in which the write is occuring
    */
+  @Override
   public void performWriteInBarrier(ObjectReference ref, Address slot,
                                     ObjectReference target, Word metaDataA,
                                     Word metaDataB, int mode) {
@@ -57,6 +62,7 @@
    * @param metaDataB Unused
    * @param mode The context in which the write is occuring
    */
+  @Override
   public void performRawWriteInBarrier(ObjectReference ref, Address slot,
                                        Word rawTarget, Word metaDataA,
                                        Word metaDataB, int mode) {
@@ -73,6 +79,7 @@
    * @param mode The context in which the write is occuring
    * @return the read value
    */
+  @Override
   public ObjectReference performReadInBarrier(ObjectReference ref, Address slot,
                                               Word metaDataA, Word metaDataB, int mode) {
     return slot.loadObjectReference();
@@ -88,6 +95,7 @@
    * @param mode The context in which the write is occuring
    * @return the read value
    */
+  @Override
   public Word performRawReadInBarrier(ObjectReference ref, Address slot,
                                       Word metaDataA, Word metaDataB, int mode) {
     return slot.loadWord();
@@ -105,6 +113,7 @@
    * @param mode The context in which the write is occuring
    * @return The value that was replaced by the write.
    */
+  @Override
   public ObjectReference performWriteInBarrierAtomic(ObjectReference ref, Address slot,
                                                      ObjectReference target, Word metaDataA,
                                                      Word metaDataB, int mode) {
@@ -127,6 +136,7 @@
    * @param mode The context in which the write is occuring
    * @return The raw value that was replaced by the write.
    */
+  @Override
   public Word performRawWriteInBarrierAtomic(ObjectReference ref, Address slot,
                                              Word rawTarget, Word metaDataA,
                                              Word metaDataB, int mode) {
@@ -149,6 +159,7 @@
    * @param mode The context in which the write is occuring
    * @return True if the compare and swap was successful
    */
+  @Override
   public boolean tryCompareAndSwapWriteInBarrier(ObjectReference ref, Address slot,
                                                  ObjectReference old, ObjectReference target,
                                                  Word metaDataA, Word metaDataB, int mode) {
@@ -167,6 +178,7 @@
    * @param mode The context in which the write is occuring
    * @return True if the compare and swap was successful
    */
+  @Override
   public boolean tryRawCompareAndSwapWriteInBarrier(ObjectReference ref, Address slot,
                                                     Word rawOld, Word rawTarget,
                                                     Word metaDataA, Word metaDataB, int mode) {

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -15,6 +15,8 @@
 import org.mmtk.harness.Collector;
 import org.mmtk.harness.Harness;
 import org.mmtk.harness.Mutator;
+import org.mmtk.harness.Mutators;
+import org.mmtk.harness.exception.OutOfMemory;
 import org.mmtk.harness.scheduler.Scheduler;
 import org.mmtk.plan.CollectorContext;
 import org.mmtk.plan.MutatorContext;
@@ -37,6 +39,7 @@
    * @param why the reason why a collection was triggered.  0 to
    *          <code>TRIGGER_REASONS - 1</code>.
    */
+  @Override
   public void triggerCollection(int why) {
     if (Options.verbose.getValue() >= 4) {
       new Exception("Collection trigger: " + triggerReasons[why]).printStackTrace();
@@ -57,19 +60,20 @@
       mutator.reportCollectionAttempt();
     }
 
-    if (mutator.isOutOfMemory()) throw new Mutator.OutOfMemory();
+    if (mutator.isOutOfMemory()) throw new OutOfMemory();
 
     Collector.triggerGC(why);
     Scheduler.waitForGC();
 
     if (mutator.isOutOfMemory() && !mutator.isPhysicalAllocationFailure()) {
-      throw new Mutator.OutOfMemory();
+      throw new OutOfMemory();
     }
   }
 
   /**
    * Joins an already requested collection.
    */
+  @Override
   public void joinCollection() {
     while (Plan.isCollectionTriggered()) {
       /* allow a gc thread to run */
@@ -77,7 +81,7 @@
     }
     Mutator mutator = Mutator.current();
     if (mutator.isOutOfMemory() && !mutator.isPhysicalAllocationFailure()) {
-      throw new Mutator.OutOfMemory();
+      throw new OutOfMemory();
     }
   }
 
@@ -88,6 +92,7 @@
    * @param why the reason why a collection was triggered.  0 to
    *          <code>TRIGGER_REASONS - 1</code>.
    */
+  @Override
   public void triggerAsyncCollection(int why) {
     Plan.setCollectionTriggered();
     if (Options.verbose.getValue() >= 1) {
@@ -102,13 +107,13 @@
   }
 
   /**
-   * The maximum number collection attempts across threads.
+   * @return The maximum number of collection attempts across threads.
    */
+  @Override
   public int maximumCollectionAttempt() {
       int max = 1;
-      for(int m=0; m < Mutator.count(); m++) {
-        Mutator mutator = Mutator.get(m);
-        int current = mutator.getCollectionAttempts();
+      for(Mutator m : Mutators.getAll()) {
+        int current = m.getCollectionAttempts();
         if (current > max) max = current;
       }
       return max + Collector.getCollectionAttemptBase();
@@ -117,6 +122,7 @@
   /**
    * Report that the allocation has succeeded.
    */
+  @Override
   public void reportAllocationSuccess() {
     Mutator mutator = Mutator.current();
     mutator.setOutOfMemory(false);
@@ -127,6 +133,7 @@
   /**
    * Report that a physical allocation has failed.
    */
+  @Override
   public void reportPhysicalAllocationFailed() {
     Mutator.current().setPhysicalAllocationFailure(true);
   }
@@ -135,6 +142,7 @@
    * Does the VM consider this an emergency alloction, where the normal
    * heap size rules can be ignored.
    */
+  @Override
   public boolean isEmergencyAllocation() {
     // Not required
     return false;
@@ -148,6 +156,7 @@
    *
    * @return True if GC is not in progress.
    */
+  @Override
   public boolean noThreadsInGC() {
     return Scheduler.noThreadsInGC();
   }
@@ -157,6 +166,7 @@
    *
    * @param m the mutator to prepare
    */
+  @Override
   public void prepareMutator(MutatorContext m) {
     // Nothing to do
   }
@@ -166,6 +176,7 @@
    *
    * @param c the collector to prepare
    */
+  @Override
   public void prepareCollector(CollectorContext c) {
     // Nothing to do
   }
@@ -174,11 +185,13 @@
    * Rendezvous with all other processors, returning the rank
    * (that is, the order this processor arrived at the barrier).
    */
+  @Override
   public int rendezvous(int where) {
     return Collector.rendezvous(where);
   }
 
   /** @return The number of active collector threads */
+  @Override
   public int activeGCThreads() {
     return Harness.collectors.getValue();
   }
@@ -187,6 +200,7 @@
    * @return The ordinal ID of the running collector thread w.r.t.
    * the set of active collector threads (zero based)
    */
+  @Override
   public int activeGCThreadOrdinal() {
     return Collector.current().getContext().getId();
   }
@@ -203,6 +217,7 @@
    * will trigger the flush and then yield until all processors have
    * flushed.
    */
+  @Override
   public void requestMutatorFlush() {
     Assert.notImplemented();
   }

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -16,6 +16,7 @@
 import org.mmtk.harness.lang.Trace.Item;
 import org.mmtk.harness.sanity.FromSpaceInvariant;
 import org.mmtk.plan.Simple;
+import org.mmtk.plan.TraceLocal;
 import org.vmmagic.unboxed.Address;
 import org.vmmagic.unboxed.ObjectReference;
 
@@ -48,7 +49,7 @@
    */
   @Override
   public void arrayRemsetEntry(Address start, Address guard) {
-    Trace.trace(Item.COLLECT, "arrayRemset: [%s,%s)", start, guard);
+    Trace.trace(Item.REMSET, "arrayRemset: [%s,%s)", start, guard);
   }
 
   /**
@@ -56,7 +57,7 @@
    */
   @Override
   public void modbufEntry(ObjectReference object) {
-    Trace.trace(Item.COLLECT, "modbuf: %s", format(object));
+    Trace.trace(Item.REMSET, "modbuf: %s", format(object));
   }
 
   /**
@@ -64,7 +65,7 @@
    */
   @Override
   public void remsetEntry(Address slot) {
-    Trace.trace(Item.COLLECT, "remset: %s->%s", format(slot), format(slot.loadObjectReference()));
+    Trace.trace(Item.REMSET, "remset: %s->%s", format(slot), format(slot.loadObjectReference()));
   }
 
   /**
@@ -76,4 +77,14 @@
       new FromSpaceInvariant();
     }
   }
+
+  /**
+   * @see org.mmtk.vm.Debug#traceObject(org.mmtk.plan.TraceLocal, org.vmmagic.unboxed.ObjectReference)
+   */
+  @Override
+  public void traceObject(TraceLocal trace, ObjectReference object) {
+    Trace.trace(Item.TRACEOBJECT, "traceObject: %s", format(object));
+  }
+
+
 }

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -135,12 +135,13 @@
   /**
    * Create a new ReferenceProcessor instance using the appropriate VM-specific
    * concrete ReferenceProcessor sub-class.
+   * @param semantics The reference semantics for this processor
    *
    * @see ReferenceProcessor
    * @return A concrete VM-specific ReferenceProcessor instance.
    */
   public ReferenceProcessor newReferenceProcessor(ReferenceProcessor.Semantics semantics) {
-    return new ReferenceProcessor();
+    return ReferenceProcessor.getProcessorFor(semantics);
   }
 
   /**

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -17,6 +17,8 @@
 import org.mmtk.utility.heap.VMRequest;
 
 import org.vmmagic.unboxed.*;
+import org.vmmagic.unboxed.harness.MemoryConstants;
+import org.vmmagic.unboxed.harness.SimulatedMemory;
 import org.vmmagic.pragma.*;
 
 @Uninterruptible
@@ -207,17 +209,17 @@
   /** @return The highest address in the contiguous address space available to MMTk */
   protected Address getAvailableEndConstant()  { return HEAP_END; }
   /** @return The log base two of the size of an address */
-  protected byte getLogBytesInAddressConstant() { return (byte) SimulatedMemory.LOG_BYTES_IN_WORD; }
+  protected byte getLogBytesInAddressConstant() { return (byte) MemoryConstants.LOG_BYTES_IN_WORD; }
   /** @return The log base two of the size of a word */
-  protected byte getLogBytesInWordConstant() { return (byte) SimulatedMemory.LOG_BYTES_IN_WORD; }
+  protected byte getLogBytesInWordConstant() { return (byte) MemoryConstants.LOG_BYTES_IN_WORD; }
   /** @return The log base two of the size of an OS page */
-  protected byte getLogBytesInPageConstant() { return SimulatedMemory.LOG_BYTES_IN_PAGE; }
+  protected byte getLogBytesInPageConstant() { return MemoryConstants.LOG_BYTES_IN_PAGE; }
   /** @return The log base two of the minimum allocation alignment */
-  protected byte getLogMinAlignmentConstant()  { return (byte) SimulatedMemory.LOG_BYTES_IN_WORD; }
+  protected byte getLogMinAlignmentConstant()  { return (byte) MemoryConstants.LOG_BYTES_IN_WORD; }
   /** @return The log base two of (MAX_ALIGNMENT/MIN_ALIGNMENT) */
   protected byte getMaxAlignmentShiftConstant() { return 1; }
   /** @return The maximum number of bytes of padding to prepend to an object */
-  protected int getMaxBytesPaddingConstant() { return SimulatedMemory.BYTES_IN_WORD; }
+  protected int getMaxBytesPaddingConstant() { return MemoryConstants.BYTES_IN_WORD; }
   /** @return The value to store in alignment holes */
   protected int getAlignmentValueConstant() { return ObjectModel.ALIGNMENT_VALUE; }
 }

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -13,9 +13,11 @@
 package org.mmtk.harness.vm;
 
 import java.io.PrintStream;
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
-import java.util.Stack;
+import java.util.Collection;
 
 import org.mmtk.harness.Collector;
 import org.mmtk.harness.Mutator;
@@ -27,45 +29,46 @@
 import org.mmtk.policy.Space;
 import org.vmmagic.pragma.Uninterruptible;
 import org.vmmagic.unboxed.*;
+import org.vmmagic.unboxed.harness.ArchitecturalWord;
+import org.vmmagic.unboxed.harness.MemoryConstants;
+import org.vmmagic.unboxed.harness.SimulatedMemory;
 
+/**
+ * MMTk Harness implementation of MMTk object model
+ *    Object id (age in allocations);        (Word)
+ *    Allocation site                        (Word)
+ *    The size of the data section in words. (UInt16)
+ *    The number of reference words.         (UInt16)
+ *    Status Word (includes GC)
+ *    References
+ *    Data
+ */
 @Uninterruptible
 public final class ObjectModel extends org.mmtk.vm.ObjectModel {
 
-  /*
-   * The object model for the harness stores:
-   *
-   *    Object id (age in allocations);        (Word)
-   *    Allocation site                        (Word)
-   *    The size of the data section in words. (UInt16)
-   *    The number of reference words.         (UInt16)
-   *    Status Word (includes GC)
-   *    References
-   *    Data
-   */
-
   private static final boolean IS_32_BIT = ArchitecturalWord.getModel().bitsInWord() == 32;
 
   /** The total header size (including any requested GC words) */
   public static final int HEADER_WORDS = (IS_32_BIT ? 5 : 3) + ActivePlan.constraints.gcHeaderWords();
   /** The number of bytes in the header */
-  private static final int HEADER_SIZE = HEADER_WORDS << SimulatedMemory.LOG_BYTES_IN_WORD;
+  private static final int HEADER_SIZE = HEADER_WORDS << MemoryConstants.LOG_BYTES_IN_WORD;
   /** The number of bytes requested for GC in the header */
-  private static final int GC_HEADER_BYTES = ActivePlan.constraints.gcHeaderWords() << SimulatedMemory.LOG_BYTES_IN_WORD;
+  private static final int GC_HEADER_BYTES = ActivePlan.constraints.gcHeaderWords() << MemoryConstants.LOG_BYTES_IN_WORD;
 
   /** The offset of the first GC header word */
   private static final Offset GC_OFFSET        = Offset.zero();
   /** The offset of the object ID */
   private static final Offset ID_OFFSET        = GC_OFFSET.plus(GC_HEADER_BYTES);
   /** The offset of the allocation site */
-  private static final Offset SITE_OFFSET      = ID_OFFSET.plus(SimulatedMemory.BYTES_IN_INT);
+  private static final Offset SITE_OFFSET      = ID_OFFSET.plus(MemoryConstants.BYTES_IN_INT);
   /** The offset of the UInt16 storing the number of data fields */
-  private static final Offset DATACOUNT_OFFSET = SITE_OFFSET.plus(SimulatedMemory.BYTES_IN_INT);
+  private static final Offset DATACOUNT_OFFSET = SITE_OFFSET.plus(MemoryConstants.BYTES_IN_INT);
   /** The offset of the UInt16 storing the number of reference fields */
-  private static final Offset REFCOUNT_OFFSET  = DATACOUNT_OFFSET.plus(SimulatedMemory.BYTES_IN_INT);
+  private static final Offset REFCOUNT_OFFSET  = DATACOUNT_OFFSET.plus(MemoryConstants.BYTES_IN_INT);
   /** The offset of the status word */
-  private static final Offset STATUS_OFFSET    = REFCOUNT_OFFSET.plus(SimulatedMemory.BYTES_IN_INT);
+  private static final Offset STATUS_OFFSET    = REFCOUNT_OFFSET.plus(MemoryConstants.BYTES_IN_INT);
   /** The offset of the first reference field. */
-  public  static final Offset REFS_OFFSET      = STATUS_OFFSET.plus(SimulatedMemory.BYTES_IN_WORD);
+  public  static final Offset REFS_OFFSET      = STATUS_OFFSET.plus(MemoryConstants.BYTES_IN_WORD);
 
   @SuppressWarnings("unused")
   private static void printObjectLayout(PrintStream wr) {
@@ -84,11 +87,11 @@
   public static final int MAX_REF_FIELDS = Integer.MAX_VALUE;
 
   /** Has this object been hashed? */
-  private static final int HASHED           = 0x1 << (3 * SimulatedMemory.BITS_IN_BYTE);
+  private static final int HASHED           = 0x1 << (3 * MemoryConstants.BITS_IN_BYTE);
   /** Has this object been moved since it was hashed? */
-  private static final int HASHED_AND_MOVED = 0x3 << (3 * SimulatedMemory.BITS_IN_BYTE);
+  private static final int HASHED_AND_MOVED = 0x3 << (3 * MemoryConstants.BITS_IN_BYTE);
   /** Is this object 8 byte aligned */
-  private static final int DOUBLE_ALIGN     = 0x1 << (2 * SimulatedMemory.BITS_IN_BYTE);
+  private static final int DOUBLE_ALIGN     = 0x1 << (2 * MemoryConstants.BITS_IN_BYTE);
 
   /** The value placed in alignment holes */
   public static final int ALIGNMENT_VALUE = 1;
@@ -105,7 +108,9 @@
     return nextObjectId++;
   }
 
-  /** Return the last object ID allocated - for error reporting: NOT THREAD SAFE!!! */
+  /**
+   * @return the last object ID allocated - for error reporting: NOT THREAD SAFE!!!
+   */
   public static int lastObjectId() {
     return nextObjectId;
   }
@@ -124,11 +129,17 @@
     return watchSet.contains(getId(object));
   }
 
+  /**
+   * Add the specified object (numbered in allocation order) to the watch set.
+   * @param id Object ID
+   */
+  public static void watchObject(int id) {
+    watchSet.add(id);
+  }
+
   static {
-    //printObjectLayout(System.out);
+    //printObjectLayout(System.out);     // Sometimes helps debug the object header layout
     assert REFS_OFFSET.EQ(Offset.fromIntSignExtend(HEADER_SIZE));
-    //watchSet.add(4109);
-    //watchSet.add(8205);
   }
 
   /**
@@ -138,15 +149,20 @@
    * @param refCount The number of reference fields.
    * @param dataCount The number of data fields.
    * @param doubleAlign Align the object at an 8 byte boundary?
+   * @param site The allocation site
    * @return The new ObjectReference.
    */
   public static ObjectReference allocateObject(MutatorContext context, int refCount, int dataCount, boolean doubleAlign, int site) {
-    int bytes = (HEADER_WORDS + refCount + dataCount) << SimulatedMemory.LOG_BYTES_IN_WORD;
+    int bytes = (HEADER_WORDS + refCount + dataCount) << MemoryConstants.LOG_BYTES_IN_WORD;
     int align = ArchitecturalWord.getModel().bitsInWord() == 64 ?
-        SimulatedMemory.BYTES_IN_WORD :
-        (doubleAlign ? 2 : 1) * SimulatedMemory.BYTES_IN_INT;
-    int allocator = context.checkAllocator(bytes, align, Plan.ALLOC_DEFAULT);
+        MemoryConstants.BYTES_IN_WORD :
+        (doubleAlign ? 2 : 1) * MemoryConstants.BYTES_IN_INT;
+    int allocator = context.checkAllocator(bytes, align, refCount == 0 ? Plan.ALLOC_NON_REFERENCE : Plan.ALLOC_DEFAULT);
 
+//    if (allocator == Plan.ALLOC_LOS) {
+//      System.out.printf("Allocating %d bytes in LOS%n",bytes);
+//    }
+
     // Allocate the raw memory
     Address region = context.alloc(bytes, align, 0, allocator, 0);
 
@@ -201,6 +217,8 @@
 
   /**
    * Get the call site identifier.
+   * @param object The object
+   * @return The call site
    */
   public static int getSite(ObjectReference object) {
     return object.toAddress().loadInt(SITE_OFFSET);
@@ -208,6 +226,8 @@
 
   /**
    * Get the number of data words in the object.
+   * @param object The object
+   * @return The data count
    */
   public static int getDataCount(ObjectReference object) {
     return object.toAddress().loadInt(DATACOUNT_OFFSET);
@@ -232,34 +252,39 @@
 
   /**
    * Get the current size of an object.
+   * @param object The object
+   * @return The object size in bytes
    */
   public static int getSize(ObjectReference object) {
     int refs = getRefs(object);
     int data = getDataCount(object);
     boolean includesHash = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED_AND_MOVED) == HASHED_AND_MOVED;
 
-    return getSize(refs, data) + (includesHash ? SimulatedMemory.BYTES_IN_WORD : 0);
+    return getSize(refs, data) + (includesHash ? MemoryConstants.BYTES_IN_WORD : 0);
   }
 
   /**
    * Get the size this object will require when copied.
+   * @param object The object
+   * @return The object size in bytes after copying
    */
   public static int getCopiedSize(ObjectReference object) {
     int refs = getRefs(object);
     int data = getDataCount(object);
     boolean needsHash = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED) == HASHED;
 
-    return getSize(refs, data) + (needsHash ? SimulatedMemory.BYTES_IN_WORD : 0);
+    return getSize(refs, data) + (needsHash ? MemoryConstants.BYTES_IN_WORD : 0);
   }
 
   /**
-   * Return the address of the specified reference.
+   * Return the address of a reference field in an object.
    *
    * @param object The object with the references.
    * @param index The reference index.
+   * @return The address of the specified reference field
    */
   public static Address getRefSlot(ObjectReference object, int index) {
-    return object.toAddress().plus(REFS_OFFSET).plus(index << SimulatedMemory.LOG_BYTES_IN_WORD);
+    return object.toAddress().plus(REFS_OFFSET).plus(index << MemoryConstants.LOG_BYTES_IN_WORD);
   }
 
   /**
@@ -267,6 +292,7 @@
    *
    * @param object The object with the data slot.
    * @param index The data slot index.
+   * @return The address of the specified data field
    */
   public static Address getDataSlot(ObjectReference object, int index) {
     return getRefSlot(object, index + getRefs(object));
@@ -274,14 +300,19 @@
 
   /**
    * Calculate the size of an object.
+   * @param refs Number of reference fields
+   * @param data Number of data fields
+   * @return Size in bytes of the object
    */
   public static int getSize(int refs, int data) {
-    return (HEADER_WORDS + refs + data) << SimulatedMemory.LOG_BYTES_IN_WORD;
+    return (HEADER_WORDS + refs + data) << MemoryConstants.LOG_BYTES_IN_WORD;
   }
 
 
   /**
-   * Return the next object id to be allocated.
+   * Return the next object id to be allocated.  For debugging/formatting
+   * purposes - not thread safe.
+   * @return The next object ID
    */
   public static int nextObjectId() {
     return nextObjectId;
@@ -304,9 +335,9 @@
       } while (!addr.attempt(old, old | HASHED, STATUS_OFFSET));
     } else if (status == HASHED_AND_MOVED) {
       // Load stored hash code
-      return addr.loadInt(Offset.fromIntZeroExtend(getSize(ref) - SimulatedMemory.BYTES_IN_WORD));
+      return addr.loadInt(Offset.fromIntZeroExtend(getSize(ref) - MemoryConstants.BYTES_IN_WORD));
     }
-    return addr.toInt() >>> SimulatedMemory.LOG_BYTES_IN_WORD;
+    return addr.toInt() >>> MemoryConstants.LOG_BYTES_IN_WORD;
   }
 
   /**
@@ -334,7 +365,7 @@
         addressAndSpaceString(from),addressAndSpaceString(to));
 
     Address fromRegion = from.toAddress();
-    for(int i=0; i < oldBytes; i += SimulatedMemory.BYTES_IN_INT) {
+    for(int i=0; i < oldBytes; i += MemoryConstants.BYTES_IN_INT) {
       toRegion.plus(i).store(fromRegion.plus(i).loadInt());
     }
 
@@ -376,7 +407,7 @@
     }
     int bytes = getSize(from);
     Address fromRegion = from.toAddress();
-    for(int i=0; i < bytes; i += SimulatedMemory.BYTES_IN_WORD) {
+    for(int i=0; i < bytes; i += MemoryConstants.BYTES_IN_WORD) {
       toRegion.plus(i).store(fromRegion.plus(i).loadInt());
     }
 
@@ -384,7 +415,7 @@
     if ((status & HASHED_AND_MOVED) == HASHED) {
       toRegion.store(status | HASHED_AND_MOVED, STATUS_OFFSET);
       toRegion.store(getHashCode(from), Offset.fromIntZeroExtend(bytes));
-      bytes += SimulatedMemory.BYTES_IN_WORD;
+      bytes += MemoryConstants.BYTES_IN_WORD;
     }
 
     if (Trace.isEnabled(Item.COLLECT)) {
@@ -429,7 +460,7 @@
    */
   public int getAlignWhenCopied(ObjectReference object) {
     boolean doubleAlign = (object.toAddress().loadInt(STATUS_OFFSET) & DOUBLE_ALIGN) == DOUBLE_ALIGN;
-    return (doubleAlign ? 2 : 1) * SimulatedMemory.BYTES_IN_WORD;
+    return (doubleAlign ? 2 : 1) * MemoryConstants.BYTES_IN_WORD;
   }
 
   /**
@@ -459,7 +490,7 @@
   public ObjectReference getNextObject(ObjectReference object) {
     Address nextAddress = object.toAddress().plus(getSize(object));
     if (nextAddress.loadInt() == ALIGNMENT_VALUE) {
-      nextAddress = nextAddress.plus(SimulatedMemory.BYTES_IN_WORD);
+      nextAddress = nextAddress.plus(MemoryConstants.BYTES_IN_WORD);
     }
     if (nextAddress.loadWord().isZero()) {
       return ObjectReference.nullReference();
@@ -473,7 +504,7 @@
   @Override
   public ObjectReference getObjectFromStartAddress(Address start) {
     if ((start.loadInt() & ALIGNMENT_VALUE) != 0) {
-      start = start.plus(SimulatedMemory.BYTES_IN_WORD);
+      start = start.plus(MemoryConstants.BYTES_IN_WORD);
     }
     return start.toObjectReference();
   }
@@ -549,7 +580,7 @@
   @Override
   public boolean attemptAvailableBits(ObjectReference object, Word oldVal, Word newVal) {
     if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) {
-      Trace.printf(Item.AVBYTE,"%s.status:%s->%s", object,oldVal,newVal);
+      Trace.printf(Item.AVBYTE,"%s.status:%s->%s%n", getString(object),oldVal,newVal);
     }
     return object.toAddress().attempt(oldVal, newVal, STATUS_OFFSET);
   }
@@ -576,7 +607,7 @@
   public void writeAvailableByte(ObjectReference object, byte val) {
     if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) {
       byte old = object.toAddress().loadByte(STATUS_OFFSET);
-      Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val);
+      Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d%n", getString(object),old,val);
     }
     object.toAddress().store(val, STATUS_OFFSET);
   }
@@ -602,7 +633,7 @@
   public void writeAvailableBitsWord(ObjectReference object, Word val) {
     if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) {
       byte old = object.toAddress().loadByte(STATUS_OFFSET);
-      Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val.and(Word.fromIntZeroExtend(0xFF)).toInt());
+      Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d%n", getString(object),old,val.and(Word.fromIntZeroExtend(0xFF)).toInt());
     }
     object.toAddress().store(val, STATUS_OFFSET);
   }
@@ -692,14 +723,18 @@
 
   /**
    * Format the object for dumping, and trim to a max width.
+   * @param width Max output width
+   * @param object The object to dump
+   * @return The formatted object
    */
   public static String formatObject(int width, ObjectReference object) {
     String base = getString(object);
-    return base.substring(base.length() - width);
+    return base.substring(Math.max(base.length() - width,0));
   }
 
   /**
    * Print an object's header
+   * @param object The object reference
    */
   public static void dumpObjectHeader(ObjectReference object) {
     int gcWord = object.toAddress().loadInt(GC_OFFSET);
@@ -708,14 +743,17 @@
   }
 
   /**
-   * Dump (logical) information for an object.
+   * Dump (logical) information for an object.  Returns the non-null pointers
+   * in the object.
    * @param width Output width
    * @param object The object whose information is to be dumped
+   * @return The non-null references in the object
    */
-  public static void dumpLogicalObject(int width, ObjectReference object, Stack<ObjectReference> workStack) {
+  public static Collection<ObjectReference> dumpLogicalObject(int width, ObjectReference object) {
     int refCount = getRefs(object);
     int dataCount = getDataCount(object);
     boolean hashed = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED) == HASHED;
+    List<ObjectReference> pointers = new ArrayList<ObjectReference>(refCount);
     System.err.printf("  Object %s <%d %d %1s> [", ObjectModel.formatObject(width, object), refCount, dataCount, (hashed ? "H" : ""));
     if (refCount > 0) {
       for(int i=0; i < refCount; i++) {
@@ -723,11 +761,12 @@
         System.err.print(" ");
         System.err.print(ObjectModel.formatObject(width, ref));
         if (!ref.isNull()) {
-          workStack.push(ref);
+          pointers.add(ref);
         }
       }
     }
     System.err.println(" ]");
+    return pointers;
   }
 
   /**
@@ -737,6 +776,7 @@
    * @return "Object[size b nR/mD]
    */
   public static String getString(ObjectReference ref) {
+    if (ref.isNull()) return "<null>";
     int refs = getRefs(ref);
     int data = getDataCount(ref);
     return addressAndSpaceString(ref)+objectIdString(ref)+refs + "R" + data + "D";
@@ -762,7 +802,7 @@
 
   /**
    * Address and space name (eg 0x45678900/ms)
-   * @param ref The object
+   * @param addr The object
    * @return "address/space"
    */
   public static String addressAndSpaceString(Address addr) {

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -12,47 +12,140 @@
  */
 package org.mmtk.harness.vm;
 
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.mmtk.harness.lang.Trace;
+import org.mmtk.harness.lang.Trace.Item;
+import org.mmtk.harness.lang.runtime.ReferenceValue;
 import org.mmtk.plan.TraceLocal;
 import org.vmmagic.pragma.Uninterruptible;
+import org.vmmagic.unboxed.ObjectReference;
 
 /**
  * This class manages SoftReferences, WeakReferences, and
  * PhantomReferences.
+ *
+ * The harness only provides reference types to ensure that the MMTk
+ * Plan processes them correctly, so all types have the semantics
+ * of weak references.
  */
 @Uninterruptible
-public class ReferenceProcessor extends org.mmtk.vm.ReferenceProcessor {
+public final class ReferenceProcessor extends org.mmtk.vm.ReferenceProcessor {
 
+  private static Map<Semantics,ReferenceProcessor> processors =
+    new EnumMap<Semantics,ReferenceProcessor>(Semantics.class);
+
+  static {
+    processors.put(Semantics.SOFT, new ReferenceProcessor(Semantics.SOFT));
+    processors.put(Semantics.WEAK, new ReferenceProcessor(Semantics.WEAK));
+    processors.put(Semantics.PHANTOM, new ReferenceProcessor(Semantics.PHANTOM));
+  }
+
+  static ReferenceProcessor getProcessorFor(Semantics semantics) {
+    return processors.get(semantics);
+  }
+
   /**
+   * Discover a reference value while scanning stacks
+   * @param ref Reference value
+   */
+  public static void discover(ReferenceValue ref) {
+    processors.get(ref.getSemantics()).add(ref);
+  }
+
+  /**
+   * The set of reference objects of this semantics
+   */
+  private final Set<ReferenceValue> oldRefs = new HashSet<ReferenceValue>();
+  private final Set<ReferenceValue> currentRefs = Collections.synchronizedSet(new HashSet<ReferenceValue>());
+  private final Set<ReferenceValue> newRefs = Collections.synchronizedSet(new HashSet<ReferenceValue>());
+
+  private final Semantics semantics;
+
+  private ReferenceProcessor(Semantics semantics) {
+    this.semantics = semantics;
+  }
+
+  /**
+   * Add a reference value to the set of references of this type.
+   *
+   * This method is thread-safe, to support concurrent collection of
+   * roots, by virtue of the synchronized collection types used for newRefs
+   * and currentRefs.
+   *
+   * @param ref The reference value
+   */
+  private void add(ReferenceValue ref) {
+    Trace.trace(Item.REFERENCES, "Discovered reference %s", ref);
+    if (!oldRefs.contains(ref)) {
+      newRefs.add(ref);
+    } else {
+      currentRefs.add(ref);
+    }
+  }
+
+  /**
    * 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 void clear() {
+    Trace.trace(Item.REFERENCES, "Clearing %s references", semantics);
+    currentRefs.clear();
+    newRefs.clear();
   }
 
   /**
    * Scan through the list of references.
    *
+   * TODO support concurrent scans
+   *
+   * TODO the nursery/mature logic could be improved
+   *
    * @param trace the thread local trace element.
    * @param nursery true if it is safe to only scan new references.
    */
-  public void scan(TraceLocal trace, boolean nursery) {
-    Assert.notImplemented();
+  public synchronized void scan(TraceLocal trace, boolean nursery) {
+    Trace.trace(Item.REFERENCES, "Scanning %s references: current = %d, new = %d, %s",
+        semantics,currentRefs.size(), newRefs.size(), nursery  ? "nursery" : "full-heap");
+    if (!nursery) {
+      scanReferenceSet(trace, currentRefs);
+    }
+    scanReferenceSet(trace, newRefs);
+    oldRefs.clear();
+    oldRefs.addAll(currentRefs);
+    oldRefs.addAll(newRefs);
+    currentRefs.clear();
+    newRefs.clear();
   }
 
+  private void scanReferenceSet(TraceLocal trace, Set<ReferenceValue> set) {
+    for (ReferenceValue value : set) {
+      ObjectReference referent = value.getObjectValue();
+      if (trace.isReferentLive(referent)) {
+        value.traceObject(trace);
+      } else {
+        value.clear();
+      }
+    }
+  }
+
   /**
    * Iterate over all references and forward.
+   * @param trace The MMTk trace to forward to
+   * @param nursery The nursery collection hint
    */
   public void forward(TraceLocal trace, boolean nursery) {
     Assert.notImplemented();
   }
 
   /**
-   * Return the number of references objects on the queue
-   *
-   * @return
+   * @return the number of references objects on the queue
    */
   public int countWaitingReferences() {
-    Assert.notImplemented();
-    return 0;
+    return currentRefs.size() + newRefs.size();
   }
 }

Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java
===================================================================
--- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -12,21 +12,32 @@
  */
 package org.mmtk.harness.vm;
 
+import java.util.concurrent.BlockingQueue;
+
 import org.mmtk.harness.Mutator;
+import org.mmtk.harness.Mutators;
+import org.mmtk.harness.lang.Trace;
+import org.mmtk.harness.lang.Trace.Item;
 import org.mmtk.plan.TraceLocal;
 import org.mmtk.plan.TransitiveClosure;
 
 import org.vmmagic.pragma.Uninterruptible;
 import org.vmmagic.unboxed.*;
 
+/**
+ *
+ *
+ */
 @Uninterruptible
 public class Scanning extends org.mmtk.vm.Scanning {
   /**
    * Delegated scanning of a object, processing each pointer field
    * encountered.
+   * @param trace The trace
    *
    * @param object The object to be scanned.
    */
+  @Override
   public void scanObject(TransitiveClosure trace, ObjectReference object) {
     int refs = ObjectModel.getRefs(object);
 
@@ -44,6 +55,7 @@
    * @param trace The trace the method has been specialized for
    * @param object The object to be scanned
    */
+  @Override
   public void specializedScanObject(int id, TransitiveClosure trace, ObjectReference object) {
     scanObject(trace, object);
   }
@@ -55,12 +67,12 @@
    * @param trace The trace object to use for precopying.
    * @param object The object to be scanned.
    */
+  @Override
   public void precopyChildren(TraceLocal trace, ObjectReference object) {
     scanObject(trace, object);
   }
 
-  /** Counter for computeThreadRoots **/
-  private int threadCounter;
+  private BlockingQueue<Mutator> mutatorsToScan = null;
 
   /**
    * Prepares for using the <code>computeAllRoots</code> method.  The
@@ -69,8 +81,10 @@
    * parallel GC threads were not important, the thread counter could
    * simply be replaced by a for loop).
    */
+  @Override
   public synchronized void resetThreadCounter() {
-    threadCounter = 0;
+    assert mutatorsToScan.size() == 0;
+    mutatorsToScan = null;
   }
 
   /**
@@ -83,7 +97,9 @@
    * included in the set of roots.  The existence of this method
    * allows the actions of calculating roots and forwarding GC
    * instances to be decoupled.
+   * @param trace The MMTk trace object
    */
+  @Override
   public void preCopyGCInstances(TraceLocal trace) {
     /* None */
   }
@@ -103,6 +119,7 @@
    *
    * @param trace The trace to use for computing roots.
    */
+  @Override
   public void computeStaticRoots(TraceLocal trace) {
     /* None */
   }
@@ -122,6 +139,7 @@
    *
    * @param trace The trace to use for computing roots.
    */
+  @Override
   public void computeGlobalRoots(TraceLocal trace) {
     /* None */
   }
@@ -142,18 +160,21 @@
    *
    * @param trace The trace to use for computing roots.
    */
+  @Override
   public void computeThreadRoots(TraceLocal trace) {
+    Trace.trace(Item.COLLECT,"Computing roots for mutators");
+    synchronized(this) {
+      if (mutatorsToScan == null) {
+        mutatorsToScan = Mutators.getAll();
+      }
+    }
     while(true) {
-      int myIndex;
-      synchronized(this) {
-        myIndex = threadCounter++;
-      }
-
-      if (myIndex >= Mutator.count()) {
+      Trace.trace(Item.COLLECT,"mutators to scan: %d",mutatorsToScan.size());
+      Mutator m = mutatorsToScan.poll();
+      if (m == null)
         break;
-      }
-
-      Mutator.get(myIndex).computeThreadRoots(trace);
+      Trace.trace(Item.COLLECT,"Computing roots for mutator");
+      m.computeThreadRoots(trace);
     }
   }
 
@@ -169,6 +190,7 @@
    *
    * @param trace The trace object to use to report root locations.
    */
+  @Override
   public void computeBootImageRoots(TraceLocal trace) {
     /* None */
   }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -200,6 +200,7 @@
       synchronized (this) {
         while (!started) {
           try {
+            /* Wait for the timeout thread to start running */
             wait();
           } catch (InterruptedException e) {
           }
@@ -214,10 +215,13 @@
     public void run() {
       long startTime = System.currentTimeMillis();
       synchronized (this) {
+        /* Inform the caller that the timeout thread has started */
+        started = true;
+        notify();
+
         while (!cancelled) {
           try {
-            started = true;
-            notify();
+            /* Sleep until woken by a cancel or the timer has expired */
             long now = System.currentTimeMillis();
             if (now - startTime >= timeout) {
               System.err.printf("Collection exceeded timeout %dms%n",timeout);
@@ -252,18 +256,20 @@
    */
   private void collect() {
     boolean primary = context.getId() == 0;
-    Sanity sanity = new Sanity();
+    Sanity sanity = null;
     TimeoutThread timeout = null;
+    rendezvous(5000);
     if (primary) {
       Plan.setCollectionTrigger(Scheduler.getTriggerReason());
+      sanity = new Sanity();
       sanity.snapshotBefore();
       timeout = new TimeoutThread(Harness.timeout.getValue());
     }
+    rendezvous(5001);
 
     long startTime = System.nanoTime();
     boolean internalPhaseTriggered = (Scheduler.getTriggerReason() == Collection.INTERNAL_PHASE_GC_TRIGGER);
     boolean userTriggered = (Scheduler.getTriggerReason() == Collection.EXTERNAL_GC_TRIGGER);
-    rendezvous(5000);
 
     do {
       context.collect();
@@ -306,8 +312,7 @@
       if (Plan.isEmergencyCollection()) {
         boolean gcFailed = ActivePlan.plan.lastCollectionFailed();
         // Allocate OOMEs (some of which *may* not get used)
-        for(int m=0; m < Mutator.count(); m++) {
-          Mutator mutator = Mutator.get(m);
+        for (Mutator mutator : Mutators.getAll()) {
           if (mutator.getCollectionAttempts() > 0) {
             /* this thread was allocating */
             if (gcFailed || mutator.isPhysicalAllocationFailure()) {
@@ -318,6 +323,7 @@
       }
     }
 
+    rendezvous(5202);
     if (primary) {
       sanity.snapshotAfter();
       sanity.assertSanity();
@@ -328,12 +334,10 @@
         Mutator.dumpHeap();
         heapDumpRequested = false;
       }
-    }
-    rendezvous(5202);
-    if (primary) {
       Plan.collectionComplete();
       timeout.cancel();
     }
+    rendezvous(5203);
   }
 
 }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -16,12 +16,14 @@
 
 import org.mmtk.harness.options.*;
 import org.mmtk.harness.scheduler.AbstractPolicy;
+import org.mmtk.harness.scheduler.MMTkThread;
 import org.mmtk.harness.vm.*;
 
 import org.mmtk.utility.Log;
 import org.mmtk.utility.heap.HeapGrowthManager;
 import org.mmtk.utility.options.Options;
-import org.vmmagic.unboxed.ArchitecturalWord;
+import org.vmmagic.unboxed.harness.ArchitecturalWord;
+import org.vmutil.options.BooleanOption;
 
 /**
  * This is the central class for the MMTk test harness.
@@ -64,18 +66,27 @@
   /** Interval for the fixed scheduler policies */
   public static final YieldInterval yieldInterval = new YieldInterval();
 
-  /** Parameters for the random scheduler policy */
+  /* Parameters for the random scheduler policy */
+  /** Length of the pseudo-random yield interval sequence */
   public static final RandomPolicyLength randomPolicyLength = new RandomPolicyLength();
+  /** Seed for the pseudo-random yield interval sequence */
   public static final RandomPolicySeed randomPolicySeed = new RandomPolicySeed();
+  /** Minimum value of each entry in the pseudo-random yield interval sequence */
   public static final RandomPolicyMin randomPolicyMin = new RandomPolicyMin();
+  /** Maximum value of each entry in the pseudo-random yield interval sequence */
   public static final RandomPolicyMax randomPolicyMax = new RandomPolicyMax();
 
   /** Print yield policy statistics on exit */
   public static final PolicyStats policyStats = new PolicyStats();
 
+  /** A set of objects to watch */
+  public static final WatchObject watchObject = new WatchObject();
+
   /** Timeout on unreasonably long GC */
   public static final Timeout timeout = new Timeout();
 
+  public static final BooleanOption sanityUsesReadBarrier = new SanityUsesReadBarrier();
+
   private static boolean isInitialized = false;
 
   /**
@@ -83,6 +94,7 @@
    * and starting off the collector threads.
    *
    * After calling this it is possible to begin creating mutator threads.
+   * @param args Command-line arguments
    */
   public static void init(String... args) {
     if (isInitialized) {
@@ -102,7 +114,7 @@
         options.process(arg);
       }
     }
-    ArchitecturalWord.init();  // Reads 'bits'
+    ArchitecturalWord.init(Harness.bits.getValue());  // Reads 'bits'
     for(String arg: args) {
       if (!options.process(arg)) newArgs.add(arg);
     }
@@ -115,6 +127,7 @@
      * give it a per-thread 'Log' object
      */
     MMTkThread m = new MMTkThread() {
+      @Override
       public void run() {
 
         /* Get MMTk breathing */
@@ -125,7 +138,6 @@
 
         /* Override some defaults */
         Options.noFinalizer.setValue(true);
-        Options.noReferenceTypes.setValue(true);
         Options.variableSizeHeap.setValue(false);
 
         /* Process command line options */
@@ -137,7 +149,6 @@
 
         /* Check options */
         assert Options.noFinalizer.getValue(): "noFinalizer must be true";
-        assert Options.noReferenceTypes.getValue(): "noReferenceTypes must be true";
 
         /* Finish starting up MMTk */
         ActivePlan.plan.postBoot();
@@ -153,9 +164,15 @@
 
     org.mmtk.harness.scheduler.Scheduler.initCollectors();
 
+    for (int value : watchObject.getValue()) {
+      System.out.printf("Setting watch for object %d%n", value);
+      org.mmtk.harness.vm.ObjectModel.watchObject(value);
+    }
+
     /* Add exit handler to print yield stats */
     if (policyStats.getValue()) {
       Runtime.getRuntime().addShutdownHook(new Thread() {
+        @Override
         public void run() {
           AbstractPolicy.printStats();
         }

Deleted: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -1,55 +0,0 @@
-/*
- *  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.harness;
-
-import org.mmtk.utility.Log;
-
-public class MMTkThread extends Thread {
-
-  /** The per-thread Log instance */
-  protected final Log log = new Log();
-
-  public MMTkThread() {
-    super();
-    trapUncaughtExceptions();
-  }
-
-  public MMTkThread(Runnable target, String name) {
-    super(target, name);
-    trapUncaughtExceptions();
-  }
-
-  public MMTkThread(Runnable target) {
-    super(target);
-    trapUncaughtExceptions();
-  }
-
-  public MMTkThread(String name) {
-    super(name);
-    trapUncaughtExceptions();
-  }
-
-  private void trapUncaughtExceptions() {
-    setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
-      public void uncaughtException(Thread t, Throwable e) {
-        System.err.print("Unexpected exception: ");
-        e.printStackTrace();
-        System.exit(1);
-      }
-    });
-  }
-
-  public final Log getLog() {
-    return log;
-  }
-}

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -12,11 +12,11 @@
  */
 package org.mmtk.harness;
 
-import java.util.ArrayList;
+import java.util.ArrayDeque;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.Stack;
 
 import org.mmtk.harness.lang.Trace;
 import org.mmtk.harness.lang.Trace.Item;
@@ -32,6 +32,7 @@
 import org.mmtk.vm.VM;
 import org.vmmagic.unboxed.Address;
 import org.vmmagic.unboxed.ObjectReference;
+import org.vmmagic.unboxed.Word;
 
 /**
  * This class represents a mutator thread that has memory managed by MMTk.
@@ -46,6 +47,7 @@
  * that a GC can not occur unless you execute commands on the mutator (or muEnd it).
  */
 public abstract class Mutator {
+
   private static boolean gcEveryWB = false;
 
   /**
@@ -55,55 +57,48 @@
     gcEveryWB = true;
   }
 
-  /** Registered mutators */
-  protected static final ArrayList<Mutator> mutators = new ArrayList<Mutator>();
-
   /**
-   * @return The active mutators
+   * @return A mutator context for the current Plan
    */
-  public static java.util.Collection<Mutator> getMutators() {
-    return Collections.unmodifiableCollection(mutators);
+  public static MutatorContext createMutatorContext() {
+    try {
+      String prefix = Harness.plan.getValue();
+      return (MutatorContext)Class.forName(prefix + "Mutator").newInstance();
+    } catch (Exception ex) {
+      throw new RuntimeException("Could not create Mutator", ex);
+    }
   }
 
   /**
-   * Get a mutator by id.
-   */
-  public static Mutator get(int id) {
-    return mutators.get(id);
-  }
-
-  /**
    * Get the currently executing mutator.
+   * @return the currently executing mutator.
    */
   public static Mutator current() {
     return Scheduler.currentMutator();
   }
 
   /**
-   * Return the number of mutators that have been created.
-   */
-  public static int count() {
-    return mutators.size();
-  }
-
-  /**
    * Register a mutator, returning the allocated id.
+   * @param context The mutator context to register
    */
-  public static synchronized void register(MutatorContext context) {
-    int id = mutators.size();
-    mutators.add(null);
-    context.initMutator(id);
+  private static synchronized void register(MutatorContext context) {
+    context.initMutator(Mutators.registerMutator());
   }
 
   /** Is this thread out of memory if the gc cannot free memory */
   private boolean outOfMemory;
 
-  /** Get the out of memory status */
+  /** Get the out of memory status
+   * @return True if we're subject to an out-of-memory condition
+   */
   public boolean isOutOfMemory() {
     return outOfMemory;
   }
 
-  /** Set the out of memory status */
+  /**
+   * Set the out of memory status
+   * @param value The status
+   */
   public void setOutOfMemory(boolean value) {
     outOfMemory = value;
   }
@@ -111,7 +106,9 @@
   /** The number of collection attempts this thread has had since allocation succeeded */
   private int collectionAttempts;
 
-  /** Get the number of collection attempts */
+  /**
+   * @return the number of collection attempts
+   */
   public int getCollectionAttempts() {
     return collectionAttempts;
   }
@@ -129,12 +126,16 @@
   /** Was the last failure a physical allocation failure (rather than a budget failure) */
   private boolean physicalAllocationFailure;
 
-  /** Was the last failure a physical allocation failure */
+  /**
+   * Was the last failure a physical allocation failure
+   * @return Was the last failure a physical allocation failure
+   */
   public boolean isPhysicalAllocationFailure() {
     return physicalAllocationFailure;
   }
 
-  /** Set if last failure a physical allocation failure */
+  /** Set if last failure a physical allocation failure
+   * @param value The new status */
   public void setPhysicalAllocationFailure(boolean value) {
     physicalAllocationFailure = value;
   }
@@ -143,50 +144,22 @@
   protected final MutatorContext context;
 
   /**
-   * The type of exception that is expected at the end of execution.
+   * Constructor
    */
-  private Class<?> expectedThrowable;
-
-  /**
-   * Set an expectation that the execution will exit with a throw of this exception.
-   */
-  public void setExpectedThrowable(Class<?> expectedThrowable) {
-    this.expectedThrowable = expectedThrowable;
-  }
-
   public Mutator() {
-    try {
-      String prefix = Harness.plan.getValue();
-      this.context = (MutatorContext)Class.forName(prefix + "Mutator").newInstance();
-      register(this.context);
-    } catch (Exception ex) {
-      throw new RuntimeException("Could not create Mutator", ex);
-    }
+    this.context = createMutatorContext();
+    register(this.context);
   }
 
-  public void begin() {
-    mutators.set(context.getId(), this);
-  }
-
   /**
-   * Mutator-specific handling of uncaught exceptions.
-   * @param t
-   * @param e
+   * Initial processing of a mutator.  Enters the mutator in the mutator table.
    */
-  public void uncaughtException(Thread t, Throwable e) {
-    if (e.getClass() == expectedThrowable) {
-      System.err.println("Mutator " + context.getId() + " exiting due to expected exception of class " + expectedThrowable);
-      expectedThrowable = null;
-      end();
-    } else {
-      System.err.print("Mutator " + context.getId() + " caused unexpected exception: ");
-      e.printStackTrace();
-      System.exit(1);
-    }
+  public void begin() {
+    Mutators.set(this);
   }
 
   /**
-   * Return the MMTk MutatorContext for this mutator.
+   * @return the MMTk MutatorContext for this mutator.
    */
   public MutatorContext getContext() {
     return context;
@@ -194,6 +167,7 @@
 
   /**
    * Compute the thread roots for this mutator.
+   * @param trace The MMTk TraceLocal to receive the roots
    */
   public void computeThreadRoots(TraceLocal trace) {
     // Nothing to do for the default mutator
@@ -201,14 +175,17 @@
 
   /**
    * Return the roots
+   * @return The roots for this mutator
    */
   public abstract Iterable<ObjectValue> getRoots();
 
   /**
-   * Print the thread roots and add them to a stack for processing.
+   * Print the thread roots and return them for processing.
+   * @param width Output width
+   * @return The thread roots
    */
-  public void dumpThreadRoots(int width, Stack<ObjectReference> roots) {
-    // Nothing to do for the default mutator
+  public java.util.Collection<ObjectReference> dumpThreadRoots(int width) {
+    return Collections.emptyList();
   }
 
   /**
@@ -216,24 +193,25 @@
    */
   public static void dumpHeap() {
     int width = Integer.toHexString(ObjectModel.nextObjectId()).length()+8;
-    Stack<ObjectReference> workStack = new Stack<ObjectReference>();
+    Deque<ObjectReference> workStack = new ArrayDeque<ObjectReference>();
     Set<ObjectReference> dumped = new HashSet<ObjectReference>();
-    for(Mutator m: mutators) {
+    for(Mutator m: Mutators.getAll()) {
       System.err.println("Mutator " + m.context.getId());
-      m.dumpThreadRoots(width, workStack);
+      workStack.addAll(m.dumpThreadRoots(width));
     }
     System.err.println("Heap (Depth First)");
     while(!workStack.isEmpty()) {
       ObjectReference object = workStack.pop();
       if (!dumped.contains(object)) {
         dumped.add(object);
-        ObjectModel.dumpLogicalObject(width, object, workStack);
+        workStack.addAll(ObjectModel.dumpLogicalObject(width, object));
       }
     }
   }
 
-/**
+  /**
    * A gc safe point for the mutator.
+   * @return Whether a GC has occurred
    */
   public boolean gcSafePoint() {
     if (Scheduler.gcTriggered()) {
@@ -244,20 +222,10 @@
   }
 
   /**
-   * An out of memory error originating from within MMTk.
-   *
-   * Tests that try to exercise out of memory conditions can catch this exception.
-   */
-  public static class OutOfMemory extends RuntimeException {
-    public static final long serialVersionUID = 1;
-  }
-
-  /**
    * Mark a mutator as no longer active. If a GC has been triggered we must ensure
    * that it proceeds before we deactivate.
    */
   public void end() {
-    check(expectedThrowable == null, "Expected exception of class " + expectedThrowable + " not found");
   }
 
   /**
@@ -277,7 +245,7 @@
 
   /**
    * Fail during execution.
-   * @param failMessage
+   * @param failMessage Message to write
    */
   public void fail(String failMessage) {
     check(false, failMessage);
@@ -292,6 +260,8 @@
 
   /**
    * Assert that the given condition is true or print the failure message.
+   * @param condition The condition to check
+   * @param failMessage The message to exit with
    */
   public void check(boolean condition, String failMessage) {
     if (!condition) throw new RuntimeException(failMessage);
@@ -347,6 +317,7 @@
    *
    * @param object The object to load the field of.
    * @param index The field index.
+   * @return The contents of the data field
    */
   public int loadDataField(ObjectReference object, int index) {
     int limit = ObjectModel.getDataCount(object);
@@ -365,6 +336,7 @@
    *
    * @param object The object to load the field of.
    * @param index The field index.
+   * @return The object reference
    */
   public ObjectReference loadReferenceField(ObjectReference object, int index) {
     int limit = ObjectModel.getRefs(object);
@@ -375,16 +347,19 @@
     Address referenceSlot = ObjectModel.getRefSlot(object, index);
     ObjectReference result;
     if (ActivePlan.constraints.needsReadBarrier()) {
-      result = context.readBarrier(object, referenceSlot, null, null, Plan.AASTORE_WRITE_BARRIER);
+      result = context.readBarrier(object, referenceSlot, null, null, Plan.GETFIELD_READ_BARRIER);
     } else {
       result = referenceSlot.loadObjectReference();
     }
+    assert result.toAddress().toWord().and(Word.fromIntZeroExtend(0x3)).EQ(Word.zero());
     Trace.trace(Item.LOAD,"[%s].object[%d] returned [%s]",ObjectModel.getString(object),index,result.toString());
     return result;
   }
 
   /**
    * Get the hash code for the given object.
+   * @param object The object
+   * @return The hash code
    */
   public int hash(ObjectReference object) {
     check(!object.isNull(), "Object can not be null");
@@ -415,8 +390,8 @@
 
   /**
    * Return a string identifying the allocation site of an object
-   * @param object
-   * @return
+   * @param object The object
+   * @return Where in the script it was allocated
    */
   public static String getSiteName(ObjectReference object) {
     return AllocationSite.getSite(ObjectModel.getSite(object)).toString();

Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java                        (rev 0)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -0,0 +1,61 @@
+/*
+ *  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.harness;
+
+import java.util.ArrayList;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * The collection of mutators
+ */
+public final class Mutators {
+
+  /** Registered mutators */
+  private static final ArrayList<Mutator> mutators = new ArrayList<Mutator>();
+
+  private static int nextId = 0;
+
+  /**
+   * Register a mutator, reserving a slot in the list
+   * @return The reserved slot number
+   */
+  static synchronized int registerMutator() {
+    return nextId++;
+  }
+
+  /**
+   * Complete the registration of a mutator, by inserting the initialized
+   * object in the allocated slot.
+   * @param id
+   * @param m
+   */
+  static synchronized void set(Mutator m) {
+    mutators.add(m);
+  }
+
+  /**
+   * Return the collection of valid mutators, as a blocking queue
+   * (so that it's synchronized - don't call 'take' on an empty queue ...)
+   * @return The non-null mutators
+   */
+  public static synchronized BlockingQueue<Mutator> getAll() {
+    BlockingQueue<Mutator> result = new ArrayBlockingQueue<Mutator>(mutators.size()+1);
+    for (Mutator m : mutators) {
+      if (m != null) {
+        result.add(m);
+      }
+    }
+    return result;
+  }
+}

Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java                        (rev 0)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -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.harness.exception;
+
+/**
+ * An out of memory error originating from within MMTk.
+ *
+ * Tests that try to exercise out of memory conditions can catch this exception.
+ */
+public class OutOfMemory extends RuntimeException {
+  private static final long serialVersionUID = 1;
+}

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -16,7 +16,6 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Random;
-import java.util.Stack;
 
 import org.mmtk.harness.Mutator;
 import org.mmtk.harness.lang.Trace.Item;
@@ -35,21 +34,29 @@
   /**
    * The stack
    */
-  private UnsyncStack<StackFrame> stack = new UnsyncStack<StackFrame>();
+  private final UnsyncStack<StackFrame> stack = new UnsyncStack<StackFrame>();
 
   /**
    * A source of random numbers (we have one per thread so that we can write
    * deterministic scripts).
    */
-  private Random rng = new Random();
+  private final Random rng = new Random();
 
+  /**
+   * The type of exception that is expected at the end of execution.
+   */
+  private Class<?> expectedThrowable;
+
+  /**
+   * Enable a CG on every safepoint
+   */
   public static void setGcEverySafepoint() {
     gcEverySafepoint = true;
   }
 
   /**
    * Enter a new procedure, pushing a new stack frame.
-   * @param frame
+   * @param frame Stack frame to push
    */
   public void push(StackFrame frame) {
     stack.push(frame);
@@ -90,6 +97,9 @@
     Trace.trace(Item.ROOTS, "Locals: %d", localCount);
   }
 
+  /**
+   * @see org.mmtk.harness.Mutator#getRoots()
+   */
   @Override
   public Collection<ObjectValue> getRoots() {
     List<ObjectValue> roots = new ArrayList<ObjectValue>();
@@ -103,17 +113,22 @@
    * Print the thread roots and add them to a stack for processing.
    */
   @Override
-  public void dumpThreadRoots(int width, Stack<ObjectReference> roots) {
+  public Collection<ObjectReference> dumpThreadRoots(int width) {
     int frameId = 0;
+    List<ObjectReference> roots = new ArrayList<ObjectReference>();
     for (StackFrame frame : stack) {
       System.err.printf("  Frame %5d [", frameId++);
-      frame.dumpRoots(width, roots);
+      roots.addAll(frame.dumpRoots(width));
       System.err.println(" ]");
     }
     System.err.println();
+    return roots;
   }
 
 
+  /**
+   * @see org.mmtk.harness.Mutator#gcSafePoint()
+   */
   @Override
   public boolean gcSafePoint() {
     if (gcEverySafepoint) {
@@ -123,6 +138,42 @@
   }
 
 
+  /**
+   * @see org.mmtk.harness.Mutator#end()
+   */
+  @Override
+  public void end() {
+    check(expectedThrowable == null, "Expected exception of class " + expectedThrowable + " not found");
+    super.end();
+  }
+
+  /**
+   * Set an expectation that the execution will exit with a throw of this exception.
+   * @param expectedThrowable The expected exception class
+   */
+  public void setExpectedThrowable(Class<?> expectedThrowable) {
+    Trace.trace(Item.EXCEPTION, "Setting expected exception %s", expectedThrowable.getCanonicalName());
+    this.expectedThrowable = expectedThrowable;
+  }
+
+  /**
+   * Mutator-specific handling of uncaught exceptions.  The scheduler calls this when
+   * it catches an unhandled exception.
+   * @param t Thread object
+   * @param e Exception
+   */
+  public void uncaughtException(Thread t, Throwable e) {
+    Trace.trace(Item.EXCEPTION, "Processing uncaught exception %s", e.getClass().getCanonicalName());
+    if (e.getClass() == expectedThrowable) {
+      System.err.println("Mutator " + context.getId() + " exiting due to expected exception of class " + expectedThrowable);
+      System.exit(0);
+    } else {
+      System.err.print("Mutator " + context.getId() + " caused unexpected exception: ");
+      e.printStackTrace();
+      System.exit(1);
+    }
+  }
+
   /*******************************************************************
    * Utility methods
    */
@@ -133,4 +184,5 @@
   public Random random() {
     return rng;
   }
+
 }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -12,8 +12,12 @@
  */
 package org.mmtk.harness.lang;
 
+import org.mmtk.harness.Harness;
 import org.mmtk.harness.Mutator;
 import org.mmtk.harness.lang.runtime.ObjectValue;
+import org.mmtk.harness.lang.runtime.PhantomReferenceValue;
+import org.mmtk.harness.lang.runtime.SoftReferenceValue;
+import org.mmtk.harness.lang.runtime.WeakReferenceValue;
 import org.mmtk.vm.Collection;
 import org.mmtk.vm.VM;
 
@@ -25,8 +29,7 @@
 public class Intrinsics {
   /**
    * Force GC
-   * @param env
-   * @return
+   * @param env Thread-local environment (language-dependent mutator context)
    */
   public static void gc(Env env) {
     VM.collection.triggerCollection(Collection.EXTERNAL_GC_TRIGGER);
@@ -34,8 +37,8 @@
 
   /**
    * Return the thread ID
-   * @param env
-   * @return
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @return the thread ID
    */
   public static int threadId(Env env) {
     return Mutator.current().getContext().getId();
@@ -43,18 +46,18 @@
 
   /**
    * Return the (identity) hash code
-   * @param env
-   * @param val
-   * @return
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param val The object to hash
+   * @return the (identity) hash code
    */
   public static int hash(Env env, ObjectValue val) {
     return env.hash(val.getObjectValue());
   }
 
   /**
-   * Set the random seed for this thread
-   * @param env
-   * @param seed
+   * Set the random number generator seed for this thread
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param seed Pseudo-random seed value
    */
   public static void setRandomSeed(Env env, int seed) {
     env.random().setSeed(seed);
@@ -62,10 +65,10 @@
 
   /**
    * A random integer in the closed interval [low..high].
-   * @param env
-   * @param low
-   * @param high
-   * @return
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param low Low bound (inclusive)
+   * @param high High bound (inclusive)
+   * @return A random integer in the closed interval [low..high]
    */
   public static int random(Env env, int low, int high) {
     return env.random().nextInt(high-low+1) + low;
@@ -73,6 +76,7 @@
 
   /**
    * Dump the heap
+   * @param env Thread-local environment (language-dependent mutator context)
    */
   public static void heapDump(Env env) {
     Mutator.dumpHeap();
@@ -80,9 +84,83 @@
 
   /**
    * Unit test method for the Intrinsic method
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param x An int
+   * @param y A boolean
+   * @param string A string
+   * @param val An object
+   * @return The string representation of <code>val</code>
    */
   public static String testMethod(Env env, int x, boolean y, String string, ObjectValue val) {
     return String.format("successfully called testMethod(%d,%b,%s,%s)", x,y,string,val.toString());
   }
 
+  /**
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param referent The object to weakly refer to
+   * @return The created weak reference value
+   *
+   */
+  public static WeakReferenceValue weakRef(Env env, ObjectValue referent) {
+    return new WeakReferenceValue(referent.getObjectValue());
+  }
+
+  /**
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param referent The object to weakly refer to
+   * @return The created weak reference value
+   *
+   */
+  public static SoftReferenceValue softRef(Env env, ObjectValue referent) {
+    return new SoftReferenceValue(referent.getObjectValue());
+  }
+
+  /**
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param referent The object to weakly refer to
+   * @return The created weak reference value
+   *
+   */
+  public static PhantomReferenceValue phantomRef(Env env, ObjectValue referent) {
+    return new PhantomReferenceValue(referent.getObjectValue());
+  }
+
+  /**
+   * Dereference a reference type
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param value The reference value
+   * @return The referent
+   */
+  public static ObjectValue getReferent(Env env, WeakReferenceValue value) {
+    return new ObjectValue(value.getObjectValue());
+  }
+  /**
+   * Dereference a reference type
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param value The reference value
+   * @return The referent
+   */
+  public static ObjectValue getReferent(Env env, SoftReferenceValue value) {
+    return new ObjectValue(value.getObjectValue());
+  }
+  /**
+   * Dereference a reference type
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param value The reference value
+   * @return The referent
+   */
+  public static ObjectValue getReferent(Env env, PhantomReferenceValue value) {
+    return new ObjectValue(value.getObjectValue());
+  }
+
+  /**
+   * Set a command-line option from within a script
+   * @param env Thread-local environment (language-dependent mutator context)
+   * @param option The command-line option
+   */
+  public static void setOption(Env env, String option) {
+    if (!Harness.options.process(option)) {
+      System.err.println("Error processing option "+option);
+    }
+  }
 }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -18,6 +18,7 @@
 import java.io.PrintStream;
 import java.util.Iterator;
 
+import org.mmtk.harness.Harness;
 import org.mmtk.harness.lang.ast.AST;
 import org.mmtk.harness.lang.ast.Alloc;
 import org.mmtk.harness.lang.ast.AllocUserType;
@@ -43,21 +44,37 @@
 import org.mmtk.harness.lang.ast.WhileStatement;
 import org.mmtk.harness.lang.parser.MethodTable;
 import org.mmtk.harness.lang.parser.Parser;
-import org.vmmagic.unboxed.ArchitecturalWord;
+import org.vmmagic.unboxed.harness.ArchitecturalWord;
 
+/**
+ * Format an AST back into Harness script-language code
+ *
+ * Implemented as a visitor over the AST
+ */
 public class PrettyPrinter extends Visitor {
 
   private final OutputFormatter fmt;
 
+  /**
+   * Create a pretty printer that sends output to an internal buffer
+   */
   public PrettyPrinter() {
-    fmt = new OutputFormatter();
+    this(new OutputFormatter());
   }
 
+  /**
+   * @param stream Where to send the output
+   */
   public PrettyPrinter(PrintStream stream) {
-    fmt = new OutputFormatter(stream);
+    this(new OutputFormatter(stream));
   }
 
-  private class OutputFormatter {
+
+  private PrettyPrinter(OutputFormatter outputFormatter) {
+    fmt = outputFormatter;
+  }
+
+  private static class OutputFormatter {
     private static final int INDENT = 2;
     private int indent = 0;
     private boolean pendingIndent = false;
@@ -103,6 +120,11 @@
   }
 
 
+  /**
+   * Visit a method definition
+   *
+   * @see org.mmtk.harness.lang.Visitor#visit(org.mmtk.harness.lang.ast.NormalMethod)
+   */
   @Override
   public Object visit(NormalMethod method) {
     fmt.out("%s %s(",method.getReturnType(),method.getName());
@@ -123,6 +145,11 @@
     return null;
   }
 
+  /**
+   * Visit a method-call
+   *
+   * @see org.mmtk.harness.lang.Visitor#visit(org.mmtk.harness.lang.ast.Call)
+   */
   @Override
   public Object visit(Call call) {
     fmt.out("%s(",call.getMethod().getName());
@@ -159,27 +186,22 @@
   public Object visit(IfStatement conditional) {
     String keyword = "if";
     Iterator<Expression> condIter = conditional.getConds().iterator();
-    Iterator<Statement> bodyIter = conditional.getStmts().iterator();
 
-    while (condIter.hasNext() && bodyIter.hasNext()) {
-      Expression cond = condIter.next();
-      Statement body = bodyIter.next();
-      fmt.out("%s (", keyword);
-      cond.accept(this);
-      fmt.out(") {"); fmt.newline();
+    for (Statement body : conditional.getStmts()) {
+      if (condIter.hasNext()) {
+        Expression cond = condIter.next();
+        fmt.out("%s (", keyword);
+        cond.accept(this);
+        fmt.out(") {"); fmt.newline();
+        keyword = "elif";
+      } else {
+        fmt.out("else {"); fmt.newline();
+      }
       fmt.increaseIndent();
       body.accept(this);
       fmt.decreaseIndent();
       fmt.out("} ");
-      keyword = "elif";
     }
-    if (bodyIter.hasNext()) {
-      fmt.out("else {"); fmt.newline();
-      fmt.increaseIndent();
-      bodyIter.next().accept(this);
-      fmt.decreaseIndent();
-      fmt.out("}");
-    }
     return null;
   }
 
@@ -376,7 +398,7 @@
   }
 
   public static void main(String[] args) {
-    ArchitecturalWord.init();
+    ArchitecturalWord.init(Harness.bits.getValue());
     try {
       MethodTable methods = new Parser(new BufferedInputStream(new FileInputStream(args[0]))).script();
       PrettyPrinter.printMethodTable(methods);

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -32,6 +32,7 @@
     /** Harness language semantic checker */                    CHECKER,
     /** Garbage collection */                                   COLLECT,
     /** P-code compiler */                                      COMPILER,
+    /** Expected exceptions */                                  EXCEPTION,
     /** Environment (stack frame) loads/stores */               ENV,
     /** P-code evaluation */                                    EVAL,
     /** Hashcode operations */                                  HASH,

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -23,21 +23,29 @@
 
   /**
    * Constructor
+   * @param t The Parser token corresponding to this entity
+   * @param name The exception name
    */
   public Expect(Token t, String name) {
     super(t);
     try {
-      expectedThrowable = Class.forName("org.mmtk.harness.Mutator$" + name);
+      expectedThrowable = Class.forName("org.mmtk.harness.exception." + name);
     } catch (ClassNotFoundException cnfe) {
       throw new RuntimeException(cnfe);
     }
   }
 
+  /**
+   * @see org.mmtk.harness.lang.ast.AbstractAST#accept(org.mmtk.harness.lang.Visitor)
+   */
   @Override
   public Object accept(Visitor v) {
     return v.visit(this);
   }
 
+  /**
+   * @return The expected exception class
+   */
   public Class<?> getExpected() {
     return expectedThrowable;
   }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -22,8 +22,11 @@
 import org.mmtk.harness.lang.runtime.BoolValue;
 import org.mmtk.harness.lang.runtime.IntValue;
 import org.mmtk.harness.lang.runtime.ObjectValue;
+import org.mmtk.harness.lang.runtime.PhantomReferenceValue;
+import org.mmtk.harness.lang.runtime.SoftReferenceValue;
 import org.mmtk.harness.lang.runtime.StringValue;
 import org.mmtk.harness.lang.runtime.Value;
+import org.mmtk.harness.lang.runtime.WeakReferenceValue;
 import org.mmtk.harness.lang.type.Type;
 
 /**
@@ -65,8 +68,14 @@
       return Type.BOOLEAN;
     } else if (externalType.equals(void.class)) {
       return Type.VOID;
+    } else if (externalType.equals(WeakReferenceValue.class)) {
+      return Type.WEAKREF;
+    } else if (externalType.equals(SoftReferenceValue.class)) {
+      return Type.SOFTREF;
+    } else if (externalType.equals(PhantomReferenceValue.class)) {
+      return Type.PHANTOMREF;
     }
-    return null;
+    throw new RuntimeException("Invalid return type for intrinsic method, "+externalType.getCanonicalName());
   }
 
   /**
@@ -147,6 +156,10 @@
 
   /**
    * Constructor
+   * @param name The name of the method in the scripting language
+   * @param className The class that implements the method
+   * @param methodName The name of the method in the implementing class
+   * @param params The types of the parameters
    */
   public IntrinsicMethod(String name, String className, String methodName, List<String> params) {
     this(name,className, methodName,classesForParams(params));
@@ -231,6 +244,8 @@
     } else if (obj instanceof Boolean) {
       assert returnType == Type.BOOLEAN : "mismatched return types";
       return BoolValue.valueOf(((Boolean)obj).booleanValue());
+    } else if (obj instanceof Value) {
+      return (Value)obj;
     }
     throw new RuntimeException("Can't unmarshall a "+obj.getClass().getCanonicalName());
   }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -14,6 +14,9 @@
 
 import org.mmtk.harness.lang.ast.IntrinsicMethod;
 import org.mmtk.harness.lang.runtime.ObjectValue;
+import org.mmtk.harness.lang.runtime.PhantomReferenceValue;
+import org.mmtk.harness.lang.runtime.SoftReferenceValue;
+import org.mmtk.harness.lang.runtime.WeakReferenceValue;
 import org.mmtk.harness.lang.type.Type;
 
 /**
@@ -27,7 +30,7 @@
    * The types - predeclared ones are passed to the constructor
    */
   public final TypeTable types = new TypeTable(Type.INT,Type.STRING,Type.BOOLEAN,
-      Type.OBJECT,Type.VOID);
+      Type.OBJECT,Type.VOID,Type.WEAKREF,Type.SOFTREF,Type.PHANTOMREF);
 
   private final String intrinsics = "org.mmtk.harness.lang.Intrinsics";
 
@@ -41,6 +44,20 @@
       new IntrinsicMethod("random",intrinsics,"random",
           new Class<?>[] { int.class, int.class }),
       new IntrinsicMethod("setSeed",intrinsics,"setRandomSeed", new Class<?>[] { int.class }),
-      new IntrinsicMethod("heapDump",intrinsics,"heapDump")
+      new IntrinsicMethod("heapDump",intrinsics,"heapDump"),
+      new IntrinsicMethod("weakRef",intrinsics,"weakRef",
+          new Class<?>[] { ObjectValue.class }),
+      new IntrinsicMethod("getWeakReferent",intrinsics,"getReferent",
+          new Class<?>[] { WeakReferenceValue.class }),
+      new IntrinsicMethod("softRef",intrinsics,"softRef",
+          new Class<?>[] { ObjectValue.class }),
+      new IntrinsicMethod("getSoftReferent",intrinsics,"getReferent",
+          new Class<?>[] { SoftReferenceValue.class }),
+      new IntrinsicMethod("phantomRef",intrinsics,"phantomRef",
+          new Class<?>[] { ObjectValue.class }),
+      new IntrinsicMethod("getPhantomReferent",intrinsics,"getReferent",
+          new Class<?>[] { PhantomReferenceValue.class }),
+      new IntrinsicMethod("setOption",intrinsics,"setOption", new Class[] { String.class })
+
   );
 }

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -13,7 +13,7 @@
 package org.mmtk.harness.lang.pcode;
 
 import org.mmtk.harness.Harness;
-import org.mmtk.harness.Mutator.OutOfMemory;
+import org.mmtk.harness.exception.OutOfMemory;
 import org.mmtk.harness.lang.Env;
 import org.mmtk.harness.lang.ast.AST;
 import org.mmtk.harness.lang.compiler.Register;

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -13,7 +13,7 @@
 package org.mmtk.harness.lang.pcode;
 
 import org.mmtk.harness.Harness;
-import org.mmtk.harness.Mutator.OutOfMemory;
+import org.mmtk.harness.exception.OutOfMemory;
 import org.mmtk.harness.lang.Env;
 import org.mmtk.harness.lang.ast.AST;
 import org.mmtk.harness.lang.compiler.Register;

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -29,7 +29,7 @@
   /**
    * The reference to the heap object
    *
-   * Not final because it may change during GC
+   * Not final because it may change during GC.
    */
   private ObjectReference value;
 

Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java                        (rev 0)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -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.harness.lang.runtime;
+
+import org.mmtk.harness.lang.type.Type;
+import org.mmtk.vm.ReferenceProcessor.Semantics;
+import org.vmmagic.unboxed.ObjectReference;
+
+/**
+ * A weak reference in the MMTk Harness language
+ */
+public class PhantomReferenceValue extends ReferenceValue {
+
+  /**
+   * The NULL weak reference
+   */
+  public static final ReferenceValue NULL = new PhantomReferenceValue(ObjectReference.nullReference());
+
+  /**
+   * @param ref The referent
+   */
+  public PhantomReferenceValue(ObjectReference ref) {
+    super(ref,Semantics.PHANTOM);
+  }
+
+  /**
+   * @see org.mmtk.harness.lang.runtime.Value#type()
+   */
+  @Override
+  public Type type() {
+    return Type.PHANTOMREF;
+  }
+}

Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java                        (rev 0)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -0,0 +1,84 @@
+/*
+ *  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.harness.lang.runtime;
+
+import org.mmtk.harness.lang.Trace;
+import org.mmtk.harness.lang.Trace.Item;
+import org.mmtk.harness.vm.ObjectModel;
+import org.mmtk.plan.TraceLocal;
+import org.mmtk.vm.ReferenceProcessor.Semantics;
+import org.vmmagic.unboxed.ObjectReference;
+
+/**
+ * Moral equivalent of java.lang.ref.Reference
+ */
+public abstract class ReferenceValue extends Value {
+
+  private ObjectReference ref;
+  private final Semantics semantics;
+  private boolean cleared = false;
+
+  protected ReferenceValue(ObjectReference ref, Semantics semantics) {
+    this.ref = ref;
+    this.semantics = semantics;
+  }
+
+  public void clear() {
+    Trace.trace(Item.REFERENCES, "Clearing reference %s", this);
+    cleared = true;
+  }
+
+  /**
+   * @see org.mmtk.harness.lang.runtime.Value#getObjectValue()
+   */
+  public ObjectReference getObjectValue() {
+    return cleared ? ObjectReference.nullReference() : ref;
+  }
+
+  /**
+   * @return The reference semantics
+   */
+  public Semantics getSemantics() {
+    return semantics;
+  }
+
+  /**
+   * @see org.mmtk.harness.lang.runtime.Value#equals(java.lang.Object)
+   */
+  @Override
+  public boolean equals(Object o) {
+    return this == o;
+  }
+
+  /**
+   * GC-time processing of the contained object
+   * @param trace The MMTk trace
+   */
+  public void traceObject(TraceLocal trace) {
+    String before = ObjectModel.getString(ref);
+    ref = trace.traceObject(ref, true);
+    Trace.trace(Item.REFERENCES, "Forwarded reference %x: %s reference (%s -> %s)",
+        System.identityHashCode(this), semantics, before, ObjectModel.getString(ref));
+  }
+
+  @Override
+  public int hashCode() {
+    return System.identityHashCode(this);
+  }
+
+  @Override
+  public String toString() {
+    return String.format("%x: %s reference (-> %s)", System.identityHashCode(this), semantics, ObjectModel.getString(ref));
+  }
+}
+

Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java                        (rev 0)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -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.harness.lang.runtime;
+
+import org.mmtk.harness.lang.type.Type;
+import org.mmtk.vm.ReferenceProcessor.Semantics;
+import org.vmmagic.unboxed.ObjectReference;
+
+/**
+ * A weak reference in the MMTk Harness language
+ */
+public class SoftReferenceValue extends ReferenceValue {
+
+  /**
+   * The NULL weak reference
+   */
+  public static final ReferenceValue NULL = new SoftReferenceValue(ObjectReference.nullReference());
+
+  /**
+   * @param ref The referent
+   */
+  public SoftReferenceValue(ObjectReference ref) {
+    super(ref,Semantics.SOFT);
+  }
+
+  /**
+   * @see org.mmtk.harness.lang.runtime.Value#type()
+   */
+  @Override
+  public Type type() {
+    return Type.SOFTREF;
+  }
+}

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -15,7 +15,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.Stack;
 
 import org.mmtk.harness.lang.Declaration;
 import org.mmtk.harness.lang.Trace;
@@ -23,6 +22,7 @@
 import org.mmtk.harness.lang.pcode.PseudoOp;
 import org.mmtk.harness.lang.type.Type;
 import org.mmtk.harness.vm.ObjectModel;
+import org.mmtk.harness.vm.ReferenceProcessor;
 import org.mmtk.plan.TraceLocal;
 import org.vmmagic.unboxed.ObjectReference;
 
@@ -53,7 +53,11 @@
   /** The slot for the return value of a method call */
   private int resultSlot = NO_SUCH_SLOT;
 
-  /** Create a stack frame, given a list of declarations and a quantity of temporaries */
+  /**
+   * Create a stack frame, given a list of declarations and a quantity of temporaries
+   * @param decls Variables declared in this stack frame
+   * @param nTemp Number of temporaries
+   */
   public StackFrame(List<Declaration> decls, int nTemp) {
     int size = decls.size()+nTemp;
     this.values = new Value[size];
@@ -70,6 +74,7 @@
 
   /**
    * Declare a variable in a given slot.  Only used when tracing.
+   * @param d The variable declaration
    */
   public void declare(Declaration d) {
     values[d.getSlot()] = d.getInitial();
@@ -78,6 +83,8 @@
 
   /**
    * Return the variable at the given slot in the current stack frame
+   * @param slot The stack frame slot
+   * @return The value in the slot
    */
   public Value get(int slot) {
     if (slot >= 0) {
@@ -88,6 +95,8 @@
 
   /**
    * Return the type of the variable at the given slot.
+   * @param slot The stack frame slot
+   * @return The type of the value in the slot
    */
   public Type getType(int slot) {
     return values[slot].type();
@@ -95,6 +104,8 @@
 
   /**
    * Assign a new value to the given slot
+   * @param slot Stack-frame slot to modify
+   * @param value New value
    */
   public void set(int slot, Value value) {
     assert value != null : "Unexpected null value";
@@ -134,6 +145,10 @@
         rootCount++;
       }
     }
+    Trace.trace(Item.REFERENCES, "Discovering references");
+    for (ReferenceValue reference : getReferences()) {
+      ReferenceProcessor.discover(reference);
+    }
     return rootCount;
   }
 
@@ -152,11 +167,26 @@
   }
 
   /**
+   *
+   * @return The root ReferenceValues for this stack frame
+   */
+  private Collection<ReferenceValue> getReferences() {
+    List<ReferenceValue> roots = new ArrayList<ReferenceValue>();
+    for (Value value : values) {
+      if (value != null && value instanceof ReferenceValue) {
+        roots.add((ReferenceValue)value);
+      }
+    }
+    return roots;
+  }
+
+  /**
    * Debug printing support: dump this stack frame and return roots.
    * @param width Output field width
-   * @param roots Root references
+   * @return The collection of roots in this frame
    */
-  public void dumpRoots(int width, Stack<ObjectReference> roots) {
+  public Collection<ObjectReference> dumpRoots(int width) {
+    List<ObjectReference> roots = new ArrayList<ObjectReference>();
     for (int i=0; i < values.length; i++) {
       Value value = values[i];
       String name;
@@ -168,45 +198,59 @@
       if (value != null && value instanceof ObjectValue) {
         ObjectReference ref = ((ObjectValue)value).getObjectValue();
         System.err.printf(" %s=%s", name, ObjectModel.formatObject(width, ref));
-        if (!ref.isNull()) roots.push(ref);
+        if (!ref.isNull()) roots.add(ref);
       }
     }
+    return roots;
   }
 
   /**
    * Save a program counter value
-   * @param pc
+   * @param pc The program counter
    */
   public void savePc(int pc) {
     savedPc = pc;
   }
 
-  /** Return the saved program counter */
+  /** @return the saved program counter */
   public int getSavedPc() {
     return savedPc;
   }
 
-  /** Save a method code array */
+  /**
+   * Save a method code array
+   * @param code The code array
+   */
   public void saveMethod(PseudoOp[] code) {
     savedCode = code;
   }
 
-  /** Return the saved code array */
+  /**
+   * @return the saved code array
+   */
   public PseudoOp[] getSavedMethod() {
     return savedCode;
   }
 
-  /** Set the slot for the return value */
+  /**
+   * Set the slot for the return value
+   * @param slot The slot in which to store the return value
+   */
   public void setResultSlot(int slot) {
     resultSlot = slot;
   }
 
-  /** Clear the return value slot */
+  /**
+   * Clear the return value slot
+   */
   public void clearResultSlot() {
     resultSlot = NO_SUCH_SLOT;
   }
 
-  /** Set the return value */
+  /**
+   * Set the return value
+   * @param returnValue The procedure return value
+   */
   public void setResult(Value returnValue) {
     assert resultSlot != NO_SUCH_SLOT : "Attempt to return a value to a method call with no result slot";
     set(resultSlot,returnValue);

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -54,7 +54,15 @@
     throw new RuntimeException("Invalid use of " + type() + " as a string");
   }
 
+  /**
+   * Marshall a value of this type into the equivalent Java value
+   * @param klass The target class
+   * @return
+   */
   public Object marshall(Class<?> klass) {
+    if (klass.isAssignableFrom(this.getClass())) {
+      return this;
+    }
     throw new RuntimeException(getClass()+" cannot be marshalled into a Java Object");
   }
 

Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java                        (rev 0)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -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.harness.lang.runtime;
+
+import org.mmtk.harness.lang.type.Type;
+import org.mmtk.vm.ReferenceProcessor.Semantics;
+import org.vmmagic.unboxed.ObjectReference;
+
+/**
+ * A weak reference in the MMTk Harness language
+ */
+public class WeakReferenceValue extends ReferenceValue {
+
+  /**
+   * The NULL weak reference
+   */
+  public static final ReferenceValue NULL = new WeakReferenceValue(ObjectReference.nullReference());
+
+  /**
+   * @param ref The referent
+   */
+  public WeakReferenceValue(ObjectReference ref) {
+    super(ref,Semantics.WEAK);
+  }
+
+  /**
+   * @see org.mmtk.harness.lang.runtime.Value#type()
+   */
+  @Override
+  public Type type() {
+    return Type.WEAKREF;
+  }
+}

Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java
===================================================================
--- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java 2009-07-21 04:20:25 UTC (rev 15731)
+++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java 2009-07-22 07:44:58 UTC (rev 15732)
@@ -12,8 +12,6 @@
  */
 package org.mmtk.harness.lang.type;
 
-import org.mmtk.harness.lang.runtime.Value;
-
 /**
  * Types in the scripting language.
  */
@@ -21,27 +19,41 @@
 
   private final String name;
 
+  /**
+   * @param name Name of this type
+   */
   public AbstractType(String name) {
     this.name = name;
   }
 
+  /**
+   * @see java.lang.Object#toString()
+   */
   @Override
   public String toString() {
     return getName();
   }
 
+  /**
+   * @see org.mmtk.harness.lang.type.Type#getName()
+   */
+  @Override
   public String getName() {
     return name;
   }
 
+  /**
+   * @see org.mmtk.harness.lang.type.Type#isObject()
+   */
   @Override
   public boolean isObject() {
     return false;
   }
 
+  /**
+   * @see org.mmtk.harness.lang.type.Type#isCompatibleWith(org.mmtk.harness.lang.type.Type)
+   */
   public boolean isCompatibleWith(Type rhs) {

@@ Diff output truncated at 100000 characters. @@

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

------------------------------------------------------------------------------
_______________________________________________
Jikesrvm-commits mailing list
Jikesrvm-commits@...
https://lists.sourceforge.net/lists/listinfo/jikesrvm-commits