From 8a39e7fe02e9a81853dc7a75cb50d9ece07a9b37 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Thu, 4 Sep 2014 18:33:17 -0700 Subject: [PATCH] Add fast path for FindClass using the type dex file. If we are using the PathClassLoader with a BootClassLoader parent, we can handle the common case in the FindClass function without needing to go back to java code. Around 10% speedup measured of maps launch, could be noise due to large variation of app launch times. Eliminates defineClassNative from being anywhere near the top of sampling profiles. Bug: 17397179 Bug: 16828525 Change-Id: Ide0db2b5f6cf5b96fc46e89178e0799de667cb88 --- runtime/class_linker.cc | 82 ++++++++++++++++++++++++++++++++++++++++++- runtime/mirror/class_loader.h | 3 ++ runtime/well_known_classes.cc | 16 +++++++++ runtime/well_known_classes.h | 8 +++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0d0c6cad3..eff2f6f4c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1961,7 +1961,6 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, // The boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); if (pair.second != nullptr) { - StackHandleScope<1> hs(self); return DefineClass(descriptor, NullHandle(), *pair.first, *pair.second); } else { // The boot class loader is searched ahead of the application class loader, failures are @@ -2000,6 +1999,87 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, } } else { ScopedObjectAccessUnchecked soa(self); + if (class_loader->GetClass() == + soa.Decode(WellKnownClasses::dalvik_system_PathClassLoader) && + class_loader->GetParent()->GetClass() == + soa.Decode(WellKnownClasses::java_lang_BootClassLoader)) { + ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); + // Check if this would be found in the parent boot class loader. + if (pair.second != nullptr) { + mirror::Class* klass = LookupClass(descriptor, nullptr); + if (klass != nullptr) { + return klass; + } + klass = DefineClass(descriptor, NullHandle(), *pair.first, + *pair.second); + if (klass == nullptr) { + CHECK(self->IsExceptionPending()) << descriptor; + self->ClearException(); + } else { + return klass; + } + } else { + // RegisterDexFile may allocate dex caches (and cause thread suspension). + StackHandleScope<3> hs(self); + // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. + // We need to get the DexPathList and loop through it. + Handle cookie_field = + hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie)); + Handle dex_file_field = + hs.NewHandle( + soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList$Element_dexFile)); + mirror::Object* dex_path_list = + soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)-> + GetObject(class_loader.Get()); + if (dex_path_list != nullptr && dex_file_field.Get() != nullptr && + cookie_field.Get() != nullptr) { + // DexPathList has an array dexElements of Elements[] which each contain a dex file. + mirror::Object* dex_elements_obj = + soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> + GetObject(dex_path_list); + // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look + // at the mCookie which is a DexFile vector. + if (dex_elements_obj != nullptr) { + Handle> dex_elements = + hs.NewHandle(dex_elements_obj->AsObjectArray()); + for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { + mirror::Object* element = dex_elements->GetWithoutChecks(i); + if (element == nullptr) { + // Should never happen, fall back to java code to throw a NPE. + break; + } + mirror::Object* dex_file = dex_file_field->GetObject(element); + if (dex_file != nullptr) { + const uint64_t cookie = cookie_field->GetLong(dex_file); + auto* dex_files = + reinterpret_cast*>(static_cast(cookie)); + if (dex_files == nullptr) { + // This should never happen so log a warning. + LOG(WARNING) << "Null DexFile::mCookie for " << descriptor; + break; + } + for (const DexFile* dex_file : *dex_files) { + const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor); + if (dex_class_def != nullptr) { + RegisterDexFile(*dex_file); + mirror::Class* klass = + DefineClass(descriptor, class_loader, *dex_file, *dex_class_def); + if (klass == nullptr) { + CHECK(self->IsExceptionPending()) << descriptor; + self->ClearException(); + // Exit the loop to make the java code generate an exception. + i = dex_elements->GetLength(); + break; + } + return klass; + } + } + } + } + } + } + } + } ScopedLocalRef class_loader_object(soa.Env(), soa.AddLocalReference(class_loader.Get())); std::string class_name_string(DescriptorToDot(descriptor)); diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h index f3594e40d..ff2ad8923 100644 --- a/runtime/mirror/class_loader.h +++ b/runtime/mirror/class_loader.h @@ -32,6 +32,9 @@ class MANAGED ClassLoader : public Object { static constexpr uint32_t InstanceSize() { return sizeof(ClassLoader); } + ClassLoader* GetParent() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject(OFFSET_OF_OBJECT_MEMBER(ClassLoader, parent_)); + } private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 3a6a72b84..7068a4d5b 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -26,7 +26,11 @@ namespace art { jclass WellKnownClasses::com_android_dex_Dex; +jclass WellKnownClasses::dalvik_system_DexFile; +jclass WellKnownClasses::dalvik_system_DexPathList; +jclass WellKnownClasses::dalvik_system_DexPathList$Element; jclass WellKnownClasses::dalvik_system_PathClassLoader; +jclass WellKnownClasses::java_lang_BootClassLoader; jclass WellKnownClasses::java_lang_ClassLoader; jclass WellKnownClasses::java_lang_ClassNotFoundException; jclass WellKnownClasses::java_lang_Daemons; @@ -79,6 +83,10 @@ jmethodID WellKnownClasses::java_nio_DirectByteBuffer_init; jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_broadcast; jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch; +jfieldID WellKnownClasses::dalvik_system_DexFile_cookie; +jfieldID WellKnownClasses::dalvik_system_PathClassLoader_pathList; +jfieldID WellKnownClasses::dalvik_system_DexPathList_dexElements; +jfieldID WellKnownClasses::dalvik_system_DexPathList$Element_dexFile; jfieldID WellKnownClasses::java_lang_Thread_daemon; jfieldID WellKnownClasses::java_lang_Thread_group; jfieldID WellKnownClasses::java_lang_Thread_lock; @@ -131,7 +139,11 @@ static jmethodID CachePrimitiveBoxingMethod(JNIEnv* env, char prim_name, const c void WellKnownClasses::Init(JNIEnv* env) { com_android_dex_Dex = CacheClass(env, "com/android/dex/Dex"); + dalvik_system_DexFile = CacheClass(env, "dalvik/system/DexFile"); + dalvik_system_DexPathList = CacheClass(env, "dalvik/system/DexPathList"); + dalvik_system_DexPathList$Element = CacheClass(env, "dalvik/system/DexPathList$Element"); dalvik_system_PathClassLoader = CacheClass(env, "dalvik/system/PathClassLoader"); + java_lang_BootClassLoader = CacheClass(env, "java/lang/BootClassLoader"); java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader"); java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException"); java_lang_Daemons = CacheClass(env, "java/lang/Daemons"); @@ -179,6 +191,10 @@ void WellKnownClasses::Init(JNIEnv* env) { org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V"); org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;"); + dalvik_system_DexFile_cookie = CacheField(env, dalvik_system_DexFile, false, "mCookie", "J"); + dalvik_system_PathClassLoader_pathList = CacheField(env, dalvik_system_PathClassLoader, false, "pathList", "Ldalvik/system/DexPathList;"); + dalvik_system_DexPathList_dexElements = CacheField(env, dalvik_system_DexPathList, false, "dexElements", "[Ldalvik/system/DexPathList$Element;"); + dalvik_system_DexPathList$Element_dexFile = CacheField(env, dalvik_system_DexPathList$Element, false, "dexFile", "Ldalvik/system/DexFile;"); java_lang_Thread_daemon = CacheField(env, java_lang_Thread, false, "daemon", "Z"); java_lang_Thread_group = CacheField(env, java_lang_Thread, false, "group", "Ljava/lang/ThreadGroup;"); java_lang_Thread_lock = CacheField(env, java_lang_Thread, false, "lock", "Ljava/lang/Object;"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 7639f50c6..b10106c0b 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -40,7 +40,11 @@ struct WellKnownClasses { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static jclass com_android_dex_Dex; + static jclass dalvik_system_DexFile; + static jclass dalvik_system_DexPathList; + static jclass dalvik_system_DexPathList$Element; static jclass dalvik_system_PathClassLoader; + static jclass java_lang_BootClassLoader; static jclass java_lang_ClassLoader; static jclass java_lang_ClassNotFoundException; static jclass java_lang_Daemons; @@ -93,6 +97,10 @@ struct WellKnownClasses { static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_broadcast; static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_dispatch; + static jfieldID dalvik_system_DexFile_cookie; + static jfieldID dalvik_system_DexPathList_dexElements; + static jfieldID dalvik_system_DexPathList$Element_dexFile; + static jfieldID dalvik_system_PathClassLoader_pathList; static jfieldID java_lang_reflect_AbstractMethod_artMethod; static jfieldID java_lang_reflect_Field_artField; static jfieldID java_lang_reflect_Proxy_h; -- 2.11.0