Add verify-profile compiler filter

Only verifies and dex2dex compiles classes in the profile. Goal
is to reduce application launch time.

~2x faster than interpret-only for Facebook.

Bug: 27688727

(cherry picked from commit a079e3aa62cceb76c1c1811e6e09bcaf75e20289)

Change-Id: Iad5aa1adee3aa6c2408820e8cbbab2d4412021b8
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index cd9d80f..ea16cb2 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -383,6 +383,9 @@
 
   compiler_->Init();
 
+  if (compiler_options->VerifyOnlyProfile()) {
+    CHECK(profile_compilation_info_ != nullptr) << "Requires profile";
+  }
   if (boot_image_) {
     CHECK(image_classes_.get() != nullptr) << "Expected image classes for boot image";
   }
@@ -830,10 +833,12 @@
 
   const bool verification_enabled = compiler_options_->IsVerificationEnabled();
   const bool never_verify = compiler_options_->NeverVerify();
+  const bool verify_only_profile = compiler_options_->VerifyOnlyProfile();
 
   // We need to resolve for never_verify since it needs to run dex to dex to add the
   // RETURN_VOID_NO_BARRIER.
-  if (never_verify || verification_enabled) {
+  // Let the verifier resolve as needed for the verify_only_profile case.
+  if ((never_verify || verification_enabled) && !verify_only_profile) {
     Resolve(class_loader, dex_files, timings);
     VLOG(compiler) << "Resolve: " << GetMemoryUsageString(false);
   }
@@ -918,6 +923,22 @@
   return result;
 }
 
+bool CompilerDriver::ShouldVerifyClassBasedOnProfile(const DexFile& dex_file,
+                                                     uint16_t class_idx) const {
+  if (!compiler_options_->VerifyOnlyProfile()) {
+    // No profile, verify everything.
+    return true;
+  }
+  DCHECK(profile_compilation_info_ != nullptr);
+  bool result = profile_compilation_info_->ContainsClass(dex_file, class_idx);
+  if (kDebugProfileGuidedCompilation) {
+    LOG(INFO) << "[ProfileGuidedCompilation] "
+        << (result ? "Verified" : "Skipped") << " method:"
+        << dex_file.GetClassDescriptor(dex_file.GetClassDef(class_idx));
+  }
+  return result;
+}
+
 class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
  public:
   ResolveCatchBlockExceptionsClassVisitor(
@@ -2197,6 +2218,10 @@
     ATRACE_CALL();
     ScopedObjectAccess soa(Thread::Current());
     const DexFile& dex_file = *manager_->GetDexFile();
+    if (!manager_->GetCompiler()->ShouldVerifyClassBasedOnProfile(dex_file, class_def_index)) {
+      // Skip verification since the class is not in the profile.
+      return;
+    }
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
     ClassLinker* class_linker = manager_->GetClassLinker();
@@ -2665,6 +2690,7 @@
       case mirror::Class::kStatusRetryVerificationAtRuntime:
       case mirror::Class::kStatusVerified:
       case mirror::Class::kStatusInitialized:
+      case mirror::Class::kStatusResolved:
         break;  // Expected states.
       default:
         LOG(FATAL) << "Unexpected class status for class "
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 4ef26dd..64a06a2 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -91,7 +91,8 @@
                  Compiler::Kind compiler_kind,
                  InstructionSet instruction_set,
                  const InstructionSetFeatures* instruction_set_features,
-                 bool boot_image, std::unordered_set<std::string>* image_classes,
+                 bool boot_image,
+                 std::unordered_set<std::string>* image_classes,
                  std::unordered_set<std::string>* compiled_classes,
                  std::unordered_set<std::string>* compiled_methods,
                  size_t thread_count,
@@ -435,6 +436,10 @@
   // according to the profile file.
   bool ShouldCompileBasedOnProfile(const MethodReference& method_ref) const;
 
+  // Checks whether profile guided verification is enabled and if the method should be verified
+  // according to the profile file.
+  bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const;
+
   void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
       REQUIRES(!compiled_classes_lock_);
 
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 43bdbf3..b4389d3 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -195,6 +195,8 @@
       compiler_filter_ = CompilerOptions::kEverything;
     } else if (strcmp(compiler_filter_string, "time") == 0) {
       compiler_filter_ = CompilerOptions::kTime;
+    } else if (strcmp(compiler_filter_string, "verify-profile") == 0) {
+      compiler_filter_ = CompilerOptions::kVerifyProfile;
     } else {
       Usage("Unknown --compiler-filter value %s", compiler_filter_string);
     }
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index fbfa7c8..59698af 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -39,6 +39,7 @@
     kSpeed,               // Maximize runtime performance.
     kEverything,          // Force compilation of everything capable of being compiled.
     kTime,                // Compile methods, but minimize compilation time.
+    kVerifyProfile,       // Verify only the classes in the profile.
   };
 
   // Guide heuristics to determine whether to compile method if profile data not available.
@@ -102,13 +103,14 @@
 
   bool IsCompilationEnabled() const {
     return compiler_filter_ != CompilerOptions::kVerifyNone &&
-        compiler_filter_ != CompilerOptions::kInterpretOnly &&
-        compiler_filter_ != CompilerOptions::kVerifyAtRuntime;
+           compiler_filter_ != CompilerOptions::kInterpretOnly &&
+           compiler_filter_ != CompilerOptions::kVerifyAtRuntime &&
+           compiler_filter_ != CompilerOptions::kVerifyProfile;
   }
 
   bool IsVerificationEnabled() const {
     return compiler_filter_ != CompilerOptions::kVerifyNone &&
-        compiler_filter_ != CompilerOptions::kVerifyAtRuntime;
+           compiler_filter_ != CompilerOptions::kVerifyAtRuntime;
   }
 
   bool NeverVerify() const {
@@ -119,6 +121,10 @@
     return compiler_filter_ == CompilerOptions::kVerifyAtRuntime;
   }
 
+  bool VerifyOnlyProfile() const {
+    return compiler_filter_ == CompilerOptions::kVerifyProfile;
+  }
+
   size_t GetHugeMethodThreshold() const {
     return huge_method_threshold_;
   }