Reduce how often we call FindDexCache

Before host boot.oat -j4 optimizing compile:
real  1m17.792s
user  3m26.140s
sys 0m8.340s

After:
real  1m12.324s
user  3m22.718s
sys 0m8.320s

Change-Id: If18e9e79e06cdf1676692e5efacb682bf93889c3
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 6d3a960..ded70cd 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -571,7 +571,8 @@
                           jobject class_loader,
                           const DexFile& dex_file,
                           optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level,
-                          bool compilation_enabled)
+                          bool compilation_enabled,
+                          Handle<mirror::DexCache> dex_cache)
     REQUIRES(!driver->compiled_methods_lock_) {
   DCHECK(driver != nullptr);
   CompiledMethod* compiled_method = nullptr;
@@ -608,7 +609,7 @@
       // NOTE: if compiler declines to compile this method, it will return null.
       compiled_method = driver->GetCompiler()->Compile(code_item, access_flags, invoke_type,
                                                        class_def_idx, method_idx, class_loader,
-                                                       dex_file);
+                                                       dex_file, dex_cache);
     }
     if (compiled_method == nullptr &&
         dex_to_dex_compilation_level != optimizer::DexToDexCompilationLevel::kDontDexToDexCompile) {
@@ -673,6 +674,8 @@
   uint32_t method_idx = method->GetDexMethodIndex();
   uint32_t access_flags = method->GetAccessFlags();
   InvokeType invoke_type = method->GetInvokeType();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
   {
     ScopedObjectAccessUnchecked soa(self);
     ScopedLocalRef<jobject> local_class_loader(
@@ -683,6 +686,8 @@
     class_def_idx = method->GetClassDefIndex();
   }
   const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+
+  // Go to native so that we don't block GC during compilation.
   self->TransitionFromRunnableToSuspended(kNative);
 
   std::vector<const DexFile*> dex_files;
@@ -709,7 +714,8 @@
                 jclass_loader,
                 *dex_file,
                 dex_to_dex_compilation_level,
-                true);
+                true,
+                dex_cache);
 
   self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
   self->TransitionFromSuspendedToRunnable();
@@ -719,9 +725,10 @@
   const uint32_t method_idx = method->GetDexMethodIndex();
   const uint32_t access_flags = method->GetAccessFlags();
   const InvokeType invoke_type = method->GetInvokeType();
-  StackHandleScope<1> hs(self);
+  StackHandleScope<2> hs(self);
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
       method->GetDeclaringClass()->GetClassLoader()));
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
   jobject jclass_loader = class_loader.ToJObject();
   const DexFile* dex_file = method->GetDexFile();
   const uint16_t class_def_idx = method->GetClassDefIndex();
@@ -729,6 +736,7 @@
   optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
       GetDexToDexCompilationLevel(self, *this, class_loader, *dex_file, class_def);
   const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+  // Go to native so that we don't block GC during compilation.
   self->TransitionFromRunnableToSuspended(kNative);
   CompileMethod(self,
                 this,
@@ -740,7 +748,8 @@
                 jclass_loader,
                 *dex_file,
                 dex_to_dex_compilation_level,
-                true);
+                true,
+                dex_cache);
   auto* compiled_method = GetCompiledMethod(MethodReference(dex_file, method_idx));
   self->TransitionFromSuspendedToRunnable();
   return compiled_method;
@@ -1422,24 +1431,19 @@
   // Try to resolve the field and compiling method's class.
   ArtField* resolved_field;
   mirror::Class* referrer_class;
-  mirror::DexCache* dex_cache;
+  Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
   {
-    StackHandleScope<2> hs(soa.Self());
-    Handle<mirror::DexCache> dex_cache_handle(
-        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(
-            soa.Self(), *mUnit->GetDexFile(), false)));
+    StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader_handle(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
-    resolved_field =
-        ResolveField(soa, dex_cache_handle, class_loader_handle, mUnit, field_idx, false);
+    resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false);
     referrer_class = resolved_field != nullptr
-        ? ResolveCompilingMethodsClass(soa, dex_cache_handle, class_loader_handle, mUnit) : nullptr;
-    dex_cache = dex_cache_handle.Get();
+        ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
   }
   bool can_link = false;
   if (resolved_field != nullptr && referrer_class != nullptr) {
     std::pair<bool, bool> fast_path = IsFastInstanceField(
-        dex_cache, referrer_class, resolved_field, field_idx);
+        dex_cache.Get(), referrer_class, resolved_field, field_idx);
     can_link = is_put ? fast_path.second : fast_path.first;
   }
   ProcessedInstanceField(can_link);
@@ -1473,25 +1477,21 @@
   // Try to resolve the field and compiling method's class.
   ArtField* resolved_field;
   mirror::Class* referrer_class;
-  mirror::DexCache* dex_cache;
+  Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
   {
-    StackHandleScope<2> hs(soa.Self());
-    Handle<mirror::DexCache> dex_cache_handle(
-        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(
-            soa.Self(), *mUnit->GetDexFile(), false)));
+    StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader_handle(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
     resolved_field =
-        ResolveField(soa, dex_cache_handle, class_loader_handle, mUnit, field_idx, true);
+        ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, true);
     referrer_class = resolved_field != nullptr
-        ? ResolveCompilingMethodsClass(soa, dex_cache_handle, class_loader_handle, mUnit) : nullptr;
-    dex_cache = dex_cache_handle.Get();
+        ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
   }
   bool result = false;
   if (resolved_field != nullptr && referrer_class != nullptr) {
     *is_volatile = IsFieldVolatile(resolved_field);
     std::pair<bool, bool> fast_path = IsFastStaticField(
-        dex_cache, referrer_class, resolved_field, field_idx, storage_index);
+        dex_cache.Get(), referrer_class, resolved_field, field_idx, storage_index);
     result = is_put ? fast_path.second : fast_path.first;
   }
   if (result) {
@@ -1662,10 +1662,8 @@
   int stats_flags = 0;
   ScopedObjectAccess soa(Thread::Current());
   // Try to resolve the method and compiling method's class.
-  StackHandleScope<3> hs(soa.Self());
-  Handle<mirror::DexCache> dex_cache(
-      hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(
-          soa.Self(), *mUnit->GetDexFile(), false)));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
       soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
   uint32_t method_idx = target_method->dex_method_index;
@@ -2353,39 +2351,44 @@
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     ClassLinker* class_linker = manager_->GetClassLinker();
     jobject jclass_loader = manager_->GetClassLoader();
-    Thread* self = Thread::Current();
-    {
-      // Use a scoped object access to perform to the quick SkipClass check.
-      const char* descriptor = dex_file.GetClassDescriptor(class_def);
-      ScopedObjectAccess soa(self);
-      StackHandleScope<3> hs(soa.Self());
-      Handle<mirror::ClassLoader> class_loader(
-          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
-      Handle<mirror::Class> klass(
-          hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
-      if (klass.Get() == nullptr) {
-        CHECK(soa.Self()->IsExceptionPending());
-        soa.Self()->ClearException();
-      } else if (SkipClass(jclass_loader, dex_file, klass.Get())) {
-        return;
-      }
-    }
     ClassReference ref(&dex_file, class_def_index);
     // Skip compiling classes with generic verifier failures since they will still fail at runtime
     if (manager_->GetCompiler()->verification_results_->IsClassRejected(ref)) {
       return;
     }
+    // Use a scoped object access to perform to the quick SkipClass check.
+    const char* descriptor = dex_file.GetClassDescriptor(class_def);
+    ScopedObjectAccess soa(Thread::Current());
+    StackHandleScope<3> hs(soa.Self());
+    Handle<mirror::ClassLoader> class_loader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+    Handle<mirror::Class> klass(
+        hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
+    Handle<mirror::DexCache> dex_cache;
+    if (klass.Get() == nullptr) {
+      soa.Self()->AssertPendingException();
+      soa.Self()->ClearException();
+      dex_cache = hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
+    } else if (SkipClass(jclass_loader, dex_file, klass.Get())) {
+      return;
+    } else {
+      dex_cache = hs.NewHandle(klass->GetDexCache());
+    }
+
     const uint8_t* class_data = dex_file.GetClassData(class_def);
     if (class_data == nullptr) {
       // empty class, probably a marker interface
       return;
     }
 
+    // Go to native so that we don't block GC during compilation.
+    soa.Self()->TransitionFromRunnableToSuspended(kNative);
+
     CompilerDriver* const driver = manager_->GetCompiler();
 
     // Can we run DEX-to-DEX compiler on this class ?
     optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
-        GetDexToDexCompilationLevel(self, *driver, jclass_loader, dex_file, class_def);
+        GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def);
 
     ClassDataItemIterator it(dex_file, class_data);
     // Skip fields
@@ -2410,10 +2413,10 @@
         continue;
       }
       previous_direct_method_idx = method_idx;
-      CompileMethod(self, driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
+      CompileMethod(soa.Self(), driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                     it.GetMethodInvokeType(class_def), class_def_index,
                     method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
-                    compilation_enabled);
+                    compilation_enabled, dex_cache);
       it.Next();
     }
     // Compile virtual methods
@@ -2427,13 +2430,15 @@
         continue;
       }
       previous_virtual_method_idx = method_idx;
-      CompileMethod(self, driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
+      CompileMethod(soa.Self(), driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                     it.GetMethodInvokeType(class_def), class_def_index,
                     method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
-                    compilation_enabled);
+                    compilation_enabled, dex_cache);
       it.Next();
     }
     DCHECK(!it.HasNext());
+
+    soa.Self()->TransitionFromSuspendedToRunnable();
   }
 
  private: