// Based on dvmResolveMethod. static void preloadDexCachesResolveMethod(DvmDex* pDvmDex, uint32_t methodIdx, MethodType methodType) { Method* method = dvmDexGetResolvedMethod(pDvmDex, methodIdx); if (method != NULL) { return; } const DexFile* pDexFile = pDvmDex->pDexFile; const DexMethodId* pMethodId = dexGetMethodId(pDexFile, methodIdx); ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pMethodId->classIdx); if (clazz == NULL) { return; } // Skip static methods for uninitialized classes because a filled // cache entry implies the class is initialized. if ((methodType == METHOD_STATIC) && !dvmIsClassInitialized(clazz)) { return; } const char* methodName = dexStringById(pDexFile, pMethodId->nameIdx); DexProto proto; dexProtoSetFromMethodId(&proto, pDexFile, pMethodId); if (methodType == METHOD_DIRECT) { method = dvmFindDirectMethod(clazz, methodName, &proto); } else if (methodType == METHOD_STATIC) { method = dvmFindDirectMethodHier(clazz, methodName, &proto); } else { method = dvmFindVirtualMethodHier(clazz, methodName, &proto); } if (method == NULL) { return; } // ALOGI("VMRuntime.preloadDexCaches found method %s.%s", // clazz->descriptor, methodName); dvmDexSetResolvedMethod(pDvmDex, methodIdx, method); }
/* * Find the method corresponding to "methodRef". * * We use "referrer" to find the DexFile with the constant pool that * "methodRef" is an index into. We also use its class loader. The method * being resolved may very well be in a different DEX file. * * If this is a static method, we ensure that the method's class is * initialized. */ Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx, MethodType methodType) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexMethodId* pMethodId; Method* resMethod; assert(methodType != METHOD_INTERFACE); LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx, referrer->descriptor); pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); resClass = dvmResolveClass(referrer, pMethodId->classIdx, false); if (resClass == NULL) { /* can't find the class that the method is a part of */ assert(dvmCheckException(dvmThreadSelf())); return NULL; } if (dvmIsInterfaceClass(resClass)) { /* method is part of an interface */ dvmThrowExceptionWithClassMessage( "Ljava/lang/IncompatibleClassChangeError;", resClass->descriptor); return NULL; } const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); DexProto proto; dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); /* * We need to chase up the class hierarchy to find methods defined * in super-classes. (We only want to check the current class * if we're looking for a constructor; since DIRECT calls are only * for constructors and private methods, we don't want to walk up.) */ if (methodType == METHOD_DIRECT) { resMethod = dvmFindDirectMethod(resClass, name, &proto); } else if (methodType == METHOD_STATIC) { resMethod = dvmFindDirectMethodHier(resClass, name, &proto); } else { resMethod = dvmFindVirtualMethodHier(resClass, name, &proto); } if (resMethod == NULL) { dvmThrowException("Ljava/lang/NoSuchMethodError;", name); return NULL; } LOGVV("--- found method %d (%s.%s)\n", methodIdx, resClass->descriptor, resMethod->name); /* see if this is a pure-abstract method */ if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { dvmThrowException("Ljava/lang/AbstractMethodError;", name); return NULL; } /* * If we're the first to resolve this class, we need to initialize * it now. Only necessary for METHOD_STATIC. */ if (methodType == METHOD_STATIC) { if (!dvmIsClassInitialized(resMethod->clazz) && !dvmInitClass(resMethod->clazz)) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } else { assert(!dvmCheckException(dvmThreadSelf())); } } else { /* * Edge case: if the <clinit> for a class creates an instance * of itself, we will call <init> on a class that is still being * initialized by us. */ assert(dvmIsClassInitialized(resMethod->clazz) || dvmIsClassInitializing(resMethod->clazz)); } /* * The class is initialized, the method has been found. Add a pointer * to our data structure so we don't have to jump through the hoops again. */ dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); return resMethod; }