Drive the root verification by a root visitor.

The change separates out the traversal of the roots from the
verification of references.  As of this change, the logic benhind
traversing is wholly owned by the visitor.

Change-Id: Idc07755436f5cd18ba010ec24d12b6e22000c56e
diff --git a/vm/alloc/Verify.c b/vm/alloc/Verify.c
index 2afb955..f71b0f1 100644
--- a/vm/alloc/Verify.c
+++ b/vm/alloc/Verify.c
@@ -16,23 +16,19 @@
 
 #include "Dalvik.h"
 #include "alloc/HeapBitmap.h"
-#include "alloc/HeapSource.h"
 #include "alloc/Verify.h"
 #include "alloc/Visit.h"
 
 /*
- * Helper routine for verifyRefernce that masks low-tag bits before
- * applying verification checks.  TODO: eliminate the use of low-tag
- * bits and move this code into verifyReference.
+ * Checks that the given reference points to a valid object.
  */
-static void verifyReferenceUnmask(const void *addr, uintptr_t mask)
+static void verifyReference(void *addr, void *arg)
 {
     const Object *obj;
-    uintptr_t tmp;
     bool isValid;
 
-    tmp = (uintptr_t)*(const Object **)addr;
-    obj = (const Object *)(tmp & ~mask);
+    assert(addr != NULL);
+    obj = *(const Object **)addr;
     if (obj == NULL) {
         isValid = true;
     } else {
@@ -44,22 +40,13 @@
     }
 }
 
-/*
- * Assertion that the given reference points to a valid object.
- */
-static void verifyReference(const void *addr)
-{
-    verifyReferenceUnmask(addr, 0);
-}
-
 static void visitorCallback(void *addr, void *arg)
 {
-    verifyReference(addr);
+    verifyReference(addr, arg);
 }
 
 /*
- * Verifies an object reference.  Determines the type of the reference
- * and dispatches to a specialized verification routine.
+ * Verifies an object reference.
  */
 void dvmVerifyObject(const Object *obj)
 {
@@ -75,7 +62,7 @@
     size_t i;
 
     for (i = 0; i < numPtrs; i++) {
-        dvmVerifyObject(*ptrs++);
+        dvmVerifyObject(ptrs[i]);
     }
     return true;
 }
@@ -91,177 +78,9 @@
 }
 
 /*
- * Applies a verification function to all present values in the hash table.
- */
-static void verifyHashTable(HashTable *table,
-                            void (*callback)(const void *arg))
-{
-    int i;
-
-    assert(table != NULL);
-    assert(callback != NULL);
-    dvmHashTableLock(table);
-    for (i = 0; i < table->tableSize; ++i) {
-        const HashEntry *entry = &table->pEntries[i];
-        if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
-            (*callback)(&entry->data);
-        }
-    }
-    dvmHashTableUnlock(table);
-}
-
-/*
- * Applies the verify routine to the given object.
- */
-static void verifyStringReference(const void *arg)
-{
-    assert(arg != NULL);
-    verifyReferenceUnmask(arg, 0x1);
-}
-
-/*
- * Verifies all entries in the reference table.
- */
-static void verifyReferenceTable(const ReferenceTable *table)
-{
-    Object **entry;
-
-    assert(table != NULL);
-    for (entry = table->table; entry < table->nextEntry; ++entry) {
-        assert(entry != NULL);
-        verifyReference(entry);
-    }
-}
-
-/*
- * Verifies a large heap reference table.  These objects are list
- * heads.  As such, it is valid for table to be NULL.
- */
-static void verifyLargeHeapRefTable(const LargeHeapRefTable *table)
-{
-    for (; table != NULL; table = table->next) {
-        verifyReferenceTable(&table->refs);
-    }
-}
-
-/*
- * Verifies all stack slots. TODO: verify native methods.
- */
-static void verifyThreadStack(const Thread *thread)
-{
-    const StackSaveArea *saveArea;
-    const u4 *framePtr;
-
-    assert(thread != NULL);
-    framePtr = (const u4 *)thread->curFrame;
-    for (; framePtr != NULL; framePtr = saveArea->prevFrame) {
-        Method *method;
-        saveArea = SAVEAREA_FROM_FP(framePtr);
-        method = (Method *)saveArea->method;
-        if (method != NULL && !dvmIsNativeMethod(method)) {
-            const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
-            const u1* regVector = NULL;
-            int i;
-
-            if (pMap != NULL) {
-                /* found map, get registers for this address */
-                int addr = saveArea->xtra.currentPc - method->insns;
-                regVector = dvmRegisterMapGetLine(pMap, addr);
-            }
-            if (regVector == NULL) {
-                /*
-                 * Either there was no register map or there is no
-                 * info for the current PC.  Perform a conservative
-                 * scan.
-                 */
-                for (i = 0; i < method->registersSize; ++i) {
-                    if (dvmIsValidObject((Object *)framePtr[i])) {
-                        verifyReference(&framePtr[i]);
-                    }
-                }
-            } else {
-                /*
-                 * Precise scan.  v0 is at the lowest address on the
-                 * interpreted stack, and is the first bit in the
-                 * register vector, so we can walk through the
-                 * register map and memory in the same direction.
-                 *
-                 * A '1' bit indicates a live reference.
-                 */
-                u2 bits = 1 << 1;
-                for (i = 0; i < method->registersSize; ++i) {
-                    bits >>= 1;
-                    if (bits == 1) {
-                        /* set bit 9 so we can tell when we're empty */
-                        bits = *regVector++ | 0x0100;
-                    }
-                    if ((bits & 0x1) != 0) {
-                        /*
-                         * Register is marked as live, it's a valid root.
-                         */
-                        verifyReference(&framePtr[i]);
-                    }
-                }
-                dvmReleaseRegisterMapLine(pMap, regVector);
-            }
-        }
-        /*
-         * Don't fall into an infinite loop if things get corrupted.
-         */
-        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
-               saveArea->prevFrame == NULL);
-    }
-}
-
-/*
- * Verifies all roots associated with a thread.
- */
-static void verifyThread(const Thread *thread)
-{
-    assert(thread != NULL);
-    assert(thread->status != THREAD_RUNNING ||
-           thread->isSuspended ||
-           thread == dvmThreadSelf());
-    LOGV("Entering verifyThread(thread=%p)", thread);
-    verifyReference(&thread->threadObj);
-    verifyReference(&thread->exception);
-    verifyReferenceTable(&thread->internalLocalRefTable);
-    verifyReferenceTable(&thread->jniLocalRefTable);
-    if (thread->jniMonitorRefTable.table) {
-        verifyReferenceTable(&thread->jniMonitorRefTable);
-    }
-    verifyThreadStack(thread);
-    LOGV("Exiting verifyThread(thread=%p)", thread);
-}
-
-/*
- * Verifies all threads on the thread list.
- */
-static void verifyThreads(void)
-{
-    Thread *thread;
-
-    dvmLockThreadList(dvmThreadSelf());
-    thread = gDvm.threadList;
-    while (thread) {
-        verifyThread(thread);
-        thread = thread->next;
-    }
-    dvmUnlockThreadList();
-}
-
-/*
- * Verifies roots.  TODO: verify all roots.
+ * Verifies references in the roots.
  */
 void dvmVerifyRoots(void)
 {
-    verifyHashTable(gDvm.loadedClasses, verifyReference);
-    verifyHashTable(gDvm.dbgRegistry, verifyReference);
-    verifyHashTable(gDvm.internedStrings, verifyStringReference);
-    verifyReferenceTable(&gDvm.jniGlobalRefTable);
-    verifyReferenceTable(&gDvm.jniPinRefTable);
-    verifyLargeHeapRefTable(gDvm.gcHeap->referenceOperations);
-    verifyLargeHeapRefTable(gDvm.gcHeap->pendingFinalizationRefs);
-    verifyThreads();
-    /* TODO: verify cached global references. */
+    dvmVisitRoots(verifyReference, NULL);
 }
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c
index 546a6a8..0124e29 100644
--- a/vm/alloc/Visit.c
+++ b/vm/alloc/Visit.c
@@ -16,6 +16,7 @@
 
 #include "Dalvik.h"
 #include "alloc/clz.h"
+#include "alloc/HeapInternal.h"
 #include "alloc/Visit.h"
 #include "alloc/VisitInlines.h"
 
@@ -29,3 +30,176 @@
     assert(obj->clazz != NULL);
     visitObject(visitor, obj, arg);
 }
+
+/*
+ * Applies a verification function to all present values in the hash table.
+ */
+static void visitHashTable(Visitor *visitor, HashTable *table, void *arg)
+{
+    int i;
+
+    assert(visitor != NULL);
+    assert(table != NULL);
+    dvmHashTableLock(table);
+    for (i = 0; i < table->tableSize; ++i) {
+        HashEntry *entry = &table->pEntries[i];
+        if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
+            (*visitor)(&entry->data, arg);
+        }
+    }
+    dvmHashTableUnlock(table);
+}
+
+/*
+ * Visits all entries in the reference table.
+ */
+static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table,
+                                void *arg)
+{
+    Object **entry;
+
+    assert(visitor != NULL);
+    assert(table != NULL);
+    for (entry = table->table; entry < table->nextEntry; ++entry) {
+        assert(entry != NULL);
+        (*visitor)(entry, arg);
+    }
+}
+
+/*
+ * Visits a large heap reference table.  These objects are list heads.
+ * As such, it is valid for table to be NULL.
+ */
+static void visitLargeHeapRefTable(Visitor *visitor, LargeHeapRefTable *table,
+                                   void *arg)
+{
+    assert(visitor != NULL);
+    for (; table != NULL; table = table->next) {
+        visitReferenceTable(visitor, &table->refs, arg);
+    }
+}
+
+/*
+ * Visits all stack slots. TODO: visit native methods.
+ */
+static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg)
+{
+    const StackSaveArea *saveArea;
+    u4 *framePtr;
+
+    assert(visitor != NULL);
+    assert(thread != NULL);
+    framePtr = (u4 *)thread->curFrame;
+    for (; framePtr != NULL; framePtr = saveArea->prevFrame) {
+        Method *method;
+        saveArea = SAVEAREA_FROM_FP(framePtr);
+        method = (Method *)saveArea->method;
+        if (method != NULL && !dvmIsNativeMethod(method)) {
+            const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
+            const u1* regVector = NULL;
+            size_t i;
+
+            if (pMap != NULL) {
+                /* found map, get registers for this address */
+                int addr = saveArea->xtra.currentPc - method->insns;
+                regVector = dvmRegisterMapGetLine(pMap, addr);
+            }
+            if (regVector == NULL) {
+                /*
+                 * Either there was no register map or there is no
+                 * info for the current PC.  Perform a conservative
+                 * scan.
+                 */
+                for (i = 0; i < method->registersSize; ++i) {
+                    if (dvmIsValidObject((Object *)framePtr[i])) {
+                        (*visitor)(&framePtr[i], arg);
+                    }
+                }
+            } else {
+                /*
+                 * Precise scan.  v0 is at the lowest address on the
+                 * interpreted stack, and is the first bit in the
+                 * register vector, so we can walk through the
+                 * register map and memory in the same direction.
+                 *
+                 * A '1' bit indicates a live reference.
+                 */
+                u2 bits = 1 << 1;
+                for (i = 0; i < method->registersSize; ++i) {
+                    bits >>= 1;
+                    if (bits == 1) {
+                        /* set bit 9 so we can tell when we're empty */
+                        bits = *regVector++ | 0x0100;
+                    }
+                    if ((bits & 0x1) != 0) {
+                        /*
+                         * Register is marked as live, it's a valid root.
+                         */
+                        (*visitor)(&framePtr[i], arg);
+                    }
+                }
+                dvmReleaseRegisterMapLine(pMap, regVector);
+            }
+        }
+        /*
+         * Don't fall into an infinite loop if things get corrupted.
+         */
+        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
+               saveArea->prevFrame == NULL);
+    }
+}
+
+/*
+ * Visits all roots associated with a thread.
+ */
+static void visitThread(Visitor *visitor, Thread *thread, void *arg)
+{
+    assert(visitor != NULL);
+    assert(thread != NULL);
+    assert(thread->status != THREAD_RUNNING ||
+           thread->isSuspended ||
+           thread == dvmThreadSelf());
+    (*visitor)(&thread->threadObj, arg);
+    (*visitor)(&thread->exception, arg);
+    visitReferenceTable(visitor, &thread->internalLocalRefTable, arg);
+    visitReferenceTable(visitor, &thread->jniLocalRefTable, arg);
+    if (thread->jniMonitorRefTable.table) {
+        visitReferenceTable(visitor, &thread->jniMonitorRefTable, arg);
+    }
+    visitThreadStack(visitor, thread, arg);
+}
+
+/*
+ * Visits all threads on the thread list.
+ */
+static void visitThreads(Visitor *visitor, void *arg)
+{
+    Thread *thread;
+
+    assert(visitor != NULL);
+    dvmLockThreadList(dvmThreadSelf());
+    thread = gDvm.threadList;
+    while (thread) {
+        visitThread(visitor, thread, arg);
+        thread = thread->next;
+    }
+    dvmUnlockThreadList();
+}
+
+/*
+ * Visits roots.  TODO: visit all roots.
+ */
+void dvmVisitRoots(Visitor *visitor, void *arg)
+{
+    assert(visitor != NULL);
+    visitHashTable(visitor, gDvm.loadedClasses, arg);
+    visitHashTable(visitor, gDvm.dbgRegistry, arg);
+    visitHashTable(visitor, gDvm.internedStrings, arg);
+    visitHashTable(visitor, gDvm.literalStrings, arg);
+    visitReferenceTable(visitor, &gDvm.jniGlobalRefTable, arg);
+    visitReferenceTable(visitor, &gDvm.jniPinRefTable, arg);
+    visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, arg);
+    visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, arg);
+    visitThreads(visitor, arg);
+    /* TODO: visit cached global references. */
+}
diff --git a/vm/alloc/Visit.h b/vm/alloc/Visit.h
index a954c61..488c721 100644
--- a/vm/alloc/Visit.h
+++ b/vm/alloc/Visit.h
@@ -26,9 +26,13 @@
 typedef void Visitor(void *addr, void *arg);
 
 /*
- * Visits an object and applies the callback specified by the visitor
- * to each reference-containing location.
+ * Visits references in an object.
  */
 void dvmVisitObject(Visitor *visitor, Object *obj, void *arg);
 
+/*
+ * Visits references in the root set.
+ */
+void dvmVisitRoots(Visitor *visitor, void *arg);
+
 #endif /* _DALVIK_ALLOC_VISIT */