merge in klp-release history after reset to klp-dev
diff --git a/vm/native/dalvik_system_VMRuntime.cpp b/vm/native/dalvik_system_VMRuntime.cpp
index 124c64f..002d014 100644
--- a/vm/native/dalvik_system_VMRuntime.cpp
+++ b/vm/native/dalvik_system_VMRuntime.cpp
@@ -18,12 +18,16 @@
* dalvik.system.VMRuntime
*/
#include "Dalvik.h"
-#include "alloc/HeapSource.h"
#include "ScopedPthreadMutexLock.h"
+#include "UniquePtr.h"
+#include "alloc/HeapSource.h"
+#include "alloc/Visit.h"
+#include "libdex/DexClass.h"
#include "native/InternalNativePriv.h"
#include <limits.h>
+#include <map>
/*
* public native float getTargetHeapUtilization()
@@ -234,6 +238,313 @@
RETURN_VOID();
}
+static DvmDex* getDvmDexFromClassPathEntry(ClassPathEntry* cpe) {
+ if (cpe->kind == kCpeDex) {
+ return ((RawDexFile*) cpe->ptr)->pDvmDex;
+ }
+ if (cpe->kind == kCpeJar) {
+ return ((JarFile*) cpe->ptr)->pDvmDex;
+ }
+ LOG_ALWAYS_FATAL("Unknown cpe->kind=%d", cpe->kind);
+}
+
+typedef std::map<std::string, StringObject*> StringTable;
+
+static void preloadDexCachesStringsVisitor(void* addr, u4 threadId, RootType type, void* arg) {
+ StringTable& table = *(StringTable*) arg;
+ StringObject* strObj = *(StringObject**) addr;
+ LOG_FATAL_IF(strObj->clazz != gDvm.classJavaLangString, "Unknown class for supposed string");
+ char* newStr = dvmCreateCstrFromString(strObj);
+ // ALOGI("VMRuntime.preloadDexCaches interned=%s", newStr);
+ table[newStr] = strObj;
+ free(newStr);
+}
+
+// Based on dvmResolveString.
+static void preloadDexCachesResolveString(DvmDex* pDvmDex,
+ uint32_t stringIdx,
+ StringTable& strings) {
+ StringObject* string = dvmDexGetResolvedString(pDvmDex, stringIdx);
+ if (string != NULL) {
+ return;
+ }
+ const DexFile* pDexFile = pDvmDex->pDexFile;
+ uint32_t utf16Size;
+ const char* utf8 = dexStringAndSizeById(pDexFile, stringIdx, &utf16Size);
+ string = strings[utf8];
+ if (string == NULL) {
+ return;
+ }
+ // ALOGI("VMRuntime.preloadDexCaches found string=%s", utf8);
+ dvmDexSetResolvedString(pDvmDex, stringIdx, string);
+}
+
+// Based on dvmResolveClass.
+static void preloadDexCachesResolveType(DvmDex* pDvmDex, uint32_t typeIdx) {
+ ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, typeIdx);
+ if (clazz != NULL) {
+ return;
+ }
+ const DexFile* pDexFile = pDvmDex->pDexFile;
+ const char* className = dexStringByTypeIdx(pDexFile, typeIdx);
+ if (className[0] != '\0' && className[1] == '\0') {
+ /* primitive type */
+ clazz = dvmFindPrimitiveClass(className[0]);
+ } else {
+ clazz = dvmLookupClass(className, NULL, true);
+ }
+ if (clazz == NULL) {
+ return;
+ }
+ // Skip uninitialized classes because filled cache entry implies it is initialized.
+ if (!dvmIsClassInitialized(clazz)) {
+ // ALOGI("VMRuntime.preloadDexCaches uninitialized clazz=%s", className);
+ return;
+ }
+ // ALOGI("VMRuntime.preloadDexCaches found clazz=%s", className);
+ dvmDexSetResolvedClass(pDvmDex, typeIdx, clazz);
+}
+
+// Based on dvmResolveInstField/dvmResolveStaticField.
+static void preloadDexCachesResolveField(DvmDex* pDvmDex, uint32_t fieldIdx, bool instance) {
+ Field* field = dvmDexGetResolvedField(pDvmDex, fieldIdx);
+ if (field != NULL) {
+ return;
+ }
+ const DexFile* pDexFile = pDvmDex->pDexFile;
+ const DexFieldId* pFieldId = dexGetFieldId(pDexFile, fieldIdx);
+ ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pFieldId->classIdx);
+ if (clazz == NULL) {
+ return;
+ }
+ // Skip static fields for uninitialized classes because a filled
+ // cache entry implies the class is initialized.
+ if (!instance && !dvmIsClassInitialized(clazz)) {
+ return;
+ }
+ const char* fieldName = dexStringById(pDexFile, pFieldId->nameIdx);
+ const char* signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+ if (instance) {
+ field = dvmFindInstanceFieldHier(clazz, fieldName, signature);
+ } else {
+ field = dvmFindStaticFieldHier(clazz, fieldName, signature);
+ }
+ if (field == NULL) {
+ return;
+ }
+ // ALOGI("VMRuntime.preloadDexCaches found field %s %s.%s",
+ // signature, clazz->descriptor, fieldName);
+ dvmDexSetResolvedField(pDvmDex, fieldIdx, field);
+}
+
+// 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);
+}
+
+struct DexCacheStats {
+ uint32_t numStrings;
+ uint32_t numTypes;
+ uint32_t numFields;
+ uint32_t numMethods;
+ DexCacheStats() : numStrings(0), numTypes(0), numFields(0), numMethods(0) {};
+};
+
+static const bool kPreloadDexCachesEnabled = true;
+
+// Disabled because it takes a long time (extra half second) but
+// gives almost no benefit in terms of saving private dirty pages.
+static const bool kPreloadDexCachesStrings = false;
+
+static const bool kPreloadDexCachesTypes = true;
+static const bool kPreloadDexCachesFieldsAndMethods = true;
+
+static const bool kPreloadDexCachesCollectStats = false;
+
+static void preloadDexCachesStatsTotal(DexCacheStats* total) {
+ if (!kPreloadDexCachesCollectStats) {
+ return;
+ }
+
+ for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
+ DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
+ const DexHeader* pHeader = pDvmDex->pHeader;
+ total->numStrings += pHeader->stringIdsSize;
+ total->numFields += pHeader->fieldIdsSize;
+ total->numMethods += pHeader->methodIdsSize;
+ total->numTypes += pHeader->typeIdsSize;
+ }
+}
+
+static void preloadDexCachesStatsFilled(DexCacheStats* filled) {
+ if (!kPreloadDexCachesCollectStats) {
+ return;
+ }
+ for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
+ DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
+ const DexHeader* pHeader = pDvmDex->pHeader;
+ for (size_t i = 0; i < pHeader->stringIdsSize; i++) {
+ StringObject* string = dvmDexGetResolvedString(pDvmDex, i);
+ if (string != NULL) {
+ filled->numStrings++;
+ }
+ }
+ for (size_t i = 0; i < pHeader->typeIdsSize; i++) {
+ ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, i);
+ if (clazz != NULL) {
+ filled->numTypes++;
+ }
+ }
+ for (size_t i = 0; i < pHeader->fieldIdsSize; i++) {
+ Field* field = dvmDexGetResolvedField(pDvmDex, i);
+ if (field != NULL) {
+ filled->numFields++;
+ }
+ }
+ for (size_t i = 0; i < pHeader->methodIdsSize; i++) {
+ Method* method = dvmDexGetResolvedMethod(pDvmDex, i);
+ if (method != NULL) {
+ filled->numMethods++;
+ }
+ }
+ }
+}
+
+static void Dalvik_dalvik_system_VMRuntime_preloadDexCaches(const u4* args, JValue* pResult)
+{
+ if (!kPreloadDexCachesEnabled) {
+ return;
+ }
+
+ DexCacheStats total;
+ DexCacheStats before;
+ if (kPreloadDexCachesCollectStats) {
+ ALOGI("VMRuntime.preloadDexCaches starting");
+ preloadDexCachesStatsTotal(&total);
+ preloadDexCachesStatsFilled(&before);
+ }
+
+ // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings
+ StringTable strings;
+ dvmLockMutex(&gDvm.internLock);
+ dvmHashTableLock(gDvm.literalStrings);
+ for (int i = 0; i < gDvm.literalStrings->tableSize; ++i) {
+ HashEntry *entry = &gDvm.literalStrings->pEntries[i];
+ if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
+ preloadDexCachesStringsVisitor(&entry->data, 0, ROOT_INTERNED_STRING, &strings);
+ }
+ }
+ dvmHashTableUnlock(gDvm.literalStrings);
+ dvmUnlockMutex(&gDvm.internLock);
+
+ for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
+ DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
+ const DexHeader* pHeader = pDvmDex->pHeader;
+ const DexFile* pDexFile = pDvmDex->pDexFile;
+
+ if (kPreloadDexCachesStrings) {
+ for (size_t i = 0; i < pHeader->stringIdsSize; i++) {
+ preloadDexCachesResolveString(pDvmDex, i, strings);
+ }
+ }
+
+ if (kPreloadDexCachesTypes) {
+ for (size_t i = 0; i < pHeader->typeIdsSize; i++) {
+ preloadDexCachesResolveType(pDvmDex, i);
+ }
+ }
+
+ if (kPreloadDexCachesFieldsAndMethods) {
+ for (size_t classDefIndex = 0;
+ classDefIndex < pHeader->classDefsSize;
+ classDefIndex++) {
+ const DexClassDef* pClassDef = dexGetClassDef(pDexFile, classDefIndex);
+ const u1* pEncodedData = dexGetClassData(pDexFile, pClassDef);
+ UniquePtr<DexClassData> pClassData(dexReadAndVerifyClassData(&pEncodedData, NULL));
+ if (pClassData.get() == NULL) {
+ continue;
+ }
+ for (uint32_t fieldIndex = 0;
+ fieldIndex < pClassData->header.staticFieldsSize;
+ fieldIndex++) {
+ const DexField* pField = &pClassData->staticFields[fieldIndex];
+ preloadDexCachesResolveField(pDvmDex, pField->fieldIdx, false);
+ }
+ for (uint32_t fieldIndex = 0;
+ fieldIndex < pClassData->header.instanceFieldsSize;
+ fieldIndex++) {
+ const DexField* pField = &pClassData->instanceFields[fieldIndex];
+ preloadDexCachesResolveField(pDvmDex, pField->fieldIdx, true);
+ }
+ for (uint32_t methodIndex = 0;
+ methodIndex < pClassData->header.directMethodsSize;
+ methodIndex++) {
+ const DexMethod* pDexMethod = &pClassData->directMethods[methodIndex];
+ MethodType methodType = (((pDexMethod->accessFlags & ACC_STATIC) != 0) ?
+ METHOD_STATIC :
+ METHOD_DIRECT);
+ preloadDexCachesResolveMethod(pDvmDex, pDexMethod->methodIdx, methodType);
+ }
+ for (uint32_t methodIndex = 0;
+ methodIndex < pClassData->header.virtualMethodsSize;
+ methodIndex++) {
+ const DexMethod* pDexMethod = &pClassData->virtualMethods[methodIndex];
+ preloadDexCachesResolveMethod(pDvmDex, pDexMethod->methodIdx, METHOD_VIRTUAL);
+ }
+ }
+ }
+ }
+
+ if (kPreloadDexCachesCollectStats) {
+ DexCacheStats after;
+ preloadDexCachesStatsFilled(&after);
+ ALOGI("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d",
+ total.numStrings, before.numStrings, after.numStrings);
+ ALOGI("VMRuntime.preloadDexCaches types total=%d before=%d after=%d",
+ total.numTypes, before.numTypes, after.numTypes);
+ ALOGI("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d",
+ total.numFields, before.numFields, after.numFields);
+ ALOGI("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d",
+ total.numMethods, before.numMethods, after.numMethods);
+ ALOGI("VMRuntime.preloadDexCaches finished");
+ }
+
+ RETURN_VOID();
+}
+
const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
{ "addressOf", "(Ljava/lang/Object;)J",
Dalvik_dalvik_system_VMRuntime_addressOf },
@@ -267,5 +578,7 @@
Dalvik_dalvik_system_VMRuntime_registerNativeAllocation },
{ "registerNativeFree", "(I)V",
Dalvik_dalvik_system_VMRuntime_registerNativeFree },
+ { "preloadDexCaches", "()V",
+ Dalvik_dalvik_system_VMRuntime_preloadDexCaches },
{ NULL, NULL, NULL },
};