OSDN Git Service

Add fast path for FindClass using the type dex file.
authorMathieu Chartier <mathieuc@google.com>
Fri, 5 Sep 2014 01:33:17 +0000 (18:33 -0700)
committerMathieu Chartier <mathieuc@google.com>
Tue, 9 Sep 2014 00:44:56 +0000 (17:44 -0700)
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
runtime/mirror/class_loader.h
runtime/well_known_classes.cc
runtime/well_known_classes.h

index 0d0c6ca..eff2f6f 100644 (file)
@@ -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<mirror::ClassLoader>(), *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<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) &&
+        class_loader->GetParent()->GetClass() ==
+            soa.Decode<mirror::Class*>(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<mirror::ClassLoader>(), *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<mirror::ArtField> cookie_field =
+            hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
+        Handle<mirror::ArtField> 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<mirror::ObjectArray<mirror::Object>> dex_elements =
+                hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
+            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<std::vector<const DexFile*>*>(static_cast<uintptr_t>(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<jobject> class_loader_object(soa.Env(),
                                                 soa.AddLocalReference<jobject>(class_loader.Get()));
     std::string class_name_string(DescriptorToDot(descriptor));
index f3594e4..ff2ad89 100644 (file)
@@ -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<ClassLoader>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, parent_));
+  }
 
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
index 3a6a72b..7068a4d 100644 (file)
 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;");
index 7639f50..b10106c 100644 (file)
@@ -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;