summaryrefslogtreecommitdiffstats
path: root/vm/alloc/Visit.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm/alloc/Visit.c')
-rw-r--r--vm/alloc/Visit.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c
index 546a6a881..0124e2967 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 @@ void dvmVisitObject(Visitor *visitor, Object *obj, void *arg)
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. */
+}