diff options
-rw-r--r-- | runtime/class_linker.cc | 24 | ||||
-rw-r--r-- | runtime/class_linker.h | 4 | ||||
-rw-r--r-- | runtime/dex_file.h | 2 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMRuntime.cc | 316 | ||||
-rw-r--r-- | runtime/runtime.h | 1 |
5 files changed, 329 insertions, 18 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f07282040c..db4cc00a8b 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4002,11 +4002,11 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, } mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, - uint32_t method_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, - const mirror::ArtMethod* referrer, - InvokeType type) { + uint32_t method_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + const mirror::ArtMethod* referrer, + InvokeType type) { DCHECK(dex_cache != NULL); // Check for hit in the dex cache. mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); @@ -4149,10 +4149,10 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, } mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, - uint32_t field_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, - bool is_static) { + uint32_t field_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + bool is_static) { DCHECK(dex_cache != NULL); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); if (resolved != NULL) { @@ -4189,9 +4189,9 @@ mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, } mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, - uint32_t field_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader) { + uint32_t field_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader) { DCHECK(dex_cache != NULL); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); if (resolved != NULL) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index baeec66f79..11ba78b36a 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -346,10 +346,6 @@ class ClassLinker { return quick_resolution_trampoline_; } - InternTable* GetInternTable() const { - return intern_table_; - } - // Attempts to insert a class into a class table. Returns NULL if // the class was inserted, otherwise returns an existing class with // the same descriptor and ClassLoader. diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 346154cc89..cef4ce4b87 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -33,6 +33,8 @@ namespace art { +// TODO: remove dependencies on mirror classes, primarily by moving +// EncodedStaticFieldValueIterator to its own file. namespace mirror { class ArtField; class ArtMethod; diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 5fc8bd5a48..cb7828b9a4 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -20,12 +20,15 @@ #include "common_throws.h" #include "debugger.h" #include "dex_file-inl.h" +#include "gc/accounting/card_table-inl.h" #include "gc/allocator/dlmalloc.h" #include "gc/heap.h" #include "gc/space/dlmalloc_space.h" +#include "intern_table.h" #include "jni_internal.h" +#include "mirror/art_method-inl.h" #include "mirror/class-inl.h" -#include "mirror/object.h" +#include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" #include "object_utils.h" #include "scoped_thread_state_change.h" @@ -49,7 +52,10 @@ static void VMRuntime_startJitCompilation(JNIEnv*, jobject) { static void VMRuntime_disableJitCompilation(JNIEnv*, jobject) { } -static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass, jint length) { +static jobject VMRuntime_newNonMovableArray(JNIEnv* env, + jobject, + jclass javaElementClass, + jint length) { ScopedObjectAccess soa(env); #ifdef MOVING_GARBAGE_COLLECTOR // TODO: right now, we don't have a copying collector, so there's no need @@ -196,6 +202,311 @@ static void VMRuntime_concurrentGC(JNIEnv* env, jobject) { Runtime::Current()->GetHeap()->ConcurrentGC(self); } +typedef std::map<std::string, mirror::String*> StringTable; + +static void PreloadDexCachesStringsVisitor(const mirror::Object* root, void* arg) { + StringTable& table = *reinterpret_cast<StringTable*>(arg); + mirror::String* string = const_cast<mirror::Object*>(root)->AsString(); + // LOG(INFO) << "VMRuntime.preloadDexCaches interned=" << string->ToModifiedUtf8(); + table[string->ToModifiedUtf8()] = string; +} + +// Based on ClassLinker::ResolveString. +static void PreloadDexCachesResolveString(mirror::DexCache* dex_cache, + uint32_t string_idx, + StringTable& strings) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* string = dex_cache->GetResolvedString(string_idx); + if (string != NULL) { + return; + } + const DexFile* dex_file = dex_cache->GetDexFile(); + uint32_t utf16Size; + const char* utf8 = dex_file->StringDataAndLengthByIdx(string_idx, &utf16Size); + string = strings[utf8]; + if (string == NULL) { + return; + } + // LOG(INFO) << "VMRuntime.preloadDexCaches resolved string=" << utf8; + dex_cache->SetResolvedString(string_idx, string); +} + +// Based on ClassLinker::ResolveType. +static void PreloadDexCachesResolveType(mirror::DexCache* dex_cache, uint32_t type_idx) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Class* klass = dex_cache->GetResolvedType(type_idx); + if (klass != NULL) { + return; + } + const DexFile* dex_file = dex_cache->GetDexFile(); + const char* class_name = dex_file->StringByTypeIdx(type_idx); + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + if (class_name[1] == '\0') { + klass = linker->FindPrimitiveClass(class_name[0]); + } else { + klass = linker->LookupClass(class_name, NULL); + } + if (klass == NULL) { + return; + } + // LOG(INFO) << "VMRuntime.preloadDexCaches resolved klass=" << class_name; + dex_cache->SetResolvedType(type_idx, klass); + // Skip uninitialized classes because filled static storage entry implies it is initialized. + if (!klass->IsInitialized()) { + // LOG(INFO) << "VMRuntime.preloadDexCaches uninitialized klass=" << class_name; + return; + } + // LOG(INFO) << "VMRuntime.preloadDexCaches static storage klass=" << class_name; + dex_cache->GetInitializedStaticStorage()->Set(type_idx, klass); +} + +// Based on ClassLinker::ResolveField. +static void PreloadDexCachesResolveField(mirror::DexCache* dex_cache, + uint32_t field_idx, + bool is_static) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtField* field = dex_cache->GetResolvedField(field_idx); + if (field != NULL) { + return; + } + const DexFile* dex_file = dex_cache->GetDexFile(); + const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx); + mirror::Class* klass = dex_cache->GetResolvedType(field_id.class_idx_); + if (klass == NULL) { + return; + } + if (is_static) { + field = klass->FindStaticField(dex_cache, field_idx); + } else { + field = klass->FindInstanceField(dex_cache, field_idx); + } + if (field == NULL) { + return; + } + // LOG(INFO) << "VMRuntime.preloadDexCaches resolved field " << PrettyField(field); + dex_cache->SetResolvedField(field_idx, field); +} + +// Based on ClassLinker::ResolveMethod. +static void PreloadDexCachesResolveMethod(mirror::DexCache* dex_cache, + uint32_t method_idx, + InvokeType invoke_type) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx); + if (method != NULL) { + return; + } + const DexFile* dex_file = dex_cache->GetDexFile(); + const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx); + mirror::Class* klass = dex_cache->GetResolvedType(method_id.class_idx_); + if (klass == NULL) { + return; + } + switch (invoke_type) { + case kDirect: + case kStatic: + method = klass->FindDirectMethod(dex_cache, method_idx); + break; + case kInterface: + method = klass->FindInterfaceMethod(dex_cache, method_idx); + break; + case kSuper: + case kVirtual: + method = klass->FindVirtualMethod(dex_cache, method_idx); + break; + default: + LOG(FATAL) << "Unreachable - invocation type: " << invoke_type; + } + if (method == NULL) { + return; + } + // LOG(INFO) << "VMRuntime.preloadDexCaches resolved method " << PrettyMethod(method); + dex_cache->SetResolvedMethod(method_idx, method); +} + +struct DexCacheStats { + uint32_t num_strings; + uint32_t num_types; + uint32_t num_fields; + uint32_t num_methods; + uint32_t num_static_storage; + DexCacheStats() : num_strings(0), + num_types(0), + num_fields(0), + num_methods(0), + num_static_storage(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 = true; + +static void PreloadDexCachesStatsTotal(DexCacheStats* total) { + if (!kPreloadDexCachesCollectStats) { + return; + } + + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath(); + for (size_t i = 0; i< boot_class_path.size(); i++) { + const DexFile* dex_file = boot_class_path[i]; + CHECK(dex_file != NULL); + total->num_strings += dex_file->NumStringIds(); + total->num_fields += dex_file->NumFieldIds(); + total->num_methods += dex_file->NumMethodIds(); + total->num_types += dex_file->NumTypeIds(); + total->num_static_storage += dex_file->NumTypeIds(); + } +} + +static void PreloadDexCachesStatsFilled(DexCacheStats* filled) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (!kPreloadDexCachesCollectStats) { + return; + } + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath(); + for (size_t i = 0; i< boot_class_path.size(); i++) { + const DexFile* dex_file = boot_class_path[i]; + CHECK(dex_file != NULL); + mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file); + for (size_t i = 0; i < dex_cache->NumStrings(); i++) { + mirror::String* string = dex_cache->GetResolvedString(i); + if (string != NULL) { + filled->num_strings++; + } + } + for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { + mirror::Class* klass = dex_cache->GetResolvedType(i); + if (klass != NULL) { + filled->num_types++; + } + } + for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { + mirror::ArtField* field = dex_cache->GetResolvedField(i); + if (field != NULL) { + filled->num_fields++; + } + } + for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) { + mirror::ArtMethod* method = dex_cache->GetResolvedMethod(i); + if (method != NULL) { + filled->num_methods++; + } + } + for (size_t i = 0; i < dex_cache->NumInitializedStaticStorage(); i++) { + mirror::StaticStorageBase* klass = dex_cache->GetInitializedStaticStorage()->Get(i); + if (klass != NULL) { + filled->num_static_storage++; + } + } + } +} + +// TODO: http://b/11309598 This code was ported over based on the +// Dalvik version. However, ART has similar code in other places such +// as the CompilerDriver. This code could probably be refactored to +// serve both uses. +static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) { + if (!kPreloadDexCachesEnabled) { + return; + } + + ScopedObjectAccess soa(env); + + DexCacheStats total; + DexCacheStats before; + if (kPreloadDexCachesCollectStats) { + LOG(INFO) << "VMRuntime.preloadDexCaches starting"; + PreloadDexCachesStatsTotal(&total); + PreloadDexCachesStatsFilled(&before); + } + + Runtime* runtime = Runtime::Current(); + ClassLinker* linker = runtime->GetClassLinker(); + + // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings + StringTable strings; + if (kPreloadDexCachesStrings) { + runtime->GetInternTable()->VisitRoots(PreloadDexCachesStringsVisitor, &strings, false, false); + } + + const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath(); + for (size_t i = 0; i< boot_class_path.size(); i++) { + const DexFile* dex_file = boot_class_path[i]; + CHECK(dex_file != NULL); + mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file); + + if (kPreloadDexCachesStrings) { + for (size_t i = 0; i < dex_cache->NumStrings(); i++) { + PreloadDexCachesResolveString(dex_cache, i, strings); + } + } + + if (kPreloadDexCachesTypes) { + for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { + PreloadDexCachesResolveType(dex_cache, i); + } + } + + if (kPreloadDexCachesFieldsAndMethods) { + for (size_t class_def_index = 0; + class_def_index < dex_file->NumClassDefs(); + class_def_index++) { + const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); + const byte* class_data = dex_file->GetClassData(class_def); + if (class_data == NULL) { + continue; + } + ClassDataItemIterator it(*dex_file, class_data); + for (; it.HasNextStaticField(); it.Next()) { + uint32_t field_idx = it.GetMemberIndex(); + PreloadDexCachesResolveField(dex_cache, field_idx, true); + } + for (; it.HasNextInstanceField(); it.Next()) { + uint32_t field_idx = it.GetMemberIndex(); + PreloadDexCachesResolveField(dex_cache, field_idx, false); + } + for (; it.HasNextDirectMethod(); it.Next()) { + uint32_t method_idx = it.GetMemberIndex(); + InvokeType invoke_type = it.GetMethodInvokeType(class_def); + PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type); + } + for (; it.HasNextVirtualMethod(); it.Next()) { + uint32_t method_idx = it.GetMemberIndex(); + InvokeType invoke_type = it.GetMethodInvokeType(class_def); + PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type); + } + } + } + } + + if (kPreloadDexCachesCollectStats) { + DexCacheStats after; + PreloadDexCachesStatsFilled(&after); + LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d", + total.num_strings, before.num_strings, after.num_strings); + LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches types total=%d before=%d after=%d", + total.num_types, before.num_types, after.num_types); + LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d", + total.num_fields, before.num_fields, after.num_fields); + LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d", + total.num_methods, before.num_methods, after.num_methods); + LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches storage total=%d before=%d after=%d", + total.num_static_storage, + before.num_static_storage, + after.num_static_storage); + LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches finished"); + } +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"), NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"), @@ -215,6 +526,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMRuntime, trimHeap, "()V"), NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"), NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"), + NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"), }; void register_dalvik_system_VMRuntime(JNIEnv* env) { diff --git a/runtime/runtime.h b/runtime/runtime.h index bc5c8b00a8..7c2847949a 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -279,6 +279,7 @@ class Runtime { } InternTable* GetInternTable() const { + DCHECK(intern_table_ != NULL); return intern_table_; } |