diff --git a/MMTk/src/org/mmtk/utility/TraceGenerator.java b/MMTk/src/org/mmtk/utility/TraceGenerator.java
--- a/MMTk/src/org/mmtk/utility/TraceGenerator.java
+++ b/MMTk/src/org/mmtk/utility/TraceGenerator.java
@@ -370,7 +370,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);
       }
@@ -387,7 +387,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. */
@@ -398,7 +398,7 @@
            VM.scanning.scanObject(getTraceLocal(), ref);
          }
          /* Get the next object to process */
-         ref = worklist.pop();
+         ref = worklist.popTail();
        }
      }
   }
diff --git a/MMTk/src/org/mmtk/utility/deque/LocalDeque.java b/MMTk/src/org/mmtk/utility/deque/LocalDeque.java
--- a/MMTk/src/org/mmtk/utility/deque/LocalDeque.java
+++ b/MMTk/src/org/mmtk/utility/deque/LocalDeque.java
@@ -95,6 +95,47 @@
     // if (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,6 +156,32 @@
   }
 
   /**
+   * 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 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.
    *
@@ -135,7 +202,6 @@
    * @param arity The arity of this buffer
    * @return True if the consumer has eaten all of the entries
    */
-  @SuppressWarnings("unused")
   private boolean tailStarved(int arity) {
     if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(arity == queue.getArity());
     // entries in tail, so consume tail
diff --git a/MMTk/src/org/mmtk/utility/deque/SharedDeque.java b/MMTk/src/org/mmtk/utility/deque/SharedDeque.java
--- a/MMTk/src/org/mmtk/utility/deque/SharedDeque.java
+++ b/MMTk/src/org/mmtk/utility/deque/SharedDeque.java
@@ -388,7 +388,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) {
@@ -396,10 +396,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);
diff --git a/MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java b/MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java
--- a/MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java
+++ b/MMTk/src/org/mmtk/utility/deque/SortTODObjectReferenceStack.java
@@ -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
    */
@@ -65,8 +65,21 @@
   }
 
   /**
-   * Pop an address from the address stack, return zero if the stack
-   * is empty.
+   * 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 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
@@ -81,6 +94,22 @@
   }
 
   /**
+   * 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.
    *
    * @return True if there are no more entries on the local & shared stack,
