/* * Visits all stack slots except those belonging to native method * arguments. */ static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg) { assert(visitor != NULL); assert(thread != NULL); u4 threadId = thread->threadId; const StackSaveArea *saveArea; for (u4 *fp = (u4 *)thread->interpSave.curFrame; fp != NULL; fp = (u4 *)saveArea->prevFrame) { Method *method; saveArea = SAVEAREA_FROM_FP(fp); method = (Method *)saveArea->method; if (method != NULL && !dvmIsNativeMethod(method)) { #ifdef FASTIVA // @zee do not call any malloc in gc task. // cf) dvmGetExpandedRegisterMap() const RegisterMap* pMap = NULL; #else const RegisterMap* pMap = dvmGetExpandedRegisterMap(method); #endif const u1* regVector = NULL; #ifndef FASTIVA if (pMap != NULL) { /* found map, get registers for this address */ int addr = saveArea->xtra.currentPc - method->insns; regVector = dvmRegisterMapGetLine(pMap, addr); } #endif if (regVector == NULL) { /* * Either there was no register map or there is no * info for the current PC. Perform a conservative * scan. */ for (size_t i = 0; i < method->registersSize; ++i) { if (dvmIsValidObject((Object *)fp[i])) { (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, 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 (size_t 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. */ #if WITH_EXTRA_GC_CHECKS if (fp[i] != 0 && !dvmIsValidObject((Object *)fp[i])) { /* this is very bad */ ALOGE("PGC: invalid ref in reg %d: %#x", method->registersSize - 1 - i, fp[i]); ALOGE("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); } } dvmReleaseRegisterMapLine(pMap, regVector); } } /* * Don't fall into an infinite loop if things get corrupted. */ assert((uintptr_t)saveArea->prevFrame > (uintptr_t)fp || saveArea->prevFrame == NULL); } #ifdef FASTIVA int* stack_bottom = (int*)thread->m_pNativeStackBottom; int* stack_top = (int*)thread->m_pNativeStackPointer; const bool DUMP_STACK = 0; if (DUMP_STACK) { ALOGE("##### scan_stack %i %p~%p", thread->systemTid, stack_top, stack_bottom); } assert(thread->status != THREAD_RUNNING || thread == dvmThreadSelf()); while (stack_top < stack_bottom) { if (dvmIsValidObject((Object*)stack_top[0])) { (*visitor)(stack_top, threadId, ROOT_JAVA_FRAME, arg); } stack_top ++; } #endif }
/* * static boolean cacheRegisterMap(String classAndMethodDescr) * * If the specified class is loaded, and the named method exists, ensure * that the method's register map is ready for use. If the class/method * cannot be found, nothing happens. * * This can improve the zygote's sharing of compressed register maps. Do * this after class preloading. * * Returns true if the register map is cached and ready, either as a result * of this call or earlier activity. Returns false if the class isn't loaded, * if the method couldn't be found, or if the method has no register map. * * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.) */ static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args, JValue* pResult) { StringObject* classAndMethodDescStr = (StringObject*) args[0]; ClassObject* clazz; bool result = false; if (classAndMethodDescStr == NULL) { dvmThrowNullPointerException("classAndMethodDesc == null"); RETURN_VOID(); } char* classAndMethodDesc = NULL; /* * Pick the string apart. We have a local copy, so just modify it * in place. */ classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr); char* methodName = strchr(classAndMethodDesc, '.'); if (methodName == NULL) { dvmThrowRuntimeException("method name not found in string"); RETURN_VOID(); } *methodName++ = '\0'; char* methodDescr = strchr(methodName, ':'); if (methodDescr == NULL) { dvmThrowRuntimeException("method descriptor not found in string"); RETURN_VOID(); } *methodDescr++ = '\0'; //ALOGD("GOT: %s %s %s", classAndMethodDesc, methodName, methodDescr); /* * Find the class, but only if it's already loaded. */ clazz = dvmLookupClass(classAndMethodDesc, NULL, false); if (clazz == NULL) { ALOGD("Class %s not found in bootstrap loader", classAndMethodDesc); goto bail; } Method* method; /* * Find the method, which could be virtual or direct, defined directly * or inherited. */ if (methodName[0] == '<') { /* * Constructor or class initializer. Only need to examine the * "direct" list, and don't need to search up the class hierarchy. */ method = dvmFindDirectMethodByDescriptor(clazz, methodName, methodDescr); } else { /* * Try both lists, and scan up the tree. */ method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName, methodDescr); if (method == NULL) { method = dvmFindDirectMethodHierByDescriptor(clazz, methodName, methodDescr); } } if (method != NULL) { /* * Got it. See if there's a register map here. */ const RegisterMap* pMap; pMap = dvmGetExpandedRegisterMap(method); if (pMap == NULL) { ALOGV("No map for %s.%s %s", classAndMethodDesc, methodName, methodDescr); } else { ALOGV("Found map %s.%s %s", classAndMethodDesc, methodName, methodDescr); result = true; } } else { ALOGV("Unable to find %s.%s %s", classAndMethodDesc, methodName, methodDescr); } bail: free(classAndMethodDesc); RETURN_BOOLEAN(result); }
/* * 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); } }