Merge "Inching closer to having extended opcodes in the vm." into dalvik-dev
diff --git a/tests/etc/local-run-test-jar b/tests/etc/local-run-test-jar
deleted file mode 100755
index 6155e3f..0000000
--- a/tests/etc/local-run-test-jar
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/bin/sh
-#
-# Run the code in test.jar on a host-local virtual machine. The jar should
-# contain a top-level class named Main to run.
-#
-# Options:
-#   --quiet       -- don't chatter
-#   --fast        -- use the fast interpreter (the default)
-#   --jit         -- use the jit
-#   --portable    -- use the portable interpreter
-#   --debug       -- wait for debugger to attach
-#   --valgrind    -- use valgrind
-#   --no-verify   -- turn off verification (on by default)
-#   --no-optimize -- turn off optimization (on by default)
-
-msg() {
-    if [ "$QUIET" = "n" ]; then
-        echo "$@"
-    fi
-}
-
-INTERP=""
-DEBUG="n"
-GDB="n"
-VERIFY="y"
-OPTIMIZE="y"
-VALGRIND="n"
-DEV_MODE="n"
-QUIET="n"
-PRECISE="y"
-
-while true; do
-    if [ "x$1" = "x--quiet" ]; then
-        QUIET="y"
-        shift
-    elif [ "x$1" = "x--jit" ]; then
-        INTERP="jit"
-        msg "Using jit"
-        shift
-    elif [ "x$1" = "x--fast" ]; then
-        INTERP="fast"
-        msg "Using fast interpreter"
-        shift
-    elif [ "x$1" = "x--portable" ]; then
-        INTERP="portable"
-        msg "Using portable interpreter"
-        shift
-    elif [ "x$1" = "x--debug" ]; then
-        DEBUG="y"
-        shift
-    elif [ "x$1" = "x--gdb" ]; then
-        GDB="y"
-        shift
-    elif [ "x$1" = "x--valgrind" ]; then
-        VALGRIND="y"
-        shift
-    elif [ "x$1" = "x--dev" ]; then
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--no-verify" ]; then
-        VERIFY="n"
-        shift
-    elif [ "x$1" = "x--no-optimize" ]; then
-        OPTIMIZE="n"
-        shift
-    elif [ "x$1" = "x--no-precise" ]; then
-        PRECISE="n"
-        shift
-    elif [ "x$1" = "x--" ]; then
-        shift
-        break
-    elif expr "x$1" : "x--" >/dev/null 2>&1; then
-        echo "unknown option: $1" 1>&2
-        exit 1
-    else
-        break
-    fi
-done
-
-if [ "x$INTERP" = "x" ]; then
-    INTERP="fast"
-    msg "Using fast interpreter by default"
-fi
-
-if [ "$OPTIMIZE" = "y" ]; then
-    if [ "$VERIFY" = "y" ]; then
-        DEX_OPTIMIZE="-Xdexopt:verified"
-    else
-        DEX_OPTIMIZE="-Xdexopt:all"
-    fi
-    msg "Performing optimizations"
-else
-    DEX_OPTIMIZE="-Xdexopt:none"
-    msg "Skipping optimizations"
-fi
-
-if [ "$VERIFY" = "y" ]; then
-    DEX_VERIFY=""
-    msg "Performing verification"
-else
-    DEX_VERIFY="-Xverify:none"
-    msg "Skipping verification"
-fi
-
-if [ "$VALGRIND" = "y" ]; then
-    msg "Running with valgrind"
-    valgrind_cmd="valgrind"
-    #valgrind_cmd="valgrind --leak-check=full"
-else
-    valgrind_cmd=""
-fi
-
-if [ "$PRECISE" = "y" ]; then
-    GC_OPTS="-Xgc:precise -Xgenregmap"
-else
-    GC_OPTS="-Xgc:noprecise"
-fi
-
-msg "------------------------------"
-
-BASE="$OUT" # from build environment
-DATA_DIR=/tmp
-DEBUG_OPTS="-Xcheck:jni -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
-
-export ANDROID_PRINTF_LOG=brief
-if [ "$DEV_MODE" = "y" ]; then
-    export ANDROID_LOG_TAGS='*:d'
-else
-    export ANDROID_LOG_TAGS='*:s'
-fi
-export ANDROID_DATA="$DATA_DIR"
-export ANDROID_ROOT="${BASE}/system"
-export LD_LIBRARY_PATH="${BASE}/system/lib"
-export DYLD_LIBRARY_PATH="${BASE}/system/lib"
-
-exe="${BASE}/system/bin/dalvikvm"
-framework="${BASE}/system/framework"
-bpath="${framework}/core.jar:${framework}/ext.jar:${framework}/framework.jar"
-
-if [ "$DEBUG" = "y" ]; then
-    PORT=8000
-    msg "Waiting for debugger to connect on localhost:$PORT"
-    DEX_DEBUG="-agentlib:jdwp=transport=dt_socket,addres=$PORT,server=y,suspend=y"
-fi
-
-if [ "$GDB" = "y" ]; then
-    gdb=gdb
-    gdbargs="--args $exe"
-fi
-
-$valgrind_cmd $gdb $exe $gdbargs "-Xbootclasspath:${bpath}" \
-    $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG $GC_OPTS "-Xint:${INTERP}" -ea \
-    -cp test.jar Main "$@"
diff --git a/tests/run-all-tests b/tests/run-all-tests
index 7704b18..f66cd76 100755
--- a/tests/run-all-tests
+++ b/tests/run-all-tests
@@ -37,10 +37,7 @@
 usage="no"
 
 while true; do
-    if [ "x$1" = "x--local" ]; then
-        run_args="${run_args} --local"
-        shift
-    elif [ "x$1" = "x--host" ]; then
+    if [ "x$1" = "x--host" ]; then
         run_args="${run_args} --host"
         shift
     elif [ "x$1" = "x--reference" ]; then
@@ -95,10 +92,10 @@
         echo "  $prog --help     Print this message."
         echo "  $prog [options]  Run all tests with the given options."
         echo "  Options are all passed to run-test; refer to that for " \
-	    "further documentation:"
-        echo "    --debug --dev --fast --local --no-optimize --no-verify" \
-	    "--portable"
-	echo "    --reference --update --valgrind --zygote --host"
+             "further documentation:"
+        echo "    --debug --dev --fast --host --no-optimize --no-verify" \
+             "--portable"
+        echo "    --reference --update --valgrind --zygote"
     ) 1>&2
     exit 1
 fi
diff --git a/tests/run-test b/tests/run-test
index df9fa4d..fb758d7 100755
--- a/tests/run-test
+++ b/tests/run-test
@@ -51,15 +51,12 @@
 usage="no"
 
 while true; do
-    if [ "x$1" = "x--local" ]; then
-        RUN="${progdir}/etc/local-run-test-jar"
+    if [ "x$1" = "x--host" ]; then
+        RUN="${progdir}/etc/host-run-test-jar"
         shift
     elif [ "x$1" = "x--reference" ]; then
         RUN="${progdir}/etc/reference-run-test-classes"
         shift
-    elif [ "x$1" = "x--host" ]; then
-        RUN="${progdir}/etc/host-run-test-jar"
-        shift
     elif [ "x$1" = "x--jit" ]; then
         run_args="${run_args} --jit"
         shift
@@ -143,11 +140,11 @@
         echo "  $prog --help                          Print this message."
         echo "  $prog [options] [test-name]           Run test normally."
         echo "  $prog --dev [options] [test-name]     Development mode" \
-	    "(dumps to stdout)."
+             "(dumps to stdout)."
         echo "  $prog --update [options] [test-name]  Update mode" \
-	    "(replaces expected.txt)."
+             "(replaces expected.txt)."
         echo '  Omitting the test name or specifying "-" will use the' \
-	    "current directory."
+             "current directory."
         echo "  Runtime Options:"
         echo "    --fast         Use the fast interpreter (the default)."
         echo "    --jit          Use the jit."
@@ -158,9 +155,8 @@
         echo "    --no-optimize  Turn off optimization (on by default)."
         echo "    --no-precise   Turn off precise GC (on by default)."
         echo "    --zygote       Spawn the process from the Zygote." \
-	    "If used, then the"
-	echo "                   other runtime options are ignored."
-        echo "    --local        Use a host-local virtual machine."
+             "If used, then the"
+        echo "                   other runtime options are ignored."
         echo "    --host         Use the host-mode virtual machine."
         echo "    --valgrind     Use valgrind when running locally."
         echo "    --reference    Use a host-local reference virtual machine."
@@ -212,7 +208,7 @@
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
         "./${run}" $run_args "$@" >"$output" 2>&1
-	sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}"
+        sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}"
         good="yes"
     else
         cat "$build_output" 1>&2
diff --git a/vm/Debugger.c b/vm/Debugger.c
index 39eb74a..d5215ca 100644
--- a/vm/Debugger.c
+++ b/vm/Debugger.c
@@ -238,32 +238,6 @@
 }
 
 /*
- * (This is a HashForeachFunc callback.)
- */
-static int markRef(void* data, void* arg)
-{
-    UNUSED_PARAMETER(arg);
-
-    //LOGI("dbg mark %p\n", data);
-    dvmMarkObjectNonNull(data);
-    return 0;
-}
-
-/* Mark all of the registered debugger references so the
- * GC doesn't collect them.
- */
-void dvmGcMarkDebuggerRefs()
-{
-    /* dvmDebuggerStartup() may not have been called before the first GC.
-     */
-    if (gDvm.dbgRegistry != NULL) {
-        dvmHashTableLock(gDvm.dbgRegistry);
-        dvmHashForeach(gDvm.dbgRegistry, markRef, NULL);
-        dvmHashTableUnlock(gDvm.dbgRegistry);
-    }
-}
-
-/*
  * Verify that an object has been registered.  If it hasn't, the debugger
  * is asking for something we didn't send it, which means something
  * somewhere is broken.
diff --git a/vm/Intern.c b/vm/Intern.c
index 8bc38b8..f91cc35 100644
--- a/vm/Intern.c
+++ b/vm/Intern.c
@@ -169,27 +169,6 @@
     return found == strObj;
 }
 
-static int markStringObject(void* strObj, void* arg)
-{
-    UNUSED_PARAMETER(arg);
-    dvmMarkObjectNonNull(strObj);
-    return 0;
-}
-
-/*
- * Blacken string references from the literal string table.  The
- * literal table is a root.
- */
-void dvmGcScanInternedStrings()
-{
-    /* It's possible for a GC to happen before dvmStringInternStartup()
-     * is called.
-     */
-    if (gDvm.literalStrings != NULL) {
-        dvmHashForeach(gDvm.literalStrings, markStringObject, NULL);
-    }
-}
-
 /*
  * Clear white references from the intern table.
  */
diff --git a/vm/Jni.c b/vm/Jni.c
index a7d460f..f2ee2ae 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -1043,50 +1043,6 @@
     dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
 }
 
-/*
- * GC helper function to mark all JNI global references.
- *
- * We're currently handling the "pin" table here too.
- */
-void dvmGcMarkJniGlobalRefs()
-{
-    Object** op;
-
-    dvmLockMutex(&gDvm.jniGlobalRefLock);
-
-#ifdef USE_INDIRECT_REF
-    IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
-    op = pRefTable->table;
-    int numEntries = dvmIndirectRefTableEntries(pRefTable);
-    int i;
-
-    for (i = 0; i < numEntries; i++) {
-        Object* obj = *op;
-        if (obj != NULL)
-            dvmMarkObjectNonNull(obj);
-        op++;
-    }
-#else
-    op = gDvm.jniGlobalRefTable.table;
-    while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
-        dvmMarkObjectNonNull(*(op++));
-    }
-#endif
-
-    dvmUnlockMutex(&gDvm.jniGlobalRefLock);
-
-
-    dvmLockMutex(&gDvm.jniPinRefLock);
-
-    op = gDvm.jniPinRefTable.table;
-    while ((uintptr_t)op < (uintptr_t)gDvm.jniPinRefTable.nextEntry) {
-        dvmMarkObjectNonNull(*(op++));
-    }
-
-    dvmUnlockMutex(&gDvm.jniPinRefLock);
-}
-
-
 #ifndef USE_INDIRECT_REF
 /*
  * Determine if "obj" appears in the argument list for the native method.
diff --git a/vm/Thread.c b/vm/Thread.c
index c2e11c8..dd87483 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -3911,323 +3911,3 @@
     return NULL;
 }
 #endif /*WITH_MONITOR_TRACKING*/
-
-
-/*
- * GC helper functions
- */
-
-/*
- * Add the contents of the registers from the interpreted call stack.
- */
-static void gcScanInterpStackReferences(Thread *thread)
-{
-    const u4 *framePtr;
-#if WITH_EXTRA_GC_CHECKS > 1
-    bool first = true;
-#endif
-
-    framePtr = (const u4 *)thread->curFrame;
-    while (framePtr != NULL) {
-        const StackSaveArea *saveArea;
-        const Method *method;
-
-        saveArea = SAVEAREA_FROM_FP(framePtr);
-        method = saveArea->method;
-        if (method != NULL) {
-#ifdef COUNT_PRECISE_METHODS
-            /* the GC is running, so no lock required */
-            if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
-                LOGI("PGC: added %s.%s %p\n",
-                    method->clazz->descriptor, method->name, method);
-#endif
-#if WITH_EXTRA_GC_CHECKS > 1
-            /*
-             * May also want to enable the memset() in the "invokeMethod"
-             * goto target in the portable interpreter.  That sets the stack
-             * to a pattern that makes referring to uninitialized data
-             * very obvious.
-             */
-
-            if (first) {
-                /*
-                 * First frame, isn't native, check the "alternate" saved PC
-                 * as a sanity check.
-                 *
-                 * It seems like we could check the second frame if the first
-                 * is native, since the PCs should be the same.  It turns out
-                 * this doesn't always work.  The problem is that we could
-                 * have calls in the sequence:
-                 *   interp method #2
-                 *   native method
-                 *   interp method #1
-                 *
-                 * and then GC while in the native method after returning
-                 * from interp method #2.  The currentPc on the stack is
-                 * for interp method #1, but thread->currentPc2 is still
-                 * set for the last thing interp method #2 did.
-                 *
-                 * This can also happen in normal execution:
-                 * - sget-object on not-yet-loaded class
-                 * - class init updates currentPc2
-                 * - static field init is handled by parsing annotations;
-                 *   static String init requires creation of a String object,
-                 *   which can cause a GC
-                 *
-                 * Essentially, any pattern that involves executing
-                 * interpreted code and then causes an allocation without
-                 * executing instructions in the original method will hit
-                 * this.  These are rare enough that the test still has
-                 * some value.
-                 */
-                if (saveArea->xtra.currentPc != thread->currentPc2) {
-                    LOGW("PGC: savedPC(%p) != current PC(%p), %s.%s ins=%p\n",
-                        saveArea->xtra.currentPc, thread->currentPc2,
-                        method->clazz->descriptor, method->name, method->insns);
-                    if (saveArea->xtra.currentPc != NULL)
-                        LOGE("  pc inst = 0x%04x\n", *saveArea->xtra.currentPc);
-                    if (thread->currentPc2 != NULL)
-                        LOGE("  pc2 inst = 0x%04x\n", *thread->currentPc2);
-                    dvmDumpThread(thread, false);
-                }
-            } else {
-                /*
-                 * It's unusual, but not impossible, for a non-first frame
-                 * to be at something other than a method invocation.  For
-                 * example, if we do a new-instance on a nonexistent class,
-                 * we'll have a lot of class loader activity on the stack
-                 * above the frame with the "new" operation.  Could also
-                 * happen while we initialize a Throwable when an instruction
-                 * fails.
-                 *
-                 * So there's not much we can do here to verify the PC,
-                 * except to verify that it's a GC point.
-                 */
-            }
-            assert(saveArea->xtra.currentPc != NULL);
-#endif
-
-            const RegisterMap* pMap;
-            const u1* regVector;
-            int i;
-
-            Method* nonConstMethod = (Method*) method;  // quiet gcc
-            pMap = dvmGetExpandedRegisterMap(nonConstMethod);
-            if (pMap != NULL) {
-                /* found map, get registers for this address */
-                int addr = saveArea->xtra.currentPc - method->insns;
-                regVector = dvmRegisterMapGetLine(pMap, addr);
-                if (regVector == NULL) {
-                    LOGW("PGC: map but no entry for %s.%s addr=0x%04x\n",
-                        method->clazz->descriptor, method->name, addr);
-                } else {
-                    LOGV("PGC: found map for %s.%s 0x%04x (t=%d)\n",
-                        method->clazz->descriptor, method->name, addr,
-                        thread->threadId);
-                }
-            } else {
-                /*
-                 * No map found.  If precise GC is disabled this is
-                 * expected -- we don't create pointers to the map data even
-                 * if it's present -- but if it's enabled it means we're
-                 * unexpectedly falling back on a conservative scan, so it's
-                 * worth yelling a little.
-                 */
-                if (gDvm.preciseGc) {
-                    LOGVV("PGC: no map for %s.%s\n",
-                        method->clazz->descriptor, method->name);
-                }
-                regVector = NULL;
-            }
-
-            if (regVector == NULL) {
-                /* conservative scan */
-                for (i = method->registersSize - 1; i >= 0; i--) {
-                    u4 rval = *framePtr++;
-                    if (rval != 0 && (rval & 0x3) == 0) {
-                        dvmMarkIfObject((Object *)rval);
-                    }
-                }
-            } 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 = method->registersSize - 1; i >= 0; i--) {
-                    u4 rval = *framePtr++;
-
-                    bits >>= 1;
-                    if (bits == 1) {
-                        /* set bit 9 so we can tell when we're empty */
-                        bits = *regVector++ | 0x0100;
-                        LOGVV("loaded bits: 0x%02x\n", bits & 0xff);
-                    }
-
-                    if (rval != 0 && (bits & 0x01) != 0) {
-                        /*
-                         * Non-null, register marked as live reference.  This
-                         * should always be a valid object.
-                         */
-#if WITH_EXTRA_GC_CHECKS > 0
-                        if ((rval & 0x3) != 0 ||
-                            !dvmIsValidObject((Object*) rval))
-                        {
-                            /* this is very bad */
-                            LOGE("PGC: invalid ref in reg %d: 0x%08x\n",
-                                method->registersSize-1 - i, rval);
-                            LOGE("PGC: %s.%s addr 0x%04x\n",
-                                method->clazz->descriptor, method->name,
-                                saveArea->xtra.currentPc - method->insns);
-                        } else
-#endif
-                        {
-                            dvmMarkObjectNonNull((Object *)rval);
-                        }
-                    } else {
-                        /*
-                         * Null or non-reference, do nothing at all.
-                         */
-#if WITH_EXTRA_GC_CHECKS > 1
-                        if (dvmIsValidObject((Object*) rval)) {
-                            /* this is normal, but we feel chatty */
-                            LOGD("PGC: ignoring valid ref in reg %d: 0x%08x\n",
-                                method->registersSize-1 - i, rval);
-                        }
-#endif
-                    }
-                }
-                dvmReleaseRegisterMapLine(pMap, regVector);
-            }
-        }
-
-#if WITH_EXTRA_GC_CHECKS > 1
-        first = false;
-#endif
-
-        /* Don't fall into an infinite loop if things get corrupted.
-         */
-        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
-               saveArea->prevFrame == NULL);
-        framePtr = saveArea->prevFrame;
-    }
-}
-
-static void gcScanReferenceTable(ReferenceTable *refTable)
-{
-    Object **op;
-
-    //TODO: these asserts are overkill; turn them off when things stablize.
-    assert(refTable != NULL);
-    assert(refTable->table != NULL);
-    assert(refTable->nextEntry != NULL);
-    assert((uintptr_t)refTable->nextEntry >= (uintptr_t)refTable->table);
-    assert(refTable->nextEntry - refTable->table <= refTable->maxEntries);
-
-    op = refTable->table;
-    while ((uintptr_t)op < (uintptr_t)refTable->nextEntry) {
-        dvmMarkObjectNonNull(*(op++));
-    }
-}
-
-#ifdef USE_INDIRECT_REF
-static void gcScanIndirectRefTable(IndirectRefTable* pRefTable)
-{
-    Object** op = pRefTable->table;
-    int numEntries = dvmIndirectRefTableEntries(pRefTable);
-    int i;
-
-    for (i = 0; i < numEntries; i++) {
-        Object* obj = *op;
-        if (obj != NULL)
-            dvmMarkObjectNonNull(obj);
-        op++;
-    }
-}
-#endif
-
-/*
- * Scan a Thread and mark any objects it references.
- */
-static void gcScanThread(Thread *thread)
-{
-    assert(thread != NULL);
-
-    /*
-     * The target thread must be suspended or in a state where it can't do
-     * any harm (e.g. in Object.wait()).  The only exception is the current
-     * thread, which will still be active and in the "running" state.
-     *
-     * It's possible to encounter a false-positive here because a thread
-     * transitioning to running from (say) vmwait or native will briefly
-     * set their status to running before switching to suspended.  This
-     * is highly unlikely, but does mean that we don't want to abort if
-     * the situation arises.
-     */
-    if (thread->status == THREAD_RUNNING && thread != dvmThreadSelf()) {
-        Thread* self = dvmThreadSelf();
-        LOGW("threadid=%d: Warning: GC scanning a running thread (%d)\n",
-            self->threadId, thread->threadId);
-        dvmDumpThread(thread, true);
-        LOGW("Found by:\n");
-        dvmDumpThread(self, false);
-
-        /* continue anyway */
-    }
-
-    dvmMarkObject(thread->threadObj);   // could be NULL, when constructing
-
-    dvmMarkObject(thread->exception);   // usually NULL
-    gcScanReferenceTable(&thread->internalLocalRefTable);
-
-#ifdef USE_INDIRECT_REF
-    gcScanIndirectRefTable(&thread->jniLocalRefTable);
-#else
-    gcScanReferenceTable(&thread->jniLocalRefTable);
-#endif
-
-    if (thread->jniMonitorRefTable.table != NULL) {
-        gcScanReferenceTable(&thread->jniMonitorRefTable);
-    }
-
-    gcScanInterpStackReferences(thread);
-}
-
-static void gcScanAllThreads()
-{
-    Thread *thread;
-
-    /* Lock the thread list so we can safely use the
-     * next/prev pointers.
-     */
-    dvmLockThreadList(dvmThreadSelf());
-
-    for (thread = gDvm.threadList; thread != NULL;
-            thread = thread->next)
-    {
-        /* We need to scan our own stack, so don't special-case
-         * the current thread.
-         */
-        gcScanThread(thread);
-    }
-
-    dvmUnlockThreadList();
-}
-
-void dvmGcScanRootThreadGroups()
-{
-    /* We scan the VM's list of threads instead of going
-     * through the actual ThreadGroups, but it should be
-     * equivalent.
-     *
-     * This assumes that the ThreadGroup class object is in
-     * the root set, which should always be true;  it's
-     * loaded by the built-in class loader, which is part
-     * of the root set.
-     */
-    gcScanAllThreads();
-}
diff --git a/vm/alloc/Copying.c b/vm/alloc/Copying.c
index 01c238a..0d72bfc 100644
--- a/vm/alloc/Copying.c
+++ b/vm/alloc/Copying.c
@@ -2343,11 +2343,6 @@
     /* do nothing */
 }
 
-void dvmMarkObjectNonNull(const Object *obj)
-{
-    assert(!"implemented");
-}
-
 void dvmMarkDirtyObjects(void)
 {
     assert(!"implemented");
diff --git a/vm/alloc/GC.h b/vm/alloc/GC.h
index c65c807..ce623ea 100644
--- a/vm/alloc/GC.h
+++ b/vm/alloc/GC.h
@@ -38,104 +38,10 @@
  */
 
 /*
- * Mark an object and schedule it to be scanned for
- * references to other objects.
- *
- * @param obj must be a valid object
- */
-void dvmMarkObjectNonNull(const Object *obj);
-
-/*
- * Mark an object and schedule it to be scanned for
- * references to other objects.
- *
- * @param obj must be a valid object or NULL
- */
-#define dvmMarkObject(obj) \
-    do { \
-        Object *DMO_obj_ = (Object *)(obj); \
-        if (DMO_obj_ != NULL) { \
-            dvmMarkObjectNonNull(DMO_obj_); \
-        } \
-    } while (false)
-
-/*
- * If obj points to a valid object, mark it and
- * schedule it to be scanned for references to other
- * objects.
- *
- * @param obj any pointer that may be an Object, or NULL
-TODO: check for alignment, too (would require knowledge of heap chunks)
- */
-#define dvmMarkIfObject(obj) \
-    do { \
-        Object *DMIO_obj_ = (Object *)(obj); \
-        if (DMIO_obj_ != NULL && dvmIsValidObject(DMIO_obj_)) { \
-            dvmMarkObjectNonNull(DMIO_obj_); \
-        } \
-    } while (false)
-
-/*
- * Functions that handle scanning various objects for references.
- */
-
-/*
- * Mark all class objects loaded by the root class loader;
- * most of these are the java.* classes.
- *
- * Currently implemented in Class.c.
- */
-void dvmGcScanRootClassLoader(void);
-
-/*
- * Mark all root ThreadGroup objects, guaranteeing that
- * all live Thread objects will eventually be scanned.
- *
- * NOTE: this is a misnomer, because the current implementation
- * actually only scans the internal list of VM threads, which
- * will mark all VM-reachable Thread objects.  Someone else
- * must scan the root class loader, which will mark java/lang/ThreadGroup.
- * The ThreadGroup class object has static members pointing to
- * the root ThreadGroups, and these will be marked as a side-effect
- * of marking the class object.
- *
- * Currently implemented in Thread.c.
- */
-void dvmGcScanRootThreadGroups(void);
-
-/*
- * Mark all interned string objects.
- *
- * Currently implemented in Intern.c.
- */
-void dvmGcScanInternedStrings(void);
-
-/*
  * Remove any unmarked interned string objects from the table.
  *
  * Currently implemented in Intern.c.
  */
 void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *));
 
-/*
- * Mark all primitive class objects.
- *
- * Currently implemented in Array.c.
- */
-void dvmGcScanPrimitiveClasses(void);
-
-/*
- * Mark all JNI global references.
- *
- * Currently implemented in JNI.c.
- */
-void dvmGcMarkJniGlobalRefs(void);
-
-/*
- * Mark all debugger references.
- *
- * Currently implemented in Debugger.c.
- */
-void dvmGcMarkDebuggerRefs(void);
-
 #endif  // _DALVIK_ALLOC_GC
diff --git a/vm/alloc/HeapTable.c b/vm/alloc/HeapTable.c
index e9f2729..72cf791 100644
--- a/vm/alloc/HeapTable.c
+++ b/vm/alloc/HeapTable.c
@@ -182,17 +182,3 @@
 
     return obj;
 }
-
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table)
-{
-    while (table != NULL) {
-        Object **ref, **lastRef;
-
-        ref = table->refs.table;
-        lastRef = table->refs.nextEntry;
-        while (ref < lastRef) {
-            dvmMarkObjectNonNull(*ref++);
-        }
-        table = table->next;
-    }
-}
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index ccbb663..750256c 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -29,15 +29,12 @@
 #define GC_LOG_TAG      LOG_TAG "-gc"
 
 #if LOG_NDEBUG
-#define LOGV_GC(...)    ((void)0)
 #define LOGD_GC(...)    ((void)0)
 #else
-#define LOGV_GC(...)    LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
 #define LOGD_GC(...)    LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
 #endif
 
 #define LOGE_GC(...)    LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
-#define LOG_SCAN(...)   LOGV_GC("SCAN: " __VA_ARGS__)
 
 #define ALIGN_DOWN(x, n) ((size_t)(x) & -(n))
 #define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
@@ -155,19 +152,21 @@
     }
 }
 
-/* If the object hasn't already been marked, mark it and
- * schedule it to be scanned for references.
- *
- * obj may not be NULL.  The macro dvmMarkObject() should
- * be used in situations where a reference may be NULL.
- *
- * This function may only be called when marking the root
- * set.  When recursing, use the internal markObject().
+/*
+ * Callback applied to root references during the initial root
+ * marking.  Visited roots are always marked but are only pushed on
+ * the mark stack if their address is below the finger.
  */
-void dvmMarkObjectNonNull(const Object *obj)
+static void rootMarkObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
 {
-    assert(obj != NULL);
-    markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
+    Object *obj;
+
+    assert(addr != NULL);
+    assert(arg != NULL);
+    obj = *(Object **)addr;
+    if (obj != NULL) {
+        markObjectNonNull(obj, arg, false);
+    }
 }
 
 /* Mark the set of root objects.
@@ -199,45 +198,14 @@
 void dvmHeapMarkRootSet()
 {
     GcHeap *gcHeap = gDvm.gcHeap;
-
-    LOG_SCAN("immune objects");
     dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
-
-    LOG_SCAN("root class loader\n");
-    dvmGcScanRootClassLoader();
-    LOG_SCAN("primitive classes\n");
-    dvmGcScanPrimitiveClasses();
-
-    LOG_SCAN("root thread groups\n");
-    dvmGcScanRootThreadGroups();
-
-    LOG_SCAN("interned strings\n");
-    dvmGcScanInternedStrings();
-
-    LOG_SCAN("JNI global refs\n");
-    dvmGcMarkJniGlobalRefs();
-
-    LOG_SCAN("pending reference operations\n");
-    dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
-
-    LOG_SCAN("pending finalizations\n");
-    dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
-
-    LOG_SCAN("debugger refs\n");
-    dvmGcMarkDebuggerRefs();
-
-    /* Mark any special objects we have sitting around.
-     */
-    LOG_SCAN("special objects\n");
-    dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
-    dvmMarkObjectNonNull(gDvm.internalErrorObj);
-    dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
-//TODO: scan object references sitting in gDvm;  use pointer begin & end
+    dvmVisitRoots(rootMarkObjectVisitor, &gcHeap->markContext);
 }
 
 /*
- * Callback applied to root references.  If the root location contains
- * a white reference it is pushed on the mark stack and grayed.
+ * Callback applied to root references during root remarking.  If the
+ * root location contains a white reference it is pushed on the mark
+ * stack and grayed.
  */
 static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
 {
@@ -262,16 +230,6 @@
 }
 
 /*
- * Nothing past this point is allowed to use dvmMarkObject() or
- * dvmMarkObjectNonNull(), which are for root-marking only.
- * Scanning/recursion must use markObject(), which takes the finger
- * into account.
- */
-#undef dvmMarkObject
-#define dvmMarkObject __dont_use_dvmMarkObject__
-#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
-
-/*
  * Scans instance fields.
  */
 static void scanFields(const Object *obj, GcMarkContext *ctx)
@@ -751,8 +709,6 @@
      * left on the mark stack.
      */
     processMarkStack(ctx);
-
-    LOG_SCAN("done with marked objects\n");
 }
 
 void dvmHeapReScanMarkedObjects(void)
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c
index 697cc3f..a317955 100644
--- a/vm/alloc/Visit.c
+++ b/vm/alloc/Visit.c
@@ -97,7 +97,8 @@
 }
 
 /*
- * Visits all stack slots. TODO: visit native methods.
+ * Visits all stack slots except those belonging to native method
+ * arguments.
  */
 static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg)
 {
@@ -154,6 +155,17 @@
                         /*
                          * Register is marked as live, it's a valid root.
                          */
+#if WITH_EXTRA_GC_CHECKS
+                        if (fp[i] != 0 && !dvmIsValidObject((Object *)fp[i])) {
+                            /* this is very bad */
+                            LOGE("PGC: invalid ref in reg %d: %#x",
+                                 method->registersSize - 1 - i, fp[i]);
+                            LOGE("PGC: %s.%s addr %#x",
+                                 method->clazz->descriptor, method->name,
+                                 saveArea->xtra.currentPc - method->insns);
+                            continue;
+                        }
+#endif
                         (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg);
                     }
                 }
@@ -216,10 +228,15 @@
     if (gDvm.dbgRegistry != NULL) {
         visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg);
     }
-    visitHashTable(visitor, gDvm.internedStrings, ROOT_INTERNED_STRING, arg);
-    visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg);
+    if (gDvm.literalStrings != NULL) {
+        visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg);
+    }
+    dvmLockMutex(&gDvm.jniGlobalRefLock);
     visitReferenceTable(visitor, &gDvm.jniGlobalRefTable, 0, ROOT_JNI_GLOBAL, arg);
+    dvmUnlockMutex(&gDvm.jniGlobalRefLock);
+    dvmLockMutex(&gDvm.jniPinRefLock);
     visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg);
+    dvmUnlockMutex(&gDvm.jniPinRefLock);
     visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, ROOT_REFERENCE_CLEANUP, arg);
     visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, ROOT_FINALIZING, arg);
     visitThreads(visitor, arg);
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
index 3b1c652..bc57a5a 100644
--- a/vm/oo/Array.c
+++ b/vm/oo/Array.c
@@ -799,16 +799,3 @@
     size += array->length * dvmArrayClassElementWidth(array->obj.clazz);
     return size;
 }
-
-/*
- * Add all primitive classes to the root set of objects.
-TODO: do these belong to the root class loader?
- */
-void dvmGcScanPrimitiveClasses()
-{
-    int i;
-
-    for (i = 0; i < PRIM_MAX; i++) {
-        dvmMarkObject((Object *)gDvm.primitiveClass[i]);    // may be NULL
-    }
-}
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index c6b169f..6e16adc 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -4884,34 +4884,6 @@
 }
 #endif
 
-
-/*
- * Mark all classes associated with the built-in loader.
- */
-static int markClassObject(void *clazz, void *arg)
-{
-    UNUSED_PARAMETER(arg);
-
-    dvmMarkObjectNonNull((Object *)clazz);
-    return 0;
-}
-
-/*
- * The garbage collector calls this to mark the class objects for all
- * loaded classes.
- */
-void dvmGcScanRootClassLoader()
-{
-    /* dvmClassStartup() may not have been called before the first GC.
-     */
-    if (gDvm.loadedClasses != NULL) {
-        dvmHashTableLock(gDvm.loadedClasses);
-        dvmHashForeach(gDvm.loadedClasses, markClassObject, NULL);
-        dvmHashTableUnlock(gDvm.loadedClasses);
-    }
-}
-
-
 /*
  * ===========================================================================
  *      Method Prototypes and Descriptors