Adds a DEX-to-DEX compilation level.

This CL adds a DEX-to-DEX compilation level which allows the DEX-to-DEX
compiler to ensure correctness on classes with soft-failed verification.

Bug: 9307738
Change-Id: If051336bf81370bca55872c8c75ccd573d8ca391
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 49aba4d..38d00a0 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -369,7 +369,7 @@
     compiler_ = reinterpret_cast<CompilerFn>(ArtQuickCompileMethod);
   }
 
-  dex_to_dex_compiler_ = reinterpret_cast<CompilerFn>(ArtCompileDEX);
+  dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
 
 #ifdef ART_SEA_IR_MODE
   sea_ir_compiler_ = NULL;
@@ -505,16 +505,10 @@
   }
 }
 
-static bool IsDexToDexCompilationAllowed(mirror::ClassLoader* class_loader,
-                                         const DexFile& dex_file,
-                                         const DexFile::ClassDef& class_def)
+static DexToDexCompilationLevel GetDexToDexCompilationlevel(mirror::ClassLoader* class_loader,
+                                                            const DexFile& dex_file,
+                                                            const DexFile::ClassDef& class_def)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // Do not allow DEX-to-DEX compilation of image classes. This is to prevent the
-  // verifier from passing on "quick" instruction at compilation time. It must
-  // only pass on quick instructions at runtime.
-  if (class_loader == NULL) {
-    return false;
-  }
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* klass = class_linker->FindClass(descriptor, class_loader);
@@ -522,10 +516,27 @@
     Thread* self = Thread::Current();
     CHECK(self->IsExceptionPending());
     self->ClearException();
-    return false;
+    return kDontDexToDexCompile;
   }
-  // DEX-to-DEX compilation is only allowed on preverified classes.
-  return klass->IsVerified();
+  // The verifier can only run on "quick" instructions at runtime (see usage of
+  // FindAccessedFieldAtDexPc and FindInvokedMethodAtDexPc in ThrowNullPointerExceptionFromDexPC
+  // function). Since image classes can be verified again while compiling an application,
+  // we must prevent the DEX-to-DEX compiler from introducing them.
+  // TODO: find a way to enable "quick" instructions for image classes and remove this check.
+  bool compiling_image_classes = (class_loader == NULL);
+  if (compiling_image_classes) {
+    return kRequired;
+  } else if (klass->IsVerified()) {
+    // Class is verified so we can enable DEX-to-DEX compilation for performance.
+    return kOptimize;
+  } else if (klass->IsCompileTimeVerified()) {
+    // Class verification has soft-failed. Anyway, ensure at least correctness.
+    DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
+    return kRequired;
+  } else {
+    // Class verification has failed: do not run DEX-to-DEX compilation.
+    return kDontDexToDexCompile;
+  }
 }
 
 void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings) {
@@ -556,15 +567,15 @@
   uint32_t method_idx = method->GetDexMethodIndex();
   const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
   // Can we run DEX-to-DEX compiler on this class ?
-  bool allow_dex_compilation;
+  DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
   {
     ScopedObjectAccess soa(Thread::Current());
     const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
     mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
-    allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, *dex_file, class_def);
+    dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, *dex_file, class_def);
   }
   CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(),
-                class_def_idx, method_idx, jclass_loader, *dex_file, allow_dex_compilation);
+                class_def_idx, method_idx, jclass_loader, *dex_file, dex_to_dex_compilation_level);
 
   self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
 
@@ -2171,11 +2182,11 @@
     return;
   }
   // Can we run DEX-to-DEX compiler on this class ?
-  bool allow_dex_compilation;
+  DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
   {
     ScopedObjectAccess soa(Thread::Current());
     mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
-    allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, dex_file, class_def);
+    dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, dex_file, class_def);
   }
   ClassDataItemIterator it(dex_file, class_data);
   // Skip fields
@@ -2198,7 +2209,7 @@
     previous_direct_method_idx = method_idx;
     manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
                                           it.GetMethodInvokeType(class_def), class_def_index,
-                                          method_idx, jclass_loader, dex_file, allow_dex_compilation);
+                                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
     it.Next();
   }
   // Compile virtual methods
@@ -2214,7 +2225,7 @@
     previous_virtual_method_idx = method_idx;
     manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
                                           it.GetMethodInvokeType(class_def), class_def_index,
-                                          method_idx, jclass_loader, dex_file, allow_dex_compilation);
+                                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
     it.Next();
   }
   DCHECK(!it.HasNext());
@@ -2231,7 +2242,7 @@
                                    InvokeType invoke_type, uint32_t class_def_idx,
                                    uint32_t method_idx, jobject class_loader,
                                    const DexFile& dex_file,
-                                   bool allow_dex_to_dex_compilation) {
+                                   DexToDexCompilationLevel dex_to_dex_compilation_level) {
   CompiledMethod* compiled_method = NULL;
   uint64_t start_ns = NanoTime();
 
@@ -2253,13 +2264,12 @@
       compiled_method = (*compiler)(*this, code_item, access_flags, invoke_type, class_def_idx,
                                     method_idx, class_loader, dex_file);
       CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
-    } else if (allow_dex_to_dex_compilation) {
+    } else if (dex_to_dex_compilation_level != kDontDexToDexCompile) {
       // TODO: add a mode to disable DEX-to-DEX compilation ?
-      compiled_method = (*dex_to_dex_compiler_)(*this, code_item, access_flags,
-                                                invoke_type, class_def_idx,
-                                                method_idx, class_loader, dex_file);
-      // No native code is generated.
-      CHECK(compiled_method == NULL) << PrettyMethod(method_idx, dex_file);
+      (*dex_to_dex_compiler_)(*this, code_item, access_flags,
+                              invoke_type, class_def_idx,
+                              method_idx, class_loader, dex_file,
+                              dex_to_dex_compilation_level);
     }
   }
   uint64_t duration_ns = NanoTime() - start_ns;