Add logic to eagerly resolve const-string for startup methods

Added dex2oat option --resolve-startup-const-strings=<true|false>

If true, this option causes the compiler driver to resolve all
const-strings that are referenced from methods marked as "startup" in
the profile.

Bug: 116059983
Test: test-art-host
Change-Id: I61cf9e945c125671fc4ab4b50458a911318a837f
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c5416d5..89ac308 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -708,9 +708,9 @@
   }
 }
 
-static void ResolveConstStrings(CompilerDriver* driver,
-                                const std::vector<const DexFile*>& dex_files,
-                                TimingLogger* timings) {
+void CompilerDriver::ResolveConstStrings(const std::vector<const DexFile*>& dex_files,
+                                         bool only_startup_strings,
+                                         TimingLogger* timings) {
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
@@ -721,12 +721,18 @@
     TimingLogger::ScopedTiming t("Resolve const-string Strings", timings);
 
     for (ClassAccessor accessor : dex_file->GetClasses()) {
-      if (!driver->IsClassToCompile(accessor.GetDescriptor())) {
+      if (!IsClassToCompile(accessor.GetDescriptor())) {
         // Compilation is skipped, do not resolve const-string in code of this class.
         // FIXME: Make sure that inlining honors this. b/26687569
         continue;
       }
       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+        if (only_startup_strings &&
+            profile_compilation_info_ != nullptr &&
+            !profile_compilation_info_->GetMethodHotness(method.GetReference()).IsStartup()) {
+          continue;
+        }
+
         // Resolve const-strings in the code. Done to have deterministic allocation behavior. Right
         // now this is single-threaded for simplicity.
         // TODO: Collect the relevant string indices in parallel, then allocate them sequentially
@@ -897,8 +903,10 @@
 
   if (GetCompilerOptions().IsForceDeterminism() && GetCompilerOptions().IsBootImage()) {
     // Resolve strings from const-string. Do this now to have a deterministic image.
-    ResolveConstStrings(this, dex_files, timings);
+    ResolveConstStrings(dex_files, /*only_startup_strings=*/ false, timings);
     VLOG(compiler) << "Resolve const-strings: " << GetMemoryUsageString(false);
+  } else if (GetCompilerOptions().ResolveStartupConstStrings()) {
+    ResolveConstStrings(dex_files, /*only_startup_strings=*/ true, timings);
   }
 
   Verify(class_loader, dex_files, timings);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 343f67c..9a83e55 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -430,6 +430,12 @@
   typedef AtomicDexRefMap<MethodReference, CompiledMethod*> MethodTable;
 
  private:
+  // Resolve const string literals that are loaded from dex code. If only_startup_strings is
+  // specified, only methods that are marked startup in the profile are resolved.
+  void ResolveConstStrings(const std::vector<const DexFile*>& dex_files,
+                           bool only_startup_strings,
+                           /*inout*/ TimingLogger* timings);
+
   // All method references that this compiler has compiled.
   MethodTable compiled_methods_;
 
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 3ab9afc..6b0e456 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -69,6 +69,7 @@
       force_determinism_(false),
       deduplicate_code_(true),
       count_hotness_in_compiled_code_(false),
+      resolve_startup_const_strings_(false),
       register_allocation_strategy_(RegisterAllocator::kRegisterAllocatorDefault),
       passes_to_run_(nullptr) {
 }
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index e9cbf74..4a6bbfa 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -313,6 +313,10 @@
     return count_hotness_in_compiled_code_;
   }
 
+  bool ResolveStartupConstStrings() const {
+    return resolve_startup_const_strings_;
+  }
+
  private:
   bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
   void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage);
@@ -392,6 +396,10 @@
   // won't be atomic for performance reasons, so we accept races, just like in interpreter.
   bool count_hotness_in_compiled_code_;
 
+  // Whether we eagerly resolve all of the const strings that are loaded from startup methods in the
+  // profile.
+  bool resolve_startup_const_strings_;
+
   RegisterAllocator::Strategy register_allocation_strategy_;
 
   // If not null, specifies optimization passes which will be run instead of defaults.
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index d4a582f..5a84495 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -80,6 +80,7 @@
   if (map.Exists(Base::CountHotnessInCompiledCode)) {
     options->count_hotness_in_compiled_code_ = true;
   }
+  map.AssignIfExists(Base::ResolveStartupConstStrings, &options->resolve_startup_const_strings_);
 
   if (map.Exists(Base::DumpTimings)) {
     options->dump_timings_ = true;
@@ -184,6 +185,11 @@
           .template WithType<std::string>()
           .IntoKey(Map::RegisterAllocationStrategy)
 
+      .Define("--resolve-startup-const-strings=_")
+          .template WithType<bool>()
+          .WithValueMap({{"false", false}, {"true", true}})
+          .IntoKey(Map::ResolveStartupConstStrings)
+
       .Define("--verbose-methods=_")
           .template WithType<ParseStringList<','>>()
           .IntoKey(Map::VerboseMethods);
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index 238cd46..a593240 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -52,13 +52,14 @@
 COMPILER_OPTIONS_KEY (double,                      TopKProfileThreshold)
 COMPILER_OPTIONS_KEY (bool,                        AbortOnHardVerifierFailure)
 COMPILER_OPTIONS_KEY (bool,                        AbortOnSoftVerifierFailure)
+COMPILER_OPTIONS_KEY (bool,                        ResolveStartupConstStrings, false)
 COMPILER_OPTIONS_KEY (std::string,                 DumpInitFailures)
 COMPILER_OPTIONS_KEY (std::string,                 DumpCFG)
 COMPILER_OPTIONS_KEY (Unit,                        DumpCFGAppend)
 // TODO: Add type parser.
 COMPILER_OPTIONS_KEY (std::string,                 RegisterAllocationStrategy)
 COMPILER_OPTIONS_KEY (ParseStringList<','>,        VerboseMethods)
-COMPILER_OPTIONS_KEY (bool,                        DeduplicateCode,        true)
+COMPILER_OPTIONS_KEY (bool,                        DeduplicateCode,            true)
 COMPILER_OPTIONS_KEY (Unit,                        CountHotnessInCompiledCode)
 COMPILER_OPTIONS_KEY (Unit,                        DumpTimings)
 COMPILER_OPTIONS_KEY (Unit,                        DumpPassTimings)