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