ART: Allow quickening in the boot image

Update the class linker to accept class status from the boot image
in compiler mode. Update compiler driver to allow quickening for
boot image classes. Update method verifier to accept quickened
instructions in compiler mode when we just want to dump. Update
oatdump to the new verifier API.

Bug: 17316928

(cherry picked from commit 35439baf287b291b67ee406308e17fc6194facbf)

Change-Id: I9ef1bfd78b0d93625b89b3d662131d7d6e5f2903
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 01e0ac4..b993015 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -350,10 +350,10 @@
       dump_stats_(dump_stats),
       dump_passes_(dump_passes),
       timings_logger_(timer),
-      compiler_library_(NULL),
-      compiler_context_(NULL),
-      compiler_enable_auto_elf_loading_(NULL),
-      compiler_get_method_code_addr_(NULL),
+      compiler_library_(nullptr),
+      compiler_context_(nullptr),
+      compiler_enable_auto_elf_loading_(nullptr),
+      compiler_get_method_code_addr_(nullptr),
       support_boot_image_fixup_(instruction_set != kMips),
       dedupe_code_("dedupe code"),
       dedupe_src_mapping_table_("dedupe source mapping table"),
@@ -365,7 +365,7 @@
   DCHECK(verification_results_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
 
-  CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
+  CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, nullptr), "compiler tls key");
 
   dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
 
@@ -445,7 +445,7 @@
 CompilerTls* CompilerDriver::GetTls() {
   // Lazily create thread-local storage
   CompilerTls* res = static_cast<CompilerTls*>(pthread_getspecific(tls_key_));
-  if (res == NULL) {
+  if (res == nullptr) {
     res = compiler_->CreateNewCompilerTls();
     CHECK_PTHREAD_CALL(pthread_setspecific, (tls_key_, res), "compiler tls");
   }
@@ -520,20 +520,18 @@
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader);
-  if (klass == NULL) {
+  if (klass == nullptr) {
     CHECK(self->IsExceptionPending());
     self->ClearException();
     return kDontDexToDexCompile;
   }
-  // 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.Get() == nullptr;
-  if (compiling_image_classes) {
-    return kRequired;
-  } else if (klass->IsVerified()) {
+  // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic
+  // references with actual offsets. We cannot re-verify such instructions.
+  //
+  // We store the verification information in the class status in the oat file, which the linker
+  // can validate (checksums) and use to skip load-time verification. It is thus safe to
+  // optimize when a class has been fully verified before.
+  if (klass->IsVerified()) {
     // Class is verified so we can enable DEX-to-DEX compilation for performance.
     return kOptimize;
   } else if (klass->IsCompileTimeVerified()) {
@@ -606,13 +604,14 @@
                                 ThreadPool* thread_pool, TimingLogger* timings) {
   LoadImageClasses(timings);
 
+  Resolve(class_loader, dex_files, thread_pool, timings);
+
   if (!compiler_options_->IsVerificationEnabled()) {
-    VLOG(compiler) << "Verify none mode specified, skipping pre-compilation";
+    VLOG(compiler) << "Verify none mode specified, skipping verification.";
+    SetVerified(class_loader, dex_files, thread_pool, timings);
     return;
   }
 
-  Resolve(class_loader, dex_files, thread_pool, timings);
-
   Verify(class_loader, dex_files, thread_pool, timings);
 
   InitializeClasses(class_loader, dex_files, thread_pool, timings);
@@ -632,7 +631,7 @@
     std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   const DexFile::CodeItem* code_item = mh->GetMethod()->GetCodeItem();
-  if (code_item == NULL) {
+  if (code_item == nullptr) {
     return;  // native or abstract method
   }
   if (code_item->tries_size_ == 0) {
@@ -710,7 +709,7 @@
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str())));
-    if (klass.Get() == NULL) {
+    if (klass.Get() == nullptr) {
       VLOG(compiler) << "Failed to find class " << descriptor;
       image_classes_->erase(it++);
       self->ClearException();
@@ -738,7 +737,7 @@
       Handle<mirror::Class> klass(hs.NewHandle(
           class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
                                     NullHandle<mirror::ClassLoader>())));
-      if (klass.Get() == NULL) {
+      if (klass.Get() == nullptr) {
         const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
         const char* descriptor = dex_file->GetTypeDescriptor(type_id);
         LOG(FATAL) << "Failed to resolve class " << descriptor;
@@ -785,8 +784,8 @@
 }
 
 void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
-  DCHECK(object != NULL);
-  DCHECK(arg != NULL);
+  DCHECK(object != nullptr);
+  DCHECK(arg != nullptr);
   CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
   StackHandleScope<1> hs(Thread::Current());
   MaybeAddToImageClasses(hs.NewHandle(object->GetClass()), compiler_driver->image_classes_.get());
@@ -854,29 +853,29 @@
                                                 uint32_t type_idx,
                                                 bool* type_known_final, bool* type_known_abstract,
                                                 bool* equals_referrers_class) {
-  if (type_known_final != NULL) {
+  if (type_known_final != nullptr) {
     *type_known_final = false;
   }
-  if (type_known_abstract != NULL) {
+  if (type_known_abstract != nullptr) {
     *type_known_abstract = false;
   }
-  if (equals_referrers_class != NULL) {
+  if (equals_referrers_class != nullptr) {
     *equals_referrers_class = false;
   }
   ScopedObjectAccess soa(Thread::Current());
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
-  if (resolved_class == NULL) {
+  if (resolved_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
-  if (equals_referrers_class != NULL) {
+  if (equals_referrers_class != nullptr) {
     *equals_referrers_class = (method_id.class_idx_ == type_idx);
   }
   mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
-  if (referrer_class == NULL) {
+  if (referrer_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Incomplete referrer knowledge needs access check.
   }
@@ -885,10 +884,10 @@
   bool result = referrer_class->CanAccess(resolved_class);
   if (result) {
     stats_->TypeDoesntNeedAccessCheck();
-    if (type_known_final != NULL) {
+    if (type_known_final != nullptr) {
       *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass();
     }
-    if (type_known_abstract != NULL) {
+    if (type_known_abstract != nullptr) {
       *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass();
     }
   } else {
@@ -904,13 +903,13 @@
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
-  if (resolved_class == NULL) {
+  if (resolved_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
   mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
-  if (referrer_class == NULL) {
+  if (referrer_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Incomplete referrer knowledge needs access check.
   }
@@ -1310,6 +1309,10 @@
 }
 
 bool CompilerDriver::IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc) {
+  if (!compiler_options_->IsVerificationEnabled()) {
+    // If we didn't verify, every cast has to be treated as non-safe.
+    return false;
+  }
   DCHECK(mUnit->GetVerifiedMethod() != nullptr);
   bool result = mUnit->GetVerifiedMethod()->IsSafeCast(dex_pc);
   if (result) {
@@ -1410,7 +1413,7 @@
       thread_pool_(thread_pool) {}
 
   ClassLinker* GetClassLinker() const {
-    CHECK(class_linker_ != NULL);
+    CHECK(class_linker_ != nullptr);
     return class_linker_;
   }
 
@@ -1419,12 +1422,12 @@
   }
 
   CompilerDriver* GetCompiler() const {
-    CHECK(compiler_ != NULL);
+    CHECK(compiler_ != nullptr);
     return compiler_;
   }
 
   const DexFile* GetDexFile() const {
-    CHECK(dex_file_ != NULL);
+    CHECK(dex_file_ != nullptr);
     return dex_file_;
   }
 
@@ -1499,10 +1502,10 @@
 // that avoids the expensive FindInClassPath search.
 static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(klass != NULL);
+  DCHECK(klass != nullptr);
   const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile();
   if (&dex_file != &original_dex_file) {
-    if (class_loader == NULL) {
+    if (class_loader == nullptr) {
       LOG(WARNING) << "Skipping class " << PrettyDescriptor(klass) << " from "
                    << dex_file.GetLocation() << " previously found in "
                    << original_dex_file.GetLocation();
@@ -1587,7 +1590,7 @@
   // static fields, instance fields, direct methods, and virtual
   // methods.
   const byte* class_data = dex_file.GetClassData(class_def);
-  if (class_data == NULL) {
+  if (class_data == nullptr) {
     // Empty class such as a marker interface.
     requires_constructor_barrier = false;
   } else {
@@ -1596,7 +1599,7 @@
       if (resolve_fields_and_methods) {
         mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
                                                              dex_cache, class_loader, true);
-        if (field == NULL) {
+        if (field == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
       }
@@ -1611,7 +1614,7 @@
       if (resolve_fields_and_methods) {
         mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
                                                              dex_cache, class_loader, false);
-        if (field == NULL) {
+        if (field == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
       }
@@ -1623,7 +1626,7 @@
                                                                 dex_cache, class_loader,
                                                                 NullHandle<mirror::ArtMethod>(),
                                                                 it.GetMethodInvokeType(class_def));
-        if (method == NULL) {
+        if (method == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
         it.Next();
@@ -1633,7 +1636,7 @@
                                                                 dex_cache, class_loader,
                                                                 NullHandle<mirror::ArtMethod>(),
                                                                 it.GetMethodInvokeType(class_def));
-        if (method == NULL) {
+        if (method == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
         it.Next();
@@ -1658,9 +1661,9 @@
       hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())));
   mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
 
-  if (klass == NULL) {
+  if (klass == nullptr) {
     CHECK(soa.Self()->IsExceptionPending());
-    mirror::Throwable* exception = soa.Self()->GetException(NULL);
+    mirror::Throwable* exception = soa.Self()->GetException(nullptr);
     VLOG(compiler) << "Exception during type resolution: " << exception->Dump();
     if (exception->GetClass()->DescriptorEquals("Ljava/lang/OutOfMemoryError;")) {
       // There's little point continuing compilation if the heap is exhausted.
@@ -1691,11 +1694,20 @@
   context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
 }
 
+void CompilerDriver::SetVerified(jobject class_loader, const std::vector<const DexFile*>& dex_files,
+                                 ThreadPool* thread_pool, TimingLogger* timings) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
+    CHECK(dex_file != nullptr);
+    SetVerifiedDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+  }
+}
+
 void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                             ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     VerifyDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
 }
@@ -1757,6 +1769,47 @@
   context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
 }
 
+static void SetVerifiedClass(const ParallelCompilationManager* manager, size_t class_def_index)
+    LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  ATRACE_CALL();
+  ScopedObjectAccess soa(Thread::Current());
+  const DexFile& dex_file = *manager->GetDexFile();
+  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+  const char* descriptor = dex_file.GetClassDescriptor(class_def);
+  ClassLinker* class_linker = manager->GetClassLinker();
+  jobject jclass_loader = manager->GetClassLoader();
+  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)));
+  // Class might have failed resolution. Then don't set it to verified.
+  if (klass.Get() != nullptr) {
+    // Only do this if the class is resolved. If even resolution fails, quickening will go very,
+    // very wrong.
+    if (klass->IsResolved()) {
+      if (klass->GetStatus() < mirror::Class::kStatusVerified) {
+        ObjectLock<mirror::Class> lock(soa.Self(), klass);
+        klass->SetStatus(mirror::Class::kStatusVerified, soa.Self());
+      }
+      // Record the final class status if necessary.
+      ClassReference ref(manager->GetDexFile(), class_def_index);
+      manager->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
+    }
+  }
+  soa.Self()->AssertNoPendingException();
+}
+
+void CompilerDriver::SetVerifiedDexFile(jobject class_loader, const DexFile& dex_file,
+                                        const std::vector<const DexFile*>& dex_files,
+                                        ThreadPool* thread_pool, TimingLogger* timings) {
+  TimingLogger::ScopedTiming t("Verify Dex File", timings);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
+                                     thread_pool);
+  context.ForAll(0, dex_file.NumClassDefs(), SetVerifiedClass, thread_count_);
+}
+
 static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
   ATRACE_CALL();
@@ -1865,7 +1918,7 @@
                                        ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
   if (IsImage()) {
@@ -1878,7 +1931,7 @@
                              ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
 }
@@ -1911,7 +1964,7 @@
     return;
   }
   const byte* class_data = dex_file.GetClassData(class_def);
-  if (class_data == NULL) {
+  if (class_data == nullptr) {
     // empty class, probably a marker interface
     return;
   }
@@ -1984,7 +2037,7 @@
                                    uint32_t method_idx, jobject class_loader,
                                    const DexFile& dex_file,
                                    DexToDexCompilationLevel dex_to_dex_compilation_level) {
-  CompiledMethod* compiled_method = NULL;
+  CompiledMethod* compiled_method = nullptr;
   uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
 
   if ((access_flags & kAccNative) != 0) {
@@ -1994,14 +2047,14 @@
       // Leaving this empty will trigger the generic JNI version
     } else {
       compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file);
-      CHECK(compiled_method != NULL);
+      CHECK(compiled_method != nullptr);
     }
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     MethodReference method_ref(&dex_file, method_idx);
     bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
     if (compile) {
-      // NOTE: if compiler declines to compile this method, it will return NULL.
+      // NOTE: if compiler declines to compile this method, it will return nullptr.
       compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
                                            method_idx, class_loader, dex_file);
     }
@@ -2022,20 +2075,20 @@
   }
 
   Thread* self = Thread::Current();
-  if (compiled_method != NULL) {
+  if (compiled_method != nullptr) {
     MethodReference ref(&dex_file, method_idx);
-    DCHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
     {
       MutexLock mu(self, compiled_methods_lock_);
       compiled_methods_.Put(ref, compiled_method);
     }
-    DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
   }
 
   if (self->IsExceptionPending()) {
     ScopedObjectAccess soa(self);
     LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
-        << self->GetException(NULL)->Dump();
+        << self->GetException(nullptr)->Dump();
   }
 }
 
@@ -2043,9 +2096,9 @@
   MutexLock mu(Thread::Current(), compiled_classes_lock_);
   ClassTable::const_iterator it = compiled_classes_.find(ref);
   if (it == compiled_classes_.end()) {
-    return NULL;
+    return nullptr;
   }
-  CHECK(it->second != NULL);
+  CHECK(it->second != nullptr);
   return it->second;
 }
 
@@ -2079,9 +2132,9 @@
   MutexLock mu(Thread::Current(), compiled_methods_lock_);
   MethodTable::const_iterator it = compiled_methods_.find(ref);
   if (it == compiled_methods_.end()) {
-    return NULL;
+    return nullptr;
   }
-  CHECK(it->second != NULL);
+  CHECK(it->second != nullptr);
   return it->second;
 }