Drive all root scanning by the root visitor.
The root visitor has been used by the concurrent collector during the
re-mark phase. This change makes both the initial mark use the same
visitor routine and obsoletes all of the one-off markers scattered
throughout the runtime sources.
Change-Id: I08ea86d875f235cc628754240ad30ea5dfe2ce70
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