Index: MMTk/src/org/mmtk/utility/TraceGenerator.java
===================================================================
--- MMTk/src/org/mmtk/utility/TraceGenerator.java	(revision 6)
+++ MMTk/src/org/mmtk/utility/TraceGenerator.java	(revision 7)
@@ -375,7 +375,7 @@
       /* If we should add the object for further processing. */
       if (!getTraceLocal().isReachable(ref)) {
         VM.traceInterface.setDeathTime(ref, agePropagate);
-        worklist.push(ref);
+        worklist.pushTail(ref);
       } else {
         VM.traceInterface.setDeathTime(getTraceLocal().getForwardedReference(ref), agePropagate);
       }
@@ -392,7 +392,7 @@
        /* The latest time an object can die. */
        agePropagate = Word.max();
        /* Process through the entire buffer. */
-       ObjectReference ref = worklist.pop();
+       ObjectReference ref = worklist.popTail();
        while (!ref.isNull()) {
          Word currentAge = VM.traceInterface.getDeathTime(ref);
          /* This is a cheap and simple test to process objects only once. */
@@ -403,7 +403,7 @@
            Scan.scanObject(getTraceLocal(), ref);
          }
          /* Get the next object to process */
-         ref = worklist.pop();
+         ref = worklist.popTail();
        }
      }
   }
Index: MMTk/src/org/mmtk/utility/deque/LocalDeque.java
===================================================================
--- MMTk/src/org/mmtk/utility/deque/LocalDeque.java	(revision 6)
+++ MMTk/src/org/mmtk/utility/deque/LocalDeque.java	(revision 7)
@@ -95,7 +95,46 @@
     head = head.plus(BYTES_IN_ADDRESS);
     // if (VM_Interface.VerifyAssertions) enqueued++;
   }
+  
+  /**
+   * Check whether there are sufficient entries in the tail buffer for
+   * a pending dequeue from the tail of the deque.  If there are not sufficient 
+   * entries, acquire a new buffer from the shared deque. Return true if 
+   * there are enough entries for the pending pop, false if the deque has 
+   * been exhausted.
+   *
+   * @param arity The arity of the values stored in this deque: there
+   * must be at least this many values available.
+   * @return True if there are enough entries for the pending pop,
+   * false if the queue has been exhausted.
+   */
+  @Inline
+  protected final boolean checkTailDequeue(int arity) {
+    if (tail.EQ(tailBufferEnd)) {
+      return tailDequeueUnderflow(arity);
+    } else {
+      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bufferOffset(tail).sLT(bufferSentinel(queue.getArity())));
+      return true;
+    }
+  }
 
+  /**
+   * Dequeue an address value from the tail buffer.  This is <i>unchecked</i>.  
+   * The caller must first call <code>checkTailDequeue()</code> to ensure 
+   * the buffer has sufficient values.
+   *
+   * @return the next address in the buffer
+   */
+  @Inline
+  protected final Address uncheckedTailDequeue() {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tail.LT(tailBufferEnd));
+    Address retVal;
+    retVal = tail.loadAddress();
+    tail = tail.plus(BYTES_IN_ADDRESS);
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!retVal.toObjectReference().isNull());
+    return retVal;
+  }
+
   /****************************************************************************
    *
    * Private instance methods and fields
@@ -115,7 +154,32 @@
     head = queue.alloc();
     Plan.checkForAsyncCollection(); // possible side-effect of alloc()
   }
+  
+  /**
+   * There are not sufficient entries in the tail buffer for a pending
+   * pop.  Acquire a new tail buffer.  If the shared deque has no
+   * buffers available, consume the head if necessary.  Return false
+   * if entries cannot be acquired.
+   *
+   * @param arity The arity of this buffer (used for sanity test only).
+   * @return True if the buffer has been successfully replenished.
+   */
+  @NoInline
+  private final boolean tailDequeueUnderflow(int arity) {
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
+    do {
+      if (tail.NE(Deque.TAIL_INITIAL_VALUE))
+        queue.free(bufferStart(tail));
+      tailBufferEnd = queue.dequeue(arity, true);
+      tail = bufferStart(tailBufferEnd);
+    } while (tail.NE(Deque.TAIL_INITIAL_VALUE) && tail.EQ(tailBufferEnd));
 
+    if (tail.EQ(Deque.TAIL_INITIAL_VALUE))
+      return !tailStarved(arity);
+
+    return true;
+  }
+
   /**
    * Close the head buffer and enqueue it at the front of the
    * shared buffer deque.
@@ -140,7 +204,7 @@
   @SuppressWarnings("unused")
   private boolean tailStarved(int arity) {
     if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
-    // entries in tail, so consume tail
+    // entries in head, so consume head
     if (!bufferOffset(head).isZero()) {
       tailBufferEnd = head;
       tail = bufferStart(tailBufferEnd);
Index: MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java
===================================================================
--- MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java	(revision 6)
+++ MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java	(revision 7)
@@ -52,7 +52,7 @@
   }
 
   /**
-   * Push an address onto the address stack.
+   * Push an address onto the head of the address stack.
    *
    * @param object the object to be pushed onto the object queue
    */
@@ -63,10 +63,23 @@
     checkHeadInsert(1);
     uncheckedHeadInsert(addr);
   }
+  
+  /**
+   * Push an address onto the tail of the address stack.
+   * 
+   * @param object the object to be pushed onto the object queue
+   */
+  @Inline
+  public final void pushTail(ObjectReference object) {
+    Address addr = object.toAddress();
+    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr.isZero());
+    checkTailInsert(1);
+    uncheckedTailInsert(addr);
+  }
 
   /**
-   * Pop an address from the address stack, return zero if the stack
-   * is empty.
+   * Pop an address from the head of the address stack, return zero if 
+   * the stack is empty.
    *
    * @return The next address in the address stack, or zero if the
    * stack is empty
@@ -79,6 +92,22 @@
       return ObjectReference.nullReference();
     }
   }
+  
+  /**
+   * Pop an address from the tail of the address stack, return zero 
+   * if the stack is empty.
+   * 
+   * @return The next address in the address stack, or zero if the
+   * stack is empty
+   */
+  @Inline
+  public final ObjectReference popTail() {
+    if (checkTailDequeue(1)) {
+      return uncheckedTailDequeue().toObjectReference();
+    } else {
+      return ObjectReference.nullReference();
+    }
+  }
 
   /**
    * Check if the (local and shared) stacks are empty.
Index: MMTk/src/org/mmtk/utility/deque/SharedDeque.java
===================================================================
--- MMTk/src/org/mmtk/utility/deque/SharedDeque.java	(revision 6)
+++ MMTk/src/org/mmtk/utility/deque/SharedDeque.java	(revision 7)
@@ -227,7 +227,7 @@
   /**
    * Set the "prev" pointer in a buffer forming the linked buffer chain.
    *
-   * @param buf The buffer whose next field is to be set.
+   * @param buf The buffer whose prev field is to be set.
    * @param prev The reference to which prev should point.
    */
   private void setPrev(Address buf, Address prev) {
@@ -235,10 +235,10 @@
   }
 
   /**
-   * Get the "next" pointer in a buffer forming the linked buffer chain.
+   * Get the "prev" pointer in a buffer forming the linked buffer chain.
    *
-   * @param buf The buffer whose next field is to be returned.
-   * @return The next field for this buffer.
+   * @param buf The buffer whose prev field is to be returned.
+   * @return The prev field for this buffer.
    */
   protected final Address getPrev(Address buf) {
     return buf.loadAddress(PREV_OFFSET);
