Simplify the bitmap walker subroutines.

This change...

* Separates walking from sweeping.  Walking had been implemented by a
  sweeping with an empty mark bitmap argument.

* Localizes the finger machinations to scanBitmapCallback.  There is
  one use of the finger but all callbacks received the argument.

* Inlines a simplified bitmap walking routine operating a pointer at a
  time.  Only sweeping benefits from batching decoded addresses.

Change-Id: I87485ac58d3ecf07916f142534fe96f77e7ff227
diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c
index 50f6ed9..02955bc 100644
--- a/vm/alloc/Alloc.c
+++ b/vm/alloc/Alloc.c
@@ -306,18 +306,14 @@
     size_t count;
 } CountInstancesOfClassContext;
 
-static void countInstancesOfClassCallback(size_t numPtrs, void **ptrs,
-                                          const void *finger, void *arg)
+static void countInstancesOfClassCallback(void *ptr, void *arg)
 {
     CountInstancesOfClassContext *ctx = arg;
-    size_t i;
+    const Object *obj = ptr;
 
     assert(ctx != NULL);
-    for (i = 0; i < numPtrs; ++i) {
-        const Object *obj = ptrs[i];
-        if (obj->clazz == ctx->clazz) {
-            ctx->count += 1;
-        }
+    if (obj->clazz == ctx->clazz) {
+        ctx->count += 1;
     }
 }
 
diff --git a/vm/alloc/CardTable.c b/vm/alloc/CardTable.c
index 4645a4d..06512ed 100644
--- a/vm/alloc/CardTable.c
+++ b/vm/alloc/CardTable.c
@@ -244,24 +244,21 @@
  * table verification occurs weak references have yet to be blackened
  * and so their containing objects are permitted to be gray.
  */
-static void verifyCardTableCallback(size_t numPtrs, void **ptrs,
-                                    const void *finger, void *arg)
+static void verifyCardTableCallback(void *ptr, void *arg)
 {
-    size_t i;
+    Object *obj = ptr;
+    WhiteReferenceCounter ctx = { arg, 0 };
 
-    for (i = 0; i < numPtrs; ++i) {
-        Object *obj = ptrs[i];
-        WhiteReferenceCounter ctx = { arg, 0 };
-        dvmVisitObject(countWhiteReferenceVisitor, obj, &ctx);
-        if (ctx.whiteRefs == 0) {
-            continue;
-        } else if (isObjectDirty(obj)) {
-            continue;
-        } else if (isReferentUnmarked(obj, &ctx)) {
-            continue;
-        } else if (isWeakInternedString(obj)) {
-            continue;
-        }
+    dvmVisitObject(countWhiteReferenceVisitor, obj, &ctx);
+    if (ctx.whiteRefs == 0) {
+        return;
+    } else if (isObjectDirty(obj)) {
+        return;
+    } else if (isReferentUnmarked(obj, &ctx)) {
+        return;
+    } else if (isWeakInternedString(obj)) {
+        return;
+    } else {
         LOGE("Verify failed, object %p is gray", obj);
         dvmDumpObject(obj);
         dvmAbort();
diff --git a/vm/alloc/HeapBitmap.c b/vm/alloc/HeapBitmap.c
index 03269ba..08d5976 100644
--- a/vm/alloc/HeapBitmap.c
+++ b/vm/alloc/HeapBitmap.c
@@ -83,19 +83,11 @@
  * object pointers that correspond to garbage objects.  Call
  * <callback> zero or more times with lists of these object pointers.
  *
- * The <finger> argument to the callback indicates the next-highest
- * address that hasn't been visited yet; setting bits for objects whose
- * addresses are less than <finger> are not guaranteed to be seen by
- * the current walk.
- *
  * The callback is permitted to increase the bitmap's max; the walk
  * will use the updated max as a terminating condition,
- *
- * <finger> will be set to some value beyond the bitmap max when the
- * end of the bitmap is reached.
  */
 void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
-                            BitmapCallback *callback, void *callbackArg)
+                            BitmapSweepCallback *callback, void *callbackArg)
 {
     static const size_t kPointerBufSize = 128;
     void *pointerBuf[kPointerBufSize];
@@ -103,10 +95,10 @@
     size_t index;
     size_t i;
 
-#define FLUSH_POINTERBUF(finger_) \
+#define FLUSH_POINTERBUF() \
     do { \
         (*callback)(pb - pointerBuf, (void **)pointerBuf, \
-                    (void *)(finger_), callbackArg); \
+                    callbackArg); \
         pb = pointerBuf; \
     } while (false)
 
@@ -126,8 +118,7 @@
             /* Make sure that there are always enough slots available */ \
             /* for an entire word of 1s. */ \
             if (kPointerBufSize - (pb - pointerBuf) < HB_BITS_PER_WORD) { \
-                FLUSH_POINTERBUF(ptrBase + \
-                        HB_BITS_PER_WORD * HB_OBJECT_ALIGNMENT); \
+                FLUSH_POINTERBUF(); \
                 if (update_index_) { \
                     /* The callback may have caused hb_->max to grow. */ \
                     index = HB_OFFSET_TO_INDEX(hb_->max - hb_->base); \
@@ -202,31 +193,8 @@
     }
 
     if (pb > pointerBuf) {
-        /* Set the finger to the end of the heap (rather than
-         * longHb->max) so that the callback doesn't expect to be
-         * called again if it happens to change the current max.
-         */
-        uintptr_t finalFinger = longHb->base + HB_MAX_OFFSET(longHb);
-        FLUSH_POINTERBUF(finalFinger);
-        assert(finalFinger > longHb->max);
+        FLUSH_POINTERBUF();
     }
 #undef FLUSH_POINTERBUF
 #undef DECODE_BITS
 }
-
-/*
- * dvmHeapBitmapWalk is equivalent to dvmHeapBitmapSweepWalk with
- * nothing marked.
- */
-void dvmHeapBitmapWalk(const HeapBitmap *hb,
-                       BitmapCallback *callback, void *callbackArg)
-{
-    /* Create an empty bitmap with the same extent as <hb>.
-     * Don't actually allocate any memory.
-     */
-    HeapBitmap emptyHb = *hb;
-    emptyHb.max = emptyHb.base - 1; // empty
-    emptyHb.bits = (void *)1;       // non-NULL but intentionally bad
-
-    dvmHeapBitmapSweepWalk(hb, &emptyHb, callback, callbackArg);
-}
diff --git a/vm/alloc/HeapBitmap.h b/vm/alloc/HeapBitmap.h
index 5810d9a..b0dea99 100644
--- a/vm/alloc/HeapBitmap.h
+++ b/vm/alloc/HeapBitmap.h
@@ -18,6 +18,7 @@
 
 #include <limits.h>
 #include <stdint.h>
+#include "clz.h"
 
 #define HB_OBJECT_ALIGNMENT 8
 #define HB_BITS_PER_WORD (sizeof(unsigned long) * CHAR_BIT)
@@ -79,8 +80,8 @@
     uintptr_t max;
 } HeapBitmap;
 
-typedef void BitmapCallback(size_t numPtrs, void **ptrs,
-                            const void *finger, void *arg);
+typedef void BitmapCallback(void *addr, void *arg);
+typedef void BitmapSweepCallback(size_t numPtrs, void **ptrs, void *arg);
 
 /*
  * Initialize a HeapBitmap so that it points to a bitmap large
@@ -118,14 +119,38 @@
  * end of the bitmap is reached.
  */
 void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
-                            BitmapCallback *callback, void *callbackArg);
+                            BitmapSweepCallback *callback, void *callbackArg);
 
 /*
  * Similar to dvmHeapBitmapSweepWalk(), but visit the set bits
  * in a single bitmap.
  */
-void dvmHeapBitmapWalk(const HeapBitmap *hb,
-                       BitmapCallback *callback, void *callbackArg);
+HB_INLINE_PROTO(
+    void
+    dvmHeapBitmapWalk(const HeapBitmap *bitmap,
+                      BitmapCallback *callback, void *arg)
+)
+{
+    assert(bitmap != NULL);
+    assert(bitmap->bits != NULL);
+    assert(callback != NULL);
+    uintptr_t end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
+    uintptr_t i;
+    for (i = 0; i <= end; ++i) {
+        unsigned long word = bitmap->bits[i];
+        if (UNLIKELY(word != 0)) {
+            unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
+            uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
+            while (word != 0) {
+                const int shift = CLZ(word);
+                word &= ~(highBit >> shift);
+                void *addr = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
+                (*callback)(addr, arg);
+                end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
+            }
+        }
+    }
+}
 
 /*
  * Return true iff <obj> is within the range of pointers that this
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index eaf73c7..095e2c7 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -41,8 +41,8 @@
 
 #define LOG_SCAN(...)   LOGV_GC("SCAN: " __VA_ARGS__)
 
-#define ALIGN_UP_TO_PAGE_SIZE(p) \
-    (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
+#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
+#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
 
 /* Do not cast the result of this to a boolean; the only set bit
  * may be > 1<<8.
@@ -653,25 +653,18 @@
     }
 }
 
-#ifndef NDEBUG
-static uintptr_t gLastFinger = 0;
-#endif
-
-static void scanBitmapCallback(size_t numPtrs, void **ptrs,
-                               const void *finger, void *arg)
+/*
+ * Callback for scanning each object in the bitmap.  The finger is set
+ * to the address corresponding to the lowest address in the next word
+ * of bits in the bitmap.
+ */
+static void scanBitmapCallback(void *addr, void *arg)
 {
     GcMarkContext *ctx = arg;
-    size_t i;
-
-#ifndef NDEBUG
-    assert((uintptr_t)finger >= gLastFinger);
-    gLastFinger = (uintptr_t)finger;
-#endif
-
-    ctx->finger = finger;
-    for (i = 0; i < numPtrs; i++) {
-        scanObject(*ptrs++, ctx);
-    }
+    void *nextAddr = (void *)((size_t)addr + 1);
+    size_t finger = ALIGN_UP(nextAddr, HB_BITS_PER_WORD * HB_OBJECT_ALIGNMENT);
+    ctx->finger = (void *)finger;
+    scanObject(addr, ctx);
 }
 
 /* Given bitmaps with the root set marked, find and mark all
@@ -687,9 +680,6 @@
     /* The bitmaps currently have bits set for the root set.
      * Walk across the bitmaps and scan each object.
      */
-#ifndef NDEBUG
-    gLastFinger = 0;
-#endif
     dvmHeapBitmapWalk(ctx->bitmap, scanBitmapCallback, ctx);
 
     /* We've walked the mark bitmaps.  Scan anything that's
@@ -963,8 +953,7 @@
     bool isConcurrent;
 } SweepContext;
 
-static void sweepBitmapCallback(size_t numPtrs, void **ptrs,
-                                const void *finger, void *arg)
+static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
 {
     SweepContext *ctx = arg;
 
diff --git a/vm/alloc/Verify.c b/vm/alloc/Verify.c
index 47d28d8..c4222ad 100644
--- a/vm/alloc/Verify.c
+++ b/vm/alloc/Verify.c
@@ -56,14 +56,9 @@
 /*
  * Helper function to call dvmVerifyObject from a bitmap walker.
  */
-static void verifyBitmapCallback(size_t numPtrs, void **ptrs,
-                                 const void *finger, void *arg)
+static void verifyBitmapCallback(void *ptrs, void *arg)
 {
-    size_t i;
-
-    for (i = 0; i < numPtrs; i++) {
-        dvmVerifyObject(ptrs[i]);
-    }
+    dvmVerifyObject(ptrs);
 }
 
 /*