Visit.cpp revision ce0968340f9ddd54f20e38d4946bfd2ef8f1f343
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "Dalvik.h" 18#include "alloc/HeapInternal.h" 19#include "alloc/Visit.h" 20#include "alloc/VisitInlines.h" 21 22/* 23 * Visits all of the reference locations in an object. 24 */ 25void dvmVisitObject(Visitor *visitor, Object *obj, void *arg) 26{ 27 assert(visitor != NULL); 28 assert(obj != NULL); 29 assert(obj->clazz != NULL); 30 visitObject(visitor, obj, arg); 31} 32 33/* 34 * Applies a verification function to all present values in the hash table. 35 */ 36static void visitHashTable(RootVisitor *visitor, HashTable *table, 37 RootType type, void *arg) 38{ 39 assert(visitor != NULL); 40 assert(table != NULL); 41 dvmHashTableLock(table); 42 for (int i = 0; i < table->tableSize; ++i) { 43 HashEntry *entry = &table->pEntries[i]; 44 if (entry->data != NULL && entry->data != HASH_TOMBSTONE) { 45 (*visitor)(&entry->data, 0, type, arg); 46 } 47 } 48 dvmHashTableUnlock(table); 49} 50 51/* 52 * Visits all entries in the reference table. 53 */ 54static void visitReferenceTable(RootVisitor *visitor, ReferenceTable *table, 55 u4 threadId, RootType type, void *arg) 56{ 57 assert(visitor != NULL); 58 assert(table != NULL); 59 for (Object **entry = table->table; entry < table->nextEntry; ++entry) { 60 assert(entry != NULL); 61 (*visitor)(entry, threadId, type, arg); 62 } 63} 64 65/* 66 * Visits all entries in the indirect reference table. 67 */ 68static void visitIndirectRefTable(RootVisitor *visitor, IndirectRefTable *table, 69 u4 threadId, RootType type, void *arg) 70{ 71 assert(visitor != NULL); 72 assert(table != NULL); 73 Object **entry = table->table; 74 int numEntries = table->capacity(); 75 for (int i = 0; i < numEntries; ++i) { 76 (*visitor)(&entry[i], threadId, type, arg); 77 } 78} 79 80/* 81 * Visits all stack slots except those belonging to native method 82 * arguments. 83 */ 84static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg) 85{ 86 assert(visitor != NULL); 87 assert(thread != NULL); 88 u4 threadId = thread->threadId; 89 const StackSaveArea *saveArea; 90 for (u4 *fp = (u4 *)thread->interpSave.curFrame; 91 fp != NULL; 92 fp = (u4 *)saveArea->prevFrame) { 93 Method *method; 94 saveArea = SAVEAREA_FROM_FP(fp); 95 method = (Method *)saveArea->method; 96 if (method != NULL && !dvmIsNativeMethod(method)) { 97 const RegisterMap* pMap = dvmGetExpandedRegisterMap(method); 98 const u1* regVector = NULL; 99 if (pMap != NULL) { 100 /* found map, get registers for this address */ 101 int addr = saveArea->xtra.currentPc - method->insns; 102 regVector = dvmRegisterMapGetLine(pMap, addr); 103 } 104 if (regVector == NULL) { 105 /* 106 * Either there was no register map or there is no 107 * info for the current PC. Perform a conservative 108 * scan. 109 */ 110 for (size_t i = 0; i < method->registersSize; ++i) { 111 if (dvmIsValidObject((Object *)fp[i])) { 112 (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg); 113 } 114 } 115 } else { 116 /* 117 * Precise scan. v0 is at the lowest address on the 118 * interpreted stack, and is the first bit in the 119 * register vector, so we can walk through the 120 * register map and memory in the same direction. 121 * 122 * A '1' bit indicates a live reference. 123 */ 124 u2 bits = 1 << 1; 125 for (size_t i = 0; i < method->registersSize; ++i) { 126 bits >>= 1; 127 if (bits == 1) { 128 /* set bit 9 so we can tell when we're empty */ 129 bits = *regVector++ | 0x0100; 130 } 131 if ((bits & 0x1) != 0) { 132 /* 133 * Register is marked as live, it's a valid root. 134 */ 135#if WITH_EXTRA_GC_CHECKS 136 if (fp[i] != 0 && !dvmIsValidObject((Object *)fp[i])) { 137 /* this is very bad */ 138 LOGE("PGC: invalid ref in reg %d: %#x", 139 method->registersSize - 1 - i, fp[i]); 140 LOGE("PGC: %s.%s addr %#x", 141 method->clazz->descriptor, method->name, 142 saveArea->xtra.currentPc - method->insns); 143 continue; 144 } 145#endif 146 (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg); 147 } 148 } 149 dvmReleaseRegisterMapLine(pMap, regVector); 150 } 151 } 152 /* 153 * Don't fall into an infinite loop if things get corrupted. 154 */ 155 assert((uintptr_t)saveArea->prevFrame > (uintptr_t)fp || 156 saveArea->prevFrame == NULL); 157 } 158} 159 160/* 161 * Visits all roots associated with a thread. 162 */ 163static void visitThread(RootVisitor *visitor, Thread *thread, void *arg) 164{ 165 u4 threadId; 166 167 assert(visitor != NULL); 168 assert(thread != NULL); 169 threadId = thread->threadId; 170 (*visitor)(&thread->threadObj, threadId, ROOT_THREAD_OBJECT, arg); 171 (*visitor)(&thread->exception, threadId, ROOT_NATIVE_STACK, arg); 172 visitReferenceTable(visitor, &thread->internalLocalRefTable, threadId, ROOT_NATIVE_STACK, arg); 173 visitIndirectRefTable(visitor, &thread->jniLocalRefTable, threadId, ROOT_JNI_LOCAL, arg); 174 if (thread->jniMonitorRefTable.table != NULL) { 175 visitReferenceTable(visitor, &thread->jniMonitorRefTable, threadId, ROOT_JNI_MONITOR, arg); 176 } 177 visitThreadStack(visitor, thread, arg); 178} 179 180/* 181 * Visits all threads on the thread list. 182 */ 183static void visitThreads(RootVisitor *visitor, void *arg) 184{ 185 Thread *thread; 186 187 assert(visitor != NULL); 188 dvmLockThreadList(dvmThreadSelf()); 189 thread = gDvm.threadList; 190 while (thread) { 191 visitThread(visitor, thread, arg); 192 thread = thread->next; 193 } 194 dvmUnlockThreadList(); 195} 196 197static void visitPrimitiveTypes(RootVisitor *visitor, void *arg) 198{ 199 (*visitor)(&gDvm.typeVoid, 0, ROOT_STICKY_CLASS, arg); 200 (*visitor)(&gDvm.typeBoolean, 0, ROOT_STICKY_CLASS, arg); 201 (*visitor)(&gDvm.typeByte, 0, ROOT_STICKY_CLASS, arg); 202 (*visitor)(&gDvm.typeShort, 0, ROOT_STICKY_CLASS, arg); 203 (*visitor)(&gDvm.typeChar, 0, ROOT_STICKY_CLASS, arg); 204 (*visitor)(&gDvm.typeInt, 0, ROOT_STICKY_CLASS, arg); 205 (*visitor)(&gDvm.typeLong, 0, ROOT_STICKY_CLASS, arg); 206 (*visitor)(&gDvm.typeFloat, 0, ROOT_STICKY_CLASS, arg); 207 (*visitor)(&gDvm.typeDouble, 0, ROOT_STICKY_CLASS, arg); 208} 209 210/* 211 * Visits roots. TODO: visit cached global references. 212 */ 213void dvmVisitRoots(RootVisitor *visitor, void *arg) 214{ 215 assert(visitor != NULL); 216 visitHashTable(visitor, gDvm.loadedClasses, ROOT_STICKY_CLASS, arg); 217 visitPrimitiveTypes(visitor, arg); 218 if (gDvm.dbgRegistry != NULL) { 219 visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg); 220 } 221 if (gDvm.literalStrings != NULL) { 222 visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg); 223 } 224 dvmLockMutex(&gDvm.jniGlobalRefLock); 225 visitIndirectRefTable(visitor, &gDvm.jniGlobalRefTable, 0, ROOT_JNI_GLOBAL, arg); 226 dvmUnlockMutex(&gDvm.jniGlobalRefLock); 227 dvmLockMutex(&gDvm.jniPinRefLock); 228 visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg); 229 dvmUnlockMutex(&gDvm.jniPinRefLock); 230 visitThreads(visitor, arg); 231 (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg); 232 (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg); 233 (*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg); 234} 235