diff options
author | Carl Shapiro <cshapiro@google.com> | 2010-10-26 21:07:41 -0700 |
---|---|---|
committer | Carl Shapiro <cshapiro@google.com> | 2010-10-28 18:05:28 -0700 |
commit | 07018e2d14b012ae433a0d82025a885ed8debc3b (patch) | |
tree | 101b71a3eb10034779a38f01394ae98ba61c27a1 /vm/alloc/Visit.c | |
parent | e2d2470a6282113b495f2c05a2fa47109d8a4b46 (diff) | |
download | android_dalvik-07018e2d14b012ae433a0d82025a885ed8debc3b.tar.gz android_dalvik-07018e2d14b012ae433a0d82025a885ed8debc3b.tar.bz2 android_dalvik-07018e2d14b012ae433a0d82025a885ed8debc3b.zip |
Separate HPROF from the GC.
In the beginning, the only way to traverse the roots and heap was to
piggyback off the garbage collector. As such, HPROF was implemented
by instrumenting the root- and object traversal routines to check a
mode flag and call into HPROF during a GC when the flag was set.
This change moves the HPROF calls out of the GC and into callbacks
invoked through the visitor. Notably, it allows HPROF dumps to be
computed at any point in time without invoking a GC and potentially
destroying evidence relating to the cause of an OOM.
Change-Id: I2b74c4f10f35af3ca33b7c0bbfe470a8b586ff66
Diffstat (limited to 'vm/alloc/Visit.c')
-rw-r--r-- | vm/alloc/Visit.c | 100 |
1 files changed, 61 insertions, 39 deletions
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c index 0af27dacf..537117758 100644 --- a/vm/alloc/Visit.c +++ b/vm/alloc/Visit.c @@ -34,7 +34,8 @@ void dvmVisitObject(Visitor *visitor, Object *obj, void *arg) /* * Applies a verification function to all present values in the hash table. */ -static void visitHashTable(Visitor *visitor, HashTable *table, void *arg) +static void visitHashTable(RootVisitor *visitor, HashTable *table, + RootType type, void *arg) { int i; @@ -44,17 +45,32 @@ static void visitHashTable(Visitor *visitor, HashTable *table, void *arg) for (i = 0; i < table->tableSize; ++i) { HashEntry *entry = &table->pEntries[i]; if (entry->data != NULL && entry->data != HASH_TOMBSTONE) { - (*visitor)(&entry->data, arg); + (*visitor)(&entry->data, 0, type, arg); } } dvmHashTableUnlock(table); } /* + * Applies a verification function to all elements in the array. + */ +static void visitArray(RootVisitor *visitor, Object **array, size_t length, + RootType type, void *arg) +{ + size_t i; + + assert(visitor != NULL); + assert(array != NULL); + for (i = 0; i < length; ++i) { + (*visitor)(&array[i], 0, type, arg); + } +} + +/* * Visits all entries in the reference table. */ -static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table, - void *arg) +static void visitReferenceTable(RootVisitor *visitor, ReferenceTable *table, + u4 threadId, RootType type, void *arg) { Object **entry; @@ -62,7 +78,7 @@ static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table, assert(table != NULL); for (entry = table->table; entry < table->nextEntry; ++entry) { assert(entry != NULL); - (*visitor)(entry, arg); + (*visitor)(entry, threadId, type, arg); } } @@ -70,29 +86,32 @@ static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table, * 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) +static void visitLargeHeapRefTable(RootVisitor *visitor, + LargeHeapRefTable *table, + RootType type, void *arg) { assert(visitor != NULL); for (; table != NULL; table = table->next) { - visitReferenceTable(visitor, &table->refs, arg); + visitReferenceTable(visitor, &table->refs, 0, type, arg); } } /* * Visits all stack slots. TODO: visit native methods. */ -static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) +static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg) { const StackSaveArea *saveArea; - u4 *framePtr; + u4 *fp; + u4 threadId; assert(visitor != NULL); assert(thread != NULL); - framePtr = (u4 *)thread->curFrame; - for (; framePtr != NULL; framePtr = saveArea->prevFrame) { + threadId = thread->threadId; + fp = (u4 *)thread->curFrame; + for (; fp != NULL; fp = saveArea->prevFrame) { Method *method; - saveArea = SAVEAREA_FROM_FP(framePtr); + saveArea = SAVEAREA_FROM_FP(fp); method = (Method *)saveArea->method; if (method != NULL && !dvmIsNativeMethod(method)) { const RegisterMap* pMap = dvmGetExpandedRegisterMap(method); @@ -111,8 +130,8 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) * scan. */ for (i = 0; i < method->registersSize; ++i) { - if (dvmIsValidObject((Object *)framePtr[i])) { - (*visitor)(&framePtr[i], arg); + if (dvmIsValidObject((Object *)fp[i])) { + (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg); } } } else { @@ -135,7 +154,7 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) /* * Register is marked as live, it's a valid root. */ - (*visitor)(&framePtr[i], arg); + (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg); } } dvmReleaseRegisterMapLine(pMap, regVector); @@ -144,7 +163,7 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) /* * Don't fall into an infinite loop if things get corrupted. */ - assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr || + assert((uintptr_t)saveArea->prevFrame > (uintptr_t)fp || saveArea->prevFrame == NULL); } } @@ -152,16 +171,19 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) /* * Visits all roots associated with a thread. */ -static void visitThread(Visitor *visitor, Thread *thread, void *arg) +static void visitThread(RootVisitor *visitor, Thread *thread, void *arg) { + u4 threadId; + assert(visitor != NULL); assert(thread != NULL); - (*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); + threadId = thread->threadId; + (*visitor)(&thread->threadObj, threadId, ROOT_THREAD_OBJECT, arg); + (*visitor)(&thread->exception, threadId, ROOT_NATIVE_STACK, arg); + visitReferenceTable(visitor, &thread->internalLocalRefTable, threadId, ROOT_NATIVE_STACK, arg); + visitReferenceTable(visitor, &thread->jniLocalRefTable, threadId, ROOT_JNI_LOCAL, arg); + if (thread->jniMonitorRefTable.table != NULL) { + visitReferenceTable(visitor, &thread->jniMonitorRefTable, threadId, ROOT_JNI_MONITOR, arg); } visitThreadStack(visitor, thread, arg); } @@ -169,7 +191,7 @@ static void visitThread(Visitor *visitor, Thread *thread, void *arg) /* * Visits all threads on the thread list. */ -static void visitThreads(Visitor *visitor, void *arg) +static void visitThreads(RootVisitor *visitor, void *arg) { Thread *thread; @@ -184,22 +206,22 @@ static void visitThreads(Visitor *visitor, void *arg) } /* - * Visits roots. TODO: visit all roots. + * Visits roots. TODO: visit cached global references. */ -void dvmVisitRoots(Visitor *visitor, void *arg) +void dvmVisitRoots(RootVisitor *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); + visitHashTable(visitor, gDvm.loadedClasses, ROOT_STICKY_CLASS, arg); + visitArray(visitor, (Object **)gDvm.primitiveClass, NELEM(gDvm.primitiveClass), ROOT_STICKY_CLASS, arg); + visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg); + visitHashTable(visitor, gDvm.internedStrings, ROOT_INTERNED_STRING, arg); + visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg); + visitReferenceTable(visitor, &gDvm.jniGlobalRefTable, 0, ROOT_JNI_GLOBAL, arg); + visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_NATIVE_STACK, arg); + visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, ROOT_REFERENCE_CLEANUP, arg); + visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, ROOT_FINALIZING, arg); visitThreads(visitor, arg); - (*visitor)(&gDvm.outOfMemoryObj, arg); - (*visitor)(&gDvm.internalErrorObj, arg); - (*visitor)(&gDvm.noClassDefFoundErrorObj, arg); - /* TODO: visit cached global references. */ + (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg); + (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg); + (*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg); } |