Update the card table scanning for header-only card marks.

Previously, the card table accessors assumed that objects had either
their header marked or would be marked exactly.  As such, after
reckoning a marked card the scan would back up until it found an
object header and then move forward blackening each object within the
address range of the marked card.

Following a recent change we exclusively mark headers.  The scan only
has to move forward until the end of a card.  This saves scanning time
as dlmalloc's binning may leave large segments of the heap unused.  It
is not uncommon for hundreds of cards to be spanned when backing up to
the first live object below a marked card.

In addition, this change fixes the card table verifier to search the
mark stack for gray objects.  It is permissible for roots to point to
white objects on unmarked cards.  This was incorrectly treated as an
error.

Change-Id: Ia6b6ee2012e381d644b8b3f38b39d746749ea47a
diff --git a/vm/alloc/CardTable.c b/vm/alloc/CardTable.c
index 06512ed..cc344a8 100644
--- a/vm/alloc/CardTable.c
+++ b/vm/alloc/CardTable.c
@@ -138,42 +138,14 @@
 }
 
 /*
- * Handles the complexity of object arrays for isObjectDirty.  Array
- * objects are exactly marked so all spanned cards are examined.
- */
-static bool isObjectArrayDirty(const Object *obj)
-{
-    u1 *ptr, *limit;
-    size_t size;
-
-    assert(obj != NULL);
-    assert(dvmIsValidObject(obj));
-    assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY));
-    size = dvmArrayObjectSize((const ArrayObject *)obj);
-    ptr = dvmCardFromAddr(obj);
-    limit = dvmCardFromAddr((u1 *)obj + size - 1) + 1;
-    assert(ptr != limit);
-    for (; ptr != limit; ++ptr) {
-        if (*ptr == GC_CARD_DIRTY) {
-            return true;
-        }
-    }
-    return false;
-}
-
-/*
  * Returns true if the object is on a dirty card.
  */
 static bool isObjectDirty(const Object *obj)
 {
     assert(obj != NULL);
     assert(dvmIsValidObject(obj));
-    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
-        return isObjectArrayDirty(obj);
-   } else {
-        u1 *card = dvmCardFromAddr(obj);
-        return *card == GC_CARD_DIRTY;
-    }
+    u1 *card = dvmCardFromAddr(obj);
+    return *card == GC_CARD_DIRTY;
 }
 
 /*
@@ -239,10 +211,29 @@
 }
 
 /*
- * Callback applied to marked objects.  If the object is found to be
- * gray a message is written to the log.  By virtue of where the card
- * table verification occurs weak references have yet to be blackened
- * and so their containing objects are permitted to be gray.
+ * Returns true if the given object has been pushed on the mark stack
+ * by root marking.
+ */
+static bool isPushedOnMarkStack(const Object *obj)
+{
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+    const Object **ptr;
+
+    for (ptr = ctx->stack.top; ptr != ctx->stack.base; ++ptr) {
+        if (*ptr == obj) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Callback applied to marked objects.  If the object is gray and on
+ * an unmarked card an error is logged and the VM is aborted.  Card
+ * table verification occurs between root marking and weak reference
+ * processing.  We treat objects marked from the roots and weak
+ * references specially as it is permissible for these objects to be
+ * gray and on an unmarked card.
  */
 static void verifyCardTableCallback(void *ptr, void *arg)
 {
@@ -258,8 +249,10 @@
         return;
     } else if (isWeakInternedString(obj)) {
         return;
+    } else if (isPushedOnMarkStack(obj)) {
+        return;
     } else {
-        LOGE("Verify failed, object %p is gray", obj);
+        LOGE("Verify failed, object %p is gray and on an unmarked card", obj);
         dvmDumpObject(obj);
         dvmAbort();
     }
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 12dea2d..bde1b49 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -558,34 +558,6 @@
 }
 
 /*
- * Scans backward to the header of a marked object that spans the
- * given address.  Returns NULL if there is no spanning marked object.
- */
-static Object *previousGrayObject(u1 *start, HeapBitmap *markBits,
-                                  HeapBitmap *liveBits)
-{
-    u1 *end = (u1 *)markBits->base;
-    u1 *ptr;
-
-    assert(start >= end);
-    for (ptr = start; ptr >= end; ptr -= HB_OBJECT_ALIGNMENT) {
-        if (dvmHeapBitmapIsObjectBitSet(liveBits, ptr)) {
-            break;
-        }
-    }
-    if (ptr < end || !dvmHeapBitmapIsObjectBitSet(markBits, ptr)) {
-         return NULL;
-    } else {
-        Object *obj = (Object *)ptr;
-        size_t size = objectSize(obj);
-        if (ptr + size < start) {
-            return NULL;
-        }
-        return obj;
-    }
-}
-
-/*
  * Scans forward to the header of the next marked object between start
  * and limit.  Returns NULL if no marked objects are in that region.
  */
@@ -627,16 +599,6 @@
              */
             u1 *addr = dvmAddrFromCard(card);
             /*
-             * If the last object on the previous card terminates on
-             * the current card it is gray and must be scanned.
-             */
-            if (!dvmHeapBitmapIsObjectBitSet(liveBits, addr)) {
-                Object *prev = previousGrayObject(addr, markBits, liveBits);
-                if (prev != NULL) {
-                    scanObject(prev, ctx);
-                }
-            }
-            /*
              * Scan through all black objects that start on the
              * current card.
              */
@@ -647,7 +609,7 @@
                 if (obj == NULL)
                     break;
                 scanObject(obj, ctx);
-                next = (u1*)obj + HB_OBJECT_ALIGNMENT;
+                next = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
             }
         }
     }