Merge "Move image_classes_ to CompilerOptions."
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index c37d452..7491173 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -31,6 +31,7 @@
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
+#include "jni/java_vm_ext.h"
 #include "interpreter/interpreter.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -134,8 +135,7 @@
   }
 }
 
-// Get the set of image classes given to the compiler-driver in SetUp. Note: the compiler
-// driver assumes ownership of the set, so the test should properly release the set.
+// Get the set of image classes given to the compiler options in SetUp.
 std::unique_ptr<HashSet<std::string>> CommonCompilerTest::GetImageClasses() {
   // Empty set: by default no classes are retained in the image.
   return std::make_unique<HashSet<std::string>>();
@@ -173,12 +173,13 @@
                                               size_t number_of_threads) {
   compiler_options_->boot_image_ = true;
   compiler_options_->SetCompilerFilter(GetCompilerFilter());
+  compiler_options_->image_classes_.swap(*GetImageClasses());
   compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                             verification_results_.get(),
                                             kind,
                                             isa,
                                             instruction_set_features_.get(),
-                                            GetImageClasses(),
+                                            &compiler_options_->image_classes_,
                                             number_of_threads,
                                             /* swap_fd */ -1,
                                             GetProfileCompilationInfo()));
@@ -235,9 +236,49 @@
 
 void CommonCompilerTest::CompileMethod(ArtMethod* method) {
   CHECK(method != nullptr);
-  TimingLogger timings("CommonTest::CompileMethod", false, false);
+  TimingLogger timings("CommonCompilerTest::CompileMethod", false, false);
   TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
-  compiler_driver_->CompileOne(Thread::Current(), method, &timings);
+  {
+    Thread* self = Thread::Current();
+    jobject class_loader = self->GetJniEnv()->GetVm()->AddGlobalRef(self, method->GetClassLoader());
+
+    DCHECK(!Runtime::Current()->IsStarted());
+    const DexFile* dex_file = method->GetDexFile();
+    uint16_t class_def_idx = method->GetClassDefIndex();
+    uint32_t method_idx = method->GetDexMethodIndex();
+    uint32_t access_flags = method->GetAccessFlags();
+    InvokeType invoke_type = method->GetInvokeType();
+    StackHandleScope<2> hs(self);
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+    Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle(
+        self->DecodeJObject(class_loader)->AsClassLoader());
+    const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+
+    std::vector<const DexFile*> dex_files;
+    dex_files.push_back(dex_file);
+
+    // Go to native so that we don't block GC during compilation.
+    ScopedThreadSuspension sts(self, kNative);
+
+    compiler_driver_->InitializeThreadPools();
+
+    compiler_driver_->PreCompile(class_loader, dex_files, &timings);
+
+    compiler_driver_->CompileOne(self,
+                                 class_loader,
+                                 *dex_file,
+                                 class_def_idx,
+                                 method_idx,
+                                 access_flags,
+                                 invoke_type,
+                                 code_item,
+                                 dex_cache,
+                                 h_class_loader);
+
+    compiler_driver_->FreeThreadPools();
+
+    self->GetJniEnv()->DeleteGlobalRef(class_loader);
+  }
   TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
   MakeExecutable(method);
 }
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bd2b107..ed4fb6f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -67,7 +67,6 @@
 #include "mirror/object-refvisitor-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/throwable.h"
-#include "nativehelper/ScopedLocalRef.h"
 #include "object_lock.h"
 #include "profile/profile_compilation_info.h"
 #include "runtime.h"
@@ -264,7 +263,7 @@
     Compiler::Kind compiler_kind,
     InstructionSet instruction_set,
     const InstructionSetFeatures* instruction_set_features,
-    std::unique_ptr<HashSet<std::string>>&& image_classes,
+    HashSet<std::string>* image_classes,
     size_t thread_count,
     int swap_fd,
     const ProfileCompilationInfo* profile_compilation_info)
@@ -293,7 +292,7 @@
   compiler_->Init();
 
   if (GetCompilerOptions().IsBootImage()) {
-    CHECK(image_classes_.get() != nullptr) << "Expected image classes for boot image";
+    CHECK(image_classes_ != nullptr) << "Expected image classes for boot image";
   }
 
   compiled_method_storage_.SetDedupeEnabled(compiler_options_->DeduplicateCode());
@@ -351,12 +350,6 @@
 
   InitializeThreadPools();
 
-  VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
-  // Precompile:
-  // 1) Load image classes
-  // 2) Resolve all classes
-  // 3) Attempt to verify all classes
-  // 4) Attempt to initialize image classes, and trivially initialized classes
   PreCompile(class_loader, dex_files, timings);
   if (GetCompilerOptions().IsBootImage()) {
     // We don't need to setup the intrinsics for non boot image compilation, as
@@ -673,46 +666,24 @@
                        quick_fn);
 }
 
-void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings) {
-  DCHECK(!Runtime::Current()->IsStarted());
-  jobject jclass_loader;
-  const DexFile* dex_file;
-  uint16_t class_def_idx;
-  uint32_t method_idx = method->GetDexMethodIndex();
-  uint32_t access_flags = method->GetAccessFlags();
-  InvokeType invoke_type = method->GetInvokeType();
-  StackHandleScope<2> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(method->GetDeclaringClass()->GetClassLoader()));
-  {
-    ScopedObjectAccessUnchecked soa(self);
-    ScopedLocalRef<jobject> local_class_loader(
-        soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get()));
-    jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
-    // Find the dex_file
-    dex_file = method->GetDexFile();
-    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.
-  ScopedThreadSuspension sts(self, kNative);
-
-  std::vector<const DexFile*> dex_files;
-  dex_files.push_back(dex_file);
-
-  InitializeThreadPools();
-
-  PreCompile(jclass_loader, dex_files, timings);
-
+// Compile a single Method. (For testing only.)
+void CompilerDriver::CompileOne(Thread* self,
+                                jobject class_loader,
+                                const DexFile& dex_file,
+                                uint16_t class_def_idx,
+                                uint32_t method_idx,
+                                uint32_t access_flags,
+                                InvokeType invoke_type,
+                                const DexFile::CodeItem* code_item,
+                                Handle<mirror::DexCache> dex_cache,
+                                Handle<mirror::ClassLoader> h_class_loader) {
   // Can we run DEX-to-DEX compiler on this class ?
   optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level =
       GetDexToDexCompilationLevel(self,
                                   *this,
-                                  jclass_loader,
-                                  *dex_file,
-                                  dex_file->GetClassDef(class_def_idx));
+                                  class_loader,
+                                  dex_file,
+                                  dex_file.GetClassDef(class_def_idx));
 
   CompileMethodQuick(self,
                      this,
@@ -721,8 +692,8 @@
                      invoke_type,
                      class_def_idx,
                      method_idx,
-                     class_loader,
-                     *dex_file,
+                     h_class_loader,
+                     dex_file,
                      dex_to_dex_compilation_level,
                      true,
                      dex_cache);
@@ -737,17 +708,13 @@
                          invoke_type,
                          class_def_idx,
                          method_idx,
-                         class_loader,
-                         *dex_file,
+                         h_class_loader,
+                         dex_file,
                          dex_to_dex_compilation_level,
                          true,
                          dex_cache);
     dex_to_dex_compiler_.ClearState();
   }
-
-  FreeThreadPools();
-
-  self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
 }
 
 void CompilerDriver::Resolve(jobject class_loader,
@@ -838,7 +805,7 @@
         // primitive) classes. We may reconsider this in future if it's deemed to be beneficial.
         // And we cannot use it for classes outside the boot image as we do not know the runtime
         // value of their bitstring when compiling (it may not even get assigned at runtime).
-        if (descriptor[0] == 'L' && driver->IsImageClass(descriptor)) {
+        if (descriptor[0] == 'L' && driver->GetCompilerOptions().IsImageClass(descriptor)) {
           ObjPtr<mirror::Class> klass =
               class_linker->LookupResolvedType(type_index,
                                                dex_cache.Get(),
@@ -918,6 +885,16 @@
                                 const std::vector<const DexFile*>& dex_files,
                                 TimingLogger* timings) {
   CheckThreadPools();
+  VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
+
+  // Precompile:
+  // 1) Load image classes.
+  // 2) Resolve all classes.
+  // 3) For deterministic boot image, resolve strings for const-string instructions.
+  // 4) Attempt to verify all classes.
+  // 5) Attempt to initialize image classes, and trivially initialized classes.
+  // 6) Update the set of image classes.
+  // 7) For deterministic boot image, initialize bitstrings for type checking.
 
   LoadImageClasses(timings);
   VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
@@ -988,16 +965,6 @@
   }
 }
 
-bool CompilerDriver::IsImageClass(const char* descriptor) const {
-  if (image_classes_ != nullptr) {
-    // If we have a set of image classes, use those.
-    return image_classes_->find(StringPiece(descriptor)) != image_classes_->end();
-  }
-  // No set of image classes, assume we include all the classes.
-  // NOTE: Currently only reachable from InitImageMethodVisitor for the app image case.
-  return !GetCompilerOptions().IsBootImage();
-}
-
 bool CompilerDriver::IsClassToCompile(const char* descriptor) const {
   if (classes_to_compile_ == nullptr) {
     return true;
@@ -1116,7 +1083,7 @@
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  CHECK(image_classes_.get() != nullptr);
+  CHECK(image_classes_ != nullptr);
   for (auto it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
     const std::string& descriptor(*it);
     StackHandleScope<1> hs(self);
@@ -1174,7 +1141,7 @@
   // We walk the roots looking for classes so that we'll pick up the
   // above classes plus any classes them depend on such super
   // classes, interfaces, and the required ClassLinker roots.
-  RecordImageClassesVisitor visitor(image_classes_.get());
+  RecordImageClassesVisitor visitor(image_classes_);
   class_linker->VisitClasses(&visitor);
 
   CHECK(!image_classes_->empty());
@@ -1358,7 +1325,7 @@
     VariableSizedHandleScope hs(Thread::Current());
     std::string error_msg;
     std::unique_ptr<ClinitImageUpdate> update(ClinitImageUpdate::Create(hs,
-                                                                        image_classes_.get(),
+                                                                        image_classes_,
                                                                         Thread::Current(),
                                                                         runtime->GetClassLinker()));
 
@@ -1382,7 +1349,7 @@
   }
   std::string temp;
   const char* descriptor = klass->GetDescriptor(&temp);
-  return IsImageClass(descriptor);
+  return GetCompilerOptions().IsImageClass(descriptor);
 }
 
 bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class,
@@ -2292,7 +2259,7 @@
             (is_app_image || is_boot_image) &&
             is_superclass_initialized &&
             !too_many_encoded_fields &&
-            manager_->GetCompiler()->IsImageClass(descriptor)) {
+            manager_->GetCompiler()->GetCompilerOptions().IsImageClass(descriptor)) {
           bool can_init_static_fields = false;
           if (is_boot_image) {
             // We need to initialize static fields, we only do this for image classes that aren't
@@ -2982,8 +2949,7 @@
                                        const DexFile* inlined_into) const {
   // We're not allowed to inline across dex files if we're the no-inline-from dex file.
   if (inlined_from != inlined_into &&
-      compiler_options_->GetNoInlineFromDexFile() != nullptr &&
-      ContainsElement(*compiler_options_->GetNoInlineFromDexFile(), inlined_from)) {
+      ContainsElement(compiler_options_->GetNoInlineFromDexFile(), inlined_from)) {
     return false;
   }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ff70d96..36e93a8 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -99,7 +99,7 @@
                  Compiler::Kind compiler_kind,
                  InstructionSet instruction_set,
                  const InstructionSetFeatures* instruction_set_features,
-                 std::unique_ptr<HashSet<std::string>>&& image_classes,
+                 HashSet<std::string>* image_classes,
                  size_t thread_count,
                  int swap_fd,
                  const ProfileCompilationInfo* profile_compilation_info);
@@ -122,9 +122,18 @@
                   TimingLogger* timings)
       REQUIRES(!Locks::mutator_lock_);
 
-  // Compile a single Method.
-  void CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings)
-      REQUIRES_SHARED(Locks::mutator_lock_);
+  // Compile a single Method. (For testing only.)
+  void CompileOne(Thread* self,
+                  jobject class_loader,
+                  const DexFile& dex_file,
+                  uint16_t class_def_idx,
+                  uint32_t method_idx,
+                  uint32_t access_flags,
+                  InvokeType invoke_type,
+                  const DexFile::CodeItem* code_item,
+                  Handle<mirror::DexCache> dex_cache,
+                  Handle<mirror::ClassLoader> h_class_loader)
+      REQUIRES(!Locks::mutator_lock_);
 
   VerificationResults* GetVerificationResults() const;
 
@@ -144,10 +153,6 @@
     return compiler_.get();
   }
 
-  const HashSet<std::string>* GetImageClasses() const {
-    return image_classes_.get();
-  }
-
   // Generate the trampolines that are invoked by unresolved direct methods.
   std::unique_ptr<const std::vector<uint8_t>> CreateJniDlsymLookup() const;
   std::unique_ptr<const std::vector<uint8_t>> CreateQuickGenericJniTrampoline() const;
@@ -308,9 +313,6 @@
     return compiled_method_storage_.DedupeEnabled();
   }
 
-  // Checks if class specified by type_idx is one of the image_classes_
-  bool IsImageClass(const char* descriptor) const;
-
   // Checks whether the provided class should be compiled, i.e., is in classes_to_compile_.
   bool IsClassToCompile(const char* descriptor) const;
 
@@ -491,9 +493,11 @@
   // in the .oat_patches ELF section if requested in the compiler options.
   Atomic<size_t> non_relative_linker_patch_count_;
 
-  // If image_ is true, specifies the classes that will be included in the image.
-  // Note if image_classes_ is null, all classes are included in the image.
-  std::unique_ptr<HashSet<std::string>> image_classes_;
+  // Image classes to be updated by PreCompile().
+  // TODO: Remove this member which is a non-const pointer to the CompilerOptions' data.
+  //       Pass this explicitly to the PreCompile() which should be called directly from
+  //       Dex2Oat rather than implicitly by CompileAll().
+  HashSet<std::string>* image_classes_;
 
   // Specifies the classes that will be compiled. Note that if classes_to_compile_ is null,
   // all classes are eligible for compilation (duplication filters etc. will still apply).
@@ -505,8 +509,8 @@
   bool had_hard_verifier_failure_;
 
   // A thread pool that can (potentially) run tasks in parallel.
-  std::unique_ptr<ThreadPool> parallel_thread_pool_;
   size_t parallel_thread_count_;
+  std::unique_ptr<ThreadPool> parallel_thread_pool_;
 
   // A thread pool that guarantees running single-threaded on the main thread.
   std::unique_ptr<ThreadPool> single_thread_pool_;
@@ -534,6 +538,7 @@
   // Compiler for dex to dex (quickening).
   optimizer::DexToDexCompiler dex_to_dex_compiler_;
 
+  friend class CommonCompilerTest;
   friend class CompileClassVisitor;
   friend class DexToDexDecompilerTest;
   friend class verifier::VerifierDepsTest;
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 933be4f..3d37b68 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -37,7 +37,8 @@
       tiny_method_threshold_(kDefaultTinyMethodThreshold),
       num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
       inline_max_code_units_(kUnsetInlineMaxCodeUnits),
-      no_inline_from_(nullptr),
+      no_inline_from_(),
+      image_classes_(),
       boot_image_(false),
       core_image_(false),
       app_image_(false),
@@ -67,8 +68,8 @@
 }
 
 CompilerOptions::~CompilerOptions() {
-  // The destructor looks empty but it destroys a PassManagerOptions object. We keep it here
-  // because we don't want to include the PassManagerOptions definition from the header file.
+  // Everything done by member destructors.
+  // The definitions of classes forward-declared in the header have now been #included.
 }
 
 namespace {
@@ -129,4 +130,11 @@
 
 #pragma GCC diagnostic pop
 
+bool CompilerOptions::IsImageClass(const char* descriptor) const {
+  // Historical note: We used to hold the set indirectly and there was a distinction between an
+  // empty set and a null, null meaning to include all classes. However, the distiction has been
+  // removed; if we don't have a profile, we treat it as an empty set of classes. b/77340429
+  return image_classes_.find(StringPiece(descriptor)) != image_classes_.end();
+}
+
 }  // namespace art
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index cee989b..0709faf 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "base/globals.h"
+#include "base/hash_set.h"
 #include "base/macros.h"
 #include "base/utils.h"
 #include "compiler_filter.h"
@@ -230,10 +231,16 @@
     return abort_on_soft_verifier_failure_;
   }
 
-  const std::vector<const DexFile*>* GetNoInlineFromDexFile() const {
+  const std::vector<const DexFile*>& GetNoInlineFromDexFile() const {
     return no_inline_from_;
   }
 
+  const HashSet<std::string>& GetImageClasses() const {
+    return image_classes_;
+  }
+
+  bool IsImageClass(const char* descriptor) const;
+
   bool ParseCompilerOptions(const std::vector<std::string>& options,
                             bool ignore_unrecognized,
                             std::string* error_msg);
@@ -301,10 +308,14 @@
   size_t num_dex_methods_threshold_;
   size_t inline_max_code_units_;
 
-  // Dex files from which we should not inline code.
+  // Dex files from which we should not inline code. Does not own the dex files.
   // This is usually a very short list (i.e. a single dex file), so we
   // prefer vector<> over a lookup-oriented container, such as set<>.
-  const std::vector<const DexFile*>* no_inline_from_;
+  std::vector<const DexFile*> no_inline_from_;
+
+  // Image classes, specifies the classes that will be included in the image if creating an image.
+  // Must not be empty for real boot image, only for tests pretending to compile boot image.
+  HashSet<std::string> image_classes_;
 
   bool boot_image_;
   bool core_image_;
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 8a347df..7cda6e9 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1879,7 +1879,7 @@
   Handle<mirror::Class> klass = ResolveClass(soa, type_index);
   bool needs_access_check = LoadClassNeedsAccessCheck(klass);
   TypeCheckKind check_kind = HSharpening::ComputeTypeCheckKind(
-      klass.Get(), code_generator_, compiler_driver_, needs_access_check);
+      klass.Get(), code_generator_, needs_access_check);
 
   HInstruction* class_or_null = nullptr;
   HIntConstant* bitstring_path_to_root = nullptr;
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 6541043..ebac3f6 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -71,7 +71,8 @@
 }
 
 static bool BootImageAOTCanEmbedMethod(ArtMethod* method, CompilerDriver* compiler_driver) {
-  DCHECK(compiler_driver->GetCompilerOptions().IsBootImage());
+  const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
+  DCHECK(compiler_options.IsBootImage());
   if (!compiler_driver->GetSupportBootImageFixup()) {
     return false;
   }
@@ -79,7 +80,7 @@
   ObjPtr<mirror::Class> klass = method->GetDeclaringClass();
   DCHECK(klass != nullptr);
   const DexFile& dex_file = klass->GetDexFile();
-  return compiler_driver->IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex()));
+  return compiler_options.IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex()));
 }
 
 void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke,
@@ -177,14 +178,15 @@
     bool is_in_boot_image = false;
     HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid;
     Runtime* runtime = Runtime::Current();
-    if (codegen->GetCompilerOptions().IsBootImage()) {
+    const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
+    if (compiler_options.IsBootImage()) {
       // Compiling boot image. Check if the class is a boot image class.
       DCHECK(!runtime->UseJitCompilation());
       if (!compiler_driver->GetSupportBootImageFixup()) {
         // compiler_driver_test. Do not sharpen.
         desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
       } else if ((klass != nullptr) &&
-                 compiler_driver->IsImageClass(dex_file.StringByTypeIdx(type_index))) {
+                 compiler_options.IsImageClass(dex_file.StringByTypeIdx(type_index))) {
         is_in_boot_image = true;
         desired_load_kind = HLoadClass::LoadKind::kBootImageLinkTimePcRelative;
       } else {
@@ -241,9 +243,7 @@
   return load_kind;
 }
 
-static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass,
-                                            CodeGenerator* codegen,
-                                            CompilerDriver* compiler_driver)
+static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, CodeGenerator* codegen)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(!klass->IsProxyClass());
   DCHECK(!klass->IsArrayClass());
@@ -252,7 +252,7 @@
     // If we're JITting, try to assign a type check bitstring (fall through).
   } else if (codegen->GetCompilerOptions().IsBootImage()) {
     const char* descriptor = klass->GetDexFile().StringByTypeIdx(klass->GetDexTypeIndex());
-    if (!compiler_driver->IsImageClass(descriptor)) {
+    if (!codegen->GetCompilerOptions().IsImageClass(descriptor)) {
       return false;
     }
     // If the target is a boot image class, try to assign a type check bitstring (fall through).
@@ -281,7 +281,6 @@
 
 TypeCheckKind HSharpening::ComputeTypeCheckKind(ObjPtr<mirror::Class> klass,
                                                 CodeGenerator* codegen,
-                                                CompilerDriver* compiler_driver,
                                                 bool needs_access_check) {
   if (klass == nullptr) {
     return TypeCheckKind::kUnresolvedCheck;
@@ -299,7 +298,7 @@
     return TypeCheckKind::kExactCheck;
   } else if (kBitstringSubtypeCheckEnabled &&
              !needs_access_check &&
-             CanUseTypeCheckBitstring(klass, codegen, compiler_driver)) {
+             CanUseTypeCheckBitstring(klass, codegen)) {
     // TODO: We should not need the `!needs_access_check` check but getting rid of that
     // requires rewriting some optimizations in instruction simplifier.
     return TypeCheckKind::kBitstringCheck;
diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h
index 9ccbcaf..e777328 100644
--- a/compiler/optimizing/sharpening.h
+++ b/compiler/optimizing/sharpening.h
@@ -59,7 +59,6 @@
   // Used by the builder.
   static TypeCheckKind ComputeTypeCheckKind(ObjPtr<mirror::Class> klass,
                                             CodeGenerator* codegen,
-                                            CompilerDriver* compiler_driver,
                                             bool needs_access_check)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 6cd947c..779128f 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -642,7 +642,6 @@
       driver_(nullptr),
       opened_dex_files_maps_(),
       opened_dex_files_(),
-      no_inline_from_dex_files_(),
       avoid_storing_invocation_(false),
       swap_fd_(kInvalidFd),
       app_image_fd_(kInvalidFd),
@@ -1489,22 +1488,21 @@
     if (!IsImage()) {
       return;
     }
-    // If we don't have a profile, treat it as an empty set of classes. b/77340429
-    if (image_classes_ == nullptr) {
-      // May be non-null when --image-classes is passed in, in that case avoid clearing the list.
-      image_classes_.reset(new HashSet<std::string>());
-    }
     if (profile_compilation_info_ != nullptr) {
+      // TODO: The following comment looks outdated or misplaced.
       // Filter out class path classes since we don't want to include these in the image.
-      image_classes_.reset(
-          new HashSet<std::string>(profile_compilation_info_->GetClassDescriptors(dex_files_)));
-      VLOG(compiler) << "Loaded " << image_classes_->size()
+      HashSet<std::string> image_classes =
+          profile_compilation_info_->GetClassDescriptors(dex_files_);
+      VLOG(compiler) << "Loaded " << image_classes.size()
                      << " image class descriptors from profile";
       if (VLOG_IS_ON(compiler)) {
-        for (const std::string& s : *image_classes_) {
+        for (const std::string& s : image_classes) {
           LOG(INFO) << "Image class " << s;
         }
       }
+      // Note: If we have a profile, classes previously loaded for the --image-classes
+      // option are overwritten here.
+      compiler_options_->image_classes_.swap(image_classes);
     }
   }
 
@@ -1810,6 +1808,7 @@
         class_path_files = class_loader_context_->FlattenOpenedDexFiles();
       }
 
+      std::vector<const DexFile*> no_inline_from_dex_files;
       std::vector<const std::vector<const DexFile*>*> dex_file_vectors = {
           &class_linker->GetBootClassPath(),
           &class_path_files,
@@ -1832,14 +1831,14 @@
 
             if (android::base::StartsWith(dex_location, filter.c_str())) {
               VLOG(compiler) << "Disabling inlining from " << dex_file->GetLocation();
-              no_inline_from_dex_files_.push_back(dex_file);
+              no_inline_from_dex_files.push_back(dex_file);
               break;
             }
           }
         }
       }
-      if (!no_inline_from_dex_files_.empty()) {
-        compiler_options_->no_inline_from_ = &no_inline_from_dex_files_;
+      if (!no_inline_from_dex_files.empty()) {
+        compiler_options_->no_inline_from_.swap(no_inline_from_dex_files);
       }
     }
 
@@ -1848,7 +1847,7 @@
                                      compiler_kind_,
                                      instruction_set_,
                                      instruction_set_features_.get(),
-                                     std::move(image_classes_),
+                                     &compiler_options_->image_classes_,
                                      thread_count_,
                                      swap_fd_,
                                      profile_compilation_info_.get()));
@@ -2381,14 +2380,14 @@
 
   bool PrepareImageClasses() {
     // If --image-classes was specified, calculate the full list of classes to include in the image.
+    DCHECK(compiler_options_->image_classes_.empty());
     if (image_classes_filename_ != nullptr) {
-      image_classes_ =
+      std::unique_ptr<HashSet<std::string>> image_classes =
           ReadClasses(image_classes_zip_filename_, image_classes_filename_, "image");
-      if (image_classes_ == nullptr) {
+      if (image_classes == nullptr) {
         return false;
       }
-    } else if (IsBootImage()) {
-      image_classes_.reset(new HashSet<std::string>);
+      compiler_options_->image_classes_.swap(*image_classes);
     }
     return true;
   }
@@ -2704,8 +2703,7 @@
       LOG(ERROR) << "Failed to open input file " << input_filename;
       return nullptr;
     }
-    std::unique_ptr<T> result(
-        ReadCommentedInputStream<T>(*input_file, process));
+    std::unique_ptr<T> result = ReadCommentedInputStream<T>(*input_file, process);
     input_file->close();
     return result;
   }
@@ -2851,7 +2849,6 @@
   ImageHeader::StorageMode image_storage_mode_;
   const char* passes_to_run_filename_;
   const char* dirty_image_objects_filename_;
-  std::unique_ptr<HashSet<std::string>> image_classes_;
   std::unique_ptr<HashSet<std::string>> dirty_image_objects_;
   std::unique_ptr<std::vector<std::string>> passes_to_run_;
   bool multi_image_;
@@ -2872,9 +2869,6 @@
   std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps_;
   std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
 
-  // Note that this might contain pointers owned by class_loader_context_.
-  std::vector<const DexFile*> no_inline_from_dex_files_;
-
   bool avoid_storing_invocation_;
   std::string swap_file_name_;
   int swap_fd_;
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 12ecd3a..2acdf25 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -426,9 +426,6 @@
     image_file_sizes.push_back(file->GetLength());
   }
 
-  ASSERT_TRUE(compiler_driver_->GetImageClasses() != nullptr);
-  HashSet<std::string> image_classes(*compiler_driver_->GetImageClasses());
-
   // Need to delete the compiler since it has worker threads which are attached to runtime.
   compiler_driver_.reset();
 
@@ -469,6 +466,7 @@
 
   // We loaded the runtime with an explicit image, so it must exist.
   ASSERT_EQ(heap->GetBootImageSpaces().size(), image_file_sizes.size());
+  const HashSet<std::string>& image_classes = compiler_options_->GetImageClasses();
   for (size_t i = 0; i < helper.dex_file_locations.size(); ++i) {
     std::unique_ptr<const DexFile> dex(
         LoadExpectSingleDexFile(helper.dex_file_locations[i].c_str()));
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index a61ad8f..b98dc68 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -38,6 +38,7 @@
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_types.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "gc/accounting/card_table-inl.h"
@@ -851,7 +852,8 @@
   std::string temp;
   // Prune if not an image class, this handles any broken sets of image classes such as having a
   // class in the set but not it's superclass.
-  result = result || !compiler_driver_.IsImageClass(klass->GetDescriptor(&temp));
+  result = result ||
+           !compiler_driver_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp));
   bool my_early_exit = false;  // Only for ourselves, ignore caller.
   // Remove classes that failed to verify since we don't want to have java.lang.VerifyError in the
   // app image.
@@ -941,7 +943,7 @@
     return true;
   }
   std::string temp;
-  if (!compiler_driver_.IsImageClass(klass->GetDescriptor(&temp))) {
+  if (!compiler_driver_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp))) {
     return false;
   }
   if (compile_app_image_) {
@@ -1212,27 +1214,22 @@
 }
 
 void ImageWriter::CheckNonImageClassesRemoved() {
-  if (compiler_driver_.GetImageClasses() != nullptr) {
-    auto visitor = [&](Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
-      if (obj->IsClass() && !IsInBootImage(obj)) {
-        Class* klass = obj->AsClass();
-        if (!KeepClass(klass)) {
-          DumpImageClasses();
-          std::string temp;
-          CHECK(KeepClass(klass))
-              << Runtime::Current()->GetHeap()->GetVerification()->FirstPathFromRootSet(klass);
-        }
+  auto visitor = [&](Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (obj->IsClass() && !IsInBootImage(obj)) {
+      Class* klass = obj->AsClass();
+      if (!KeepClass(klass)) {
+        DumpImageClasses();
+        CHECK(KeepClass(klass))
+            << Runtime::Current()->GetHeap()->GetVerification()->FirstPathFromRootSet(klass);
       }
-    };
-    gc::Heap* heap = Runtime::Current()->GetHeap();
-    heap->VisitObjects(visitor);
-  }
+    }
+  };
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  heap->VisitObjects(visitor);
 }
 
 void ImageWriter::DumpImageClasses() {
-  auto image_classes = compiler_driver_.GetImageClasses();
-  CHECK(image_classes != nullptr);
-  for (const std::string& image_class : *image_classes) {
+  for (const std::string& image_class : compiler_driver_.GetCompilerOptions().GetImageClasses()) {
     LOG(INFO) << " " << image_class;
   }
 }
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 9951668..0ed9579 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -366,6 +366,7 @@
     zipped_dex_files_(),
     zipped_dex_file_locations_(),
     compiler_driver_(nullptr),
+    compiler_options_(nullptr),
     image_writer_(nullptr),
     compiling_boot_image_(compiling_boot_image),
     extract_dex_files_into_vdex_(true),
@@ -642,8 +643,7 @@
 }
 
 bool OatWriter::MayHaveCompiledMethods() const {
-  return CompilerFilter::IsAnyCompilationEnabled(
-      GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter());
+  return GetCompilerOptions().IsAnyCompilationEnabled();
 }
 
 bool OatWriter::WriteAndOpenDexFiles(
@@ -703,6 +703,16 @@
   return true;
 }
 
+// Initialize the writer with the given parameters.
+void OatWriter::Initialize(const CompilerDriver* compiler_driver,
+                           ImageWriter* image_writer,
+                           const std::vector<const DexFile*>& dex_files) {
+  compiler_driver_ = compiler_driver;
+  compiler_options_ = &compiler_driver->GetCompilerOptions();
+  image_writer_ = image_writer;
+  dex_files_ = &dex_files;
+}
+
 void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) {
   CHECK(write_state_ == WriteState::kPrepareLayout);
 
@@ -1157,7 +1167,7 @@
       size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid;
 
       {
-        const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
+        const CompilerOptions& compiler_options = writer_->GetCompilerOptions();
         ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
         uint32_t code_size = quick_code.size() * sizeof(uint8_t);
 
@@ -1238,7 +1248,7 @@
                                        OrderedMethodList ordered_methods)
       : LayoutReserveOffsetCodeMethodVisitor(writer,
                                              offset,
-                                             writer->GetCompilerDriver()->GetCompilerOptions(),
+                                             writer->GetCompilerOptions(),
                                              std::move(ordered_methods)) {
   }
 
@@ -1651,7 +1661,7 @@
     const DexFile::TypeId& type_id =
         dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
     const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
-    return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
+    return writer_->GetCompilerOptions().IsImageClass(class_descriptor);
   }
 
   // Check whether specified dex file is in the compiled oat file.
@@ -1717,7 +1727,7 @@
     // Ordered method visiting is only for compiled methods.
     DCHECK(writer_->MayHaveCompiledMethods());
 
-    if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) {
+    if (writer_->GetCompilerOptions().IsAotCompilationEnabled()) {
       // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
       if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
         dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
@@ -2388,9 +2398,9 @@
   // TODO: Remove unused trampoline offsets from the OatHeader (requires oat version change).
   oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
   oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
-  if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
+  if (GetCompilerOptions().IsBootImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
-    const bool generate_debug_info = compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo();
+    const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo();
     size_t adjusted_offset = offset;
 
     #define DO_TRAMPOLINE(field, fn_name)                                   \
@@ -2428,7 +2438,7 @@
 }
 
 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
-  if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
+  if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
     if (kOatWriterDebugOatCodeLayout) {
       LOG(INFO) << "InitOatCodeDexFiles: OatWriter("
                 << this << "), "
@@ -2741,7 +2751,7 @@
   }
 
   size_t current_offset = start_offset;
-  if (compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) {
+  if (GetCompilerOptions().IsQuickeningCompilationEnabled()) {
     std::vector<uint32_t> dex_files_indices;
     WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out);
     if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) {
@@ -3019,7 +3029,7 @@
 
   oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
   oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
-  if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
+  if (GetCompilerOptions().IsBootImage()) {
     CHECK_EQ(image_patch_delta, 0);
     CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
   } else {
@@ -3283,7 +3293,7 @@
 }
 
 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
-  if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
+  if (GetCompilerOptions().IsBootImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
 
     #define DO_TRAMPOLINE(field) \
@@ -3314,7 +3324,7 @@
 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
                                     size_t file_offset,
                                     size_t relative_offset) {
-  if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
+  if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
     // As with InitOatCodeDexFiles, also skip the writer if
     // compilation was disabled.
     if (kOatWriterDebugOatCodeLayout) {
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 619743e..ccafe05 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -42,6 +42,7 @@
 class BitVector;
 class CompiledMethod;
 class CompilerDriver;
+class CompilerOptions;
 class DexContainer;
 class ProfileCompilationInfo;
 class TimingLogger;
@@ -180,17 +181,13 @@
                             CopyOption copy_dex_files,
                             /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map,
                             /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
+  // Initialize the writer with the given parameters.
+  void Initialize(const CompilerDriver* compiler_driver,
+                  ImageWriter* image_writer,
+                  const std::vector<const DexFile*>& dex_files);
   bool WriteQuickeningInfo(OutputStream* vdex_out);
   bool WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps);
   bool WriteChecksumsAndVdexHeader(OutputStream* vdex_out);
-  // Initialize the writer with the given parameters.
-  void Initialize(const CompilerDriver* compiler,
-                  ImageWriter* image_writer,
-                  const std::vector<const DexFile*>& dex_files) {
-    compiler_driver_ = compiler;
-    image_writer_ = image_writer;
-    dex_files_ = &dex_files;
-  }
 
   // Prepare layout of remaining data.
   void PrepareLayout(MultiOatRelativePatcher* relative_patcher);
@@ -263,6 +260,11 @@
     return compiler_driver_;
   }
 
+  const CompilerOptions& GetCompilerOptions() const {
+    DCHECK(compiler_options_ != nullptr);
+    return *compiler_options_;
+  }
+
  private:
   class DexFileSource;
   class OatClassHeader;
@@ -388,6 +390,7 @@
   dchecked_vector<debug::MethodDebugInfo> method_info_;
 
   const CompilerDriver* compiler_driver_;
+  const CompilerOptions* compiler_options_;
   ImageWriter* image_writer_;
   const bool compiling_boot_image_;
   // Whether the dex files being compiled are going to be extracted to the vdex.