ART: Refactor class-linker methods

Hide the LookupClass with hash version. Clients should not have to
know about that performance detail.

Hide FindClassInPathClassLoader. This is an implementation detail.

Test: m test-art-host
Change-Id: I2378c6fed8d7d1fb1ead8e042b4cf07228adf25c
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 439849b..f29ed1f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2237,8 +2237,7 @@
     }
     CHECK(h_class->IsRetired());
     // Get the updated class from class table.
-    klass = LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor),
-                        h_class.Get()->GetClassLoader());
+    klass = LookupClass(self, descriptor, h_class.Get()->GetClassLoader());
   }
 
   // Wait for the class if it has not already been linked.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 239e973..f2bf581 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -171,20 +171,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!dex_lock_);
 
-  // Finds a class in the path class loader, loading it if necessary without using JNI. Hash
-  // function is supposed to be ComputeModifiedUtf8Hash(descriptor). Returns true if the
-  // class-loader chain could be handled, false otherwise, i.e., a non-supported class-loader
-  // was encountered while walking the parent chain (currently only BootClassLoader and
-  // PathClassLoader are supported).
-  bool FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
-                                  Thread* self,
-                                  const char* descriptor,
-                                  size_t hash,
-                                  Handle<mirror::ClassLoader> class_loader,
-                                  ObjPtr<mirror::Class>* result)
-      REQUIRES_SHARED(Locks::mutator_lock_)
-      REQUIRES(!dex_lock_);
-
   // Finds a class by its descriptor using the "system" class loader, ie by searching the
   // boot_class_path_.
   mirror::Class* FindSystemClass(Thread* self, const char* descriptor)
@@ -215,10 +201,11 @@
   // by the given 'class_loader'.
   mirror::Class* LookupClass(Thread* self,
                              const char* descriptor,
-                             size_t hash,
                              ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES(!Locks::classlinker_classes_lock_)
-      REQUIRES_SHARED(Locks::mutator_lock_);
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    return LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor), class_loader);
+  }
 
   // Finds all the classes with the given descriptor, regardless of ClassLoader.
   void LookupClasses(const char* descriptor, std::vector<ObjPtr<mirror::Class>>& classes)
@@ -804,6 +791,29 @@
 
   void FixupStaticTrampolines(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Finds a class in the path class loader, loading it if necessary without using JNI. Hash
+  // function is supposed to be ComputeModifiedUtf8Hash(descriptor). Returns true if the
+  // class-loader chain could be handled, false otherwise, i.e., a non-supported class-loader
+  // was encountered while walking the parent chain (currently only BootClassLoader and
+  // PathClassLoader are supported).
+  bool FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
+                                  Thread* self,
+                                  const char* descriptor,
+                                  size_t hash,
+                                  Handle<mirror::ClassLoader> class_loader,
+                                  ObjPtr<mirror::Class>* result)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!dex_lock_);
+
+  // Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
+  // by the given 'class_loader'. Uses the provided hash for the descriptor.
+  mirror::Class* LookupClass(Thread* self,
+                             const char* descriptor,
+                             size_t hash,
+                             ObjPtr<mirror::ClassLoader> class_loader)
+      REQUIRES(!Locks::classlinker_classes_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       REQUIRES(dex_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -1187,6 +1197,7 @@
   friend struct CompilationHelper;  // For Compile in ImageTest.
   friend class ImageDumper;  // for DexLock
   friend class ImageWriter;  // for GetClassRoots
+  friend class VMClassLoader;  // for LookupClass and FindClassInPathClassLoader.
   friend class JniCompilerTest;  // for GetRuntimeQuickGenericJniStub
   friend class JniInternalTest;  // for GetRuntimeQuickGenericJniStub
   ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for DexLock, and RegisterDexFileLocked
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 5421410..866dc7f 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -317,7 +317,7 @@
   if (class_name[1] == '\0') {
     klass = linker->FindPrimitiveClass(class_name[0]);
   } else {
-    klass = linker->LookupClass(self, class_name, ComputeModifiedUtf8Hash(class_name), nullptr);
+    klass = linker->LookupClass(self, class_name, nullptr);
   }
   if (klass == nullptr) {
     return;
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index ff08284..e5bab36 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -20,12 +20,41 @@
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
+#include "obj_ptr.h"
 #include "scoped_fast_native_object_access-inl.h"
 #include "ScopedUtfChars.h"
 #include "zip_archive.h"
 
 namespace art {
 
+// A class so we can be friends with ClassLinker and access internal methods.
+class VMClassLoader {
+ public:
+  static mirror::Class* LookupClass(ClassLinker* cl,
+                                    Thread* self,
+                                    const char* descriptor,
+                                    size_t hash,
+                                    ObjPtr<mirror::ClassLoader> class_loader)
+      REQUIRES(!Locks::classlinker_classes_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    return cl->LookupClass(self, descriptor, hash, class_loader);
+  }
+
+  static ObjPtr<mirror::Class> FindClassInPathClassLoader(ClassLinker* cl,
+                                                          ScopedObjectAccessAlreadyRunnable& soa,
+                                                          Thread* self,
+                                                          const char* descriptor,
+                                                          size_t hash,
+                                                          Handle<mirror::ClassLoader> class_loader)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    ObjPtr<mirror::Class> result;
+    if (cl->FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &result)) {
+      return result;
+    }
+    return nullptr;
+  }
+};
+
 static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
                                             jstring javaName) {
   ScopedFastNativeObjectAccess soa(env);
@@ -35,12 +64,16 @@
     return nullptr;
   }
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
+
+  // Compute hash once.
   std::string descriptor(DotToDescriptor(name.c_str()));
   const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
-  ObjPtr<mirror::Class>  c = cl->LookupClass(soa.Self(),
-                                             descriptor.c_str(),
-                                             descriptor_hash,
-                                             loader.Ptr());
+
+  ObjPtr<mirror::Class> c = VMClassLoader::LookupClass(cl,
+                                                       soa.Self(),
+                                                       descriptor.c_str(),
+                                                       descriptor_hash,
+                                                       loader);
   if (c != nullptr && c->IsResolved()) {
     return soa.AddLocalReference<jclass>(c);
   }
@@ -61,17 +94,26 @@
     }
     return nullptr;
   }
+
+  // Hard-coded performance optimization: We know that all failed libcore calls to findLoadedClass
+  //                                      are followed by a call to the the classloader to actually
+  //                                      load the class.
   if (loader != nullptr) {
     // Try the common case.
     StackHandleScope<1> hs(soa.Self());
-    cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), descriptor_hash,
-                                   hs.NewHandle(loader), &c);
+    c = VMClassLoader::FindClassInPathClassLoader(cl,
+                                                  soa,
+                                                  soa.Self(),
+                                                  descriptor.c_str(),
+                                                  descriptor_hash,
+                                                  hs.NewHandle(loader));
     if (c != nullptr) {
       return soa.AddLocalReference<jclass>(c);
     }
   }
-  // Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into
-  // the regular loadClass code.
+
+  // The class wasn't loaded, yet, and our fast-path did not apply (e.g., we didn't understand the
+  // classloader chain).
   return nullptr;
 }
 
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index d0493e5..93286ea 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -154,8 +154,7 @@
   if (can_load_classes_) {
     klass = class_linker->FindClass(self, descriptor, class_loader);
   } else {
-    klass = class_linker->LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor),
-                                      loader);
+    klass = class_linker->LookupClass(self, descriptor, loader);
     if (klass != nullptr && !klass->IsResolved()) {
       // We found the class but without it being loaded its not safe for use.
       klass = nullptr;