Move instruction_set_ to CompilerOptions.

Removes CompilerDriver dependency from ImageWriter and
several other classes.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: Pixel 2 XL boots.
Test: m test-art-target-gtest
Test: testrunner.py --target --optimizing
Change-Id: I3c5b8ff73732128b9c4fad9405231a216ea72465
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 52c767f..22720ce 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -153,11 +153,7 @@
   {
     ScopedObjectAccess soa(Thread::Current());
 
-    const InstructionSet instruction_set = kRuntimeISA;
-    // Take the default set of instruction features from the build.
-    instruction_set_features_ = InstructionSetFeatures::FromCppDefines();
-
-    runtime_->SetInstructionSet(instruction_set);
+    runtime_->SetInstructionSet(instruction_set_);
     for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) {
       CalleeSaveType type = CalleeSaveType(i);
       if (!runtime_->HasCalleeSaveMethod(type)) {
@@ -165,23 +161,48 @@
       }
     }
 
-    CreateCompilerDriver(compiler_kind_, instruction_set);
+    CreateCompilerDriver();
   }
 }
 
-void CommonCompilerTest::CreateCompilerDriver(Compiler::Kind kind,
-                                              InstructionSet isa,
-                                              size_t number_of_threads) {
+void CommonCompilerTest::ApplyInstructionSet() {
+  // Copy local instruction_set_ and instruction_set_features_ to *compiler_options_;
+  CHECK(instruction_set_features_ != nullptr);
+  if (instruction_set_ == InstructionSet::kThumb2) {
+    CHECK_EQ(InstructionSet::kArm, instruction_set_features_->GetInstructionSet());
+  } else {
+    CHECK_EQ(instruction_set_, instruction_set_features_->GetInstructionSet());
+  }
+  compiler_options_->instruction_set_ = instruction_set_;
+  compiler_options_->instruction_set_features_ =
+      InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap());
+  CHECK(compiler_options_->instruction_set_features_->Equals(instruction_set_features_.get()));
+}
+
+void CommonCompilerTest::OverrideInstructionSetFeatures(InstructionSet instruction_set,
+                                                        const std::string& variant) {
+  instruction_set_ = instruction_set;
+  std::string error_msg;
+  instruction_set_features_ =
+      InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
+  CHECK(instruction_set_features_ != nullptr) << error_msg;
+
+  if (compiler_options_ != nullptr) {
+    ApplyInstructionSet();
+  }
+}
+
+void CommonCompilerTest::CreateCompilerDriver() {
+  ApplyInstructionSet();
+
   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(),
+                                            compiler_kind_,
                                             &compiler_options_->image_classes_,
-                                            number_of_threads,
+                                            number_of_threads_,
                                             /* swap_fd */ -1,
                                             GetProfileCompilationInfo()));
   // We typically don't generate an image in unit tests, disable this optimization by default.
@@ -207,11 +228,6 @@
   compiler_kind_ = compiler_kind;
 }
 
-InstructionSet CommonCompilerTest::GetInstructionSet() const {
-  DCHECK(compiler_driver_.get() != nullptr);
-  return compiler_driver_->GetInstructionSet();
-}
-
 void CommonCompilerTest::TearDown() {
   compiler_driver_.reset();
   callbacks_.reset();
@@ -339,4 +355,8 @@
   compiler_driver_->dex_to_dex_compiler_.SetDexFiles(dex_files);
 }
 
+void CommonCompilerTest::ClearBootImageOption() {
+  compiler_options_->boot_image_ = false;
+}
+
 }  // namespace art
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index f070bbb..db38110 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -20,6 +20,8 @@
 #include <list>
 #include <vector>
 
+#include "arch/instruction_set.h"
+#include "arch/instruction_set_features.h"
 #include "base/hash_set.h"
 #include "common_runtime_test.h"
 #include "compiler.h"
@@ -55,15 +57,13 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  protected:
-  virtual void SetUp();
+  void SetUp() OVERRIDE;
 
-  virtual void SetUpRuntimeOptions(RuntimeOptions* options);
+  void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE;
 
   Compiler::Kind GetCompilerKind() const;
   void SetCompilerKind(Compiler::Kind compiler_kind);
 
-  InstructionSet GetInstructionSet() const;
-
   // Get the set of image classes given to the compiler-driver in SetUp.
   virtual std::unique_ptr<HashSet<std::string>> GetImageClasses();
 
@@ -73,7 +73,7 @@
     return CompilerFilter::kDefaultCompilerFilter;
   }
 
-  virtual void TearDown();
+  void TearDown() OVERRIDE;
 
   void CompileClass(mirror::ClassLoader* class_loader, const char* class_name)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -88,7 +88,10 @@
                             const char* method_name, const char* signature)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void CreateCompilerDriver(Compiler::Kind kind, InstructionSet isa, size_t number_of_threads = 2U);
+  void ApplyInstructionSet();
+  void OverrideInstructionSetFeatures(InstructionSet instruction_set, const std::string& variant);
+
+  void CreateCompilerDriver();
 
   void ReserveImageSpace();
 
@@ -96,12 +99,20 @@
 
   void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files);
 
+  void ClearBootImageOption();
+
   Compiler::Kind compiler_kind_ = Compiler::kOptimizing;
+  size_t number_of_threads_ = 2u;
+
+  InstructionSet instruction_set_ =
+      (kRuntimeISA == InstructionSet::kArm) ? InstructionSet::kThumb2 : kRuntimeISA;
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_
+      = InstructionSetFeatures::FromCppDefines();
+
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<VerificationResults> verification_results_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
-
 
  private:
   std::unique_ptr<MemMap> image_reservation_;
diff --git a/compiler/debug/dwarf/dwarf_test.h b/compiler/debug/dwarf/dwarf_test.h
index 9a7c604..6b039a7 100644
--- a/compiler/debug/dwarf/dwarf_test.h
+++ b/compiler/debug/dwarf/dwarf_test.h
@@ -28,7 +28,7 @@
 
 #include "base/os.h"
 #include "base/unix_file/fd_file.h"
-#include "common_runtime_test.h"
+#include "common_compiler_test.h"
 #include "gtest/gtest.h"
 #include "linker/elf_builder.h"
 #include "linker/file_output_stream.h"
@@ -39,7 +39,7 @@
 #define DW_CHECK(substring) Check(substring, false, __FILE__, __LINE__)
 #define DW_CHECK_NEXT(substring) Check(substring, true, __FILE__, __LINE__)
 
-class DwarfTest : public CommonRuntimeTest {
+class DwarfTest : public CommonCompilerTest {
  public:
   static constexpr bool kPrintObjdumpOutput = false;  // debugging.
 
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index fb6a72b..fcaa0cd 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -31,6 +31,7 @@
 #include "dex/dex_instruction-inl.h"
 #include "dex_to_dex_decompiler.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "driver/dex_compilation_unit.h"
 #include "mirror/dex_cache.h"
 #include "quicken_info.h"
@@ -609,7 +610,7 @@
   }
 
   // Create a `CompiledMethod`, with the quickened information in the vmap table.
-  InstructionSet instruction_set = driver_->GetInstructionSet();
+  InstructionSet instruction_set = driver_->GetCompilerOptions().GetInstructionSet();
   if (instruction_set == InstructionSet::kThumb2) {
     // Don't use the thumb2 instruction set to avoid the one off code delta.
     instruction_set = InstructionSet::kArm;
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index 42fbba5..aed04f9 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -31,8 +31,6 @@
   CompilerDriver driver(&compiler_options,
                         &verification_results,
                         Compiler::kOptimizing,
-                        /* instruction_set_ */ InstructionSet::kNone,
-                        /* instruction_set_features */ nullptr,
                         /* image_classes */ nullptr,
                         /* thread_count */ 1u,
                         /* swap_fd */ -1,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 66a8a57..7c13894 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -261,8 +261,6 @@
     const CompilerOptions* compiler_options,
     VerificationResults* verification_results,
     Compiler::Kind compiler_kind,
-    InstructionSet instruction_set,
-    const InstructionSetFeatures* instruction_set_features,
     HashSet<std::string>* image_classes,
     size_t thread_count,
     int swap_fd,
@@ -271,9 +269,6 @@
       verification_results_(verification_results),
       compiler_(Compiler::Create(this, compiler_kind)),
       compiler_kind_(compiler_kind),
-      instruction_set_(
-          instruction_set == InstructionSet::kArm ? InstructionSet::kThumb2 : instruction_set),
-      instruction_set_features_(instruction_set_features),
       requires_constructor_barrier_lock_("constructor barrier lock"),
       non_relative_linker_patch_count_(0u),
       image_classes_(std::move(image_classes)),
@@ -309,13 +304,15 @@
 }
 
 
-#define CREATE_TRAMPOLINE(type, abi, offset) \
-    if (Is64BitInstructionSet(instruction_set_)) { \
-      return CreateTrampoline64(instruction_set_, abi, \
-                                type ## _ENTRYPOINT_OFFSET(PointerSize::k64, offset)); \
-    } else { \
-      return CreateTrampoline32(instruction_set_, abi, \
-                                type ## _ENTRYPOINT_OFFSET(PointerSize::k32, offset)); \
+#define CREATE_TRAMPOLINE(type, abi, offset)                                            \
+    if (Is64BitInstructionSet(GetCompilerOptions().GetInstructionSet())) {              \
+      return CreateTrampoline64(GetCompilerOptions().GetInstructionSet(),               \
+                                abi,                                                    \
+                                type ## _ENTRYPOINT_OFFSET(PointerSize::k64, offset));  \
+    } else {                                                                            \
+      return CreateTrampoline32(GetCompilerOptions().GetInstructionSet(),               \
+                                abi,                                                    \
+                                type ## _ENTRYPOINT_OFFSET(PointerSize::k32, offset));  \
     }
 
 std::unique_ptr<const std::vector<uint8_t>> CompilerDriver::CreateJniDlsymLookup() const {
@@ -601,7 +598,7 @@
     if ((access_flags & kAccNative) != 0) {
       // Are we extracting only and have support for generic JNI down calls?
       if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
-          InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
+          InstructionSetHasGenericJniStub(driver->GetCompilerOptions().GetInstructionSet())) {
         // Leaving this empty will trigger the generic JNI version
       } else {
         // Query any JNI optimization annotations such as @FastNative or @CriticalNative.
@@ -2146,8 +2143,9 @@
           mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self());
           // Mark methods as pre-verified. If we don't do this, the interpreter will run with
           // access checks.
-          klass->SetSkipAccessChecksFlagOnAllMethods(
-              GetInstructionSetPointerSize(manager_->GetCompiler()->GetInstructionSet()));
+          InstructionSet instruction_set =
+              manager_->GetCompiler()->GetCompilerOptions().GetInstructionSet();
+          klass->SetSkipAccessChecksFlagOnAllMethods(GetInstructionSetPointerSize(instruction_set));
           klass->SetVerificationAttempted();
         }
         // Record the final class status if necessary.
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 54e1f37..8739dc3 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -97,8 +97,6 @@
   CompilerDriver(const CompilerOptions* compiler_options,
                  VerificationResults* verification_results,
                  Compiler::Kind compiler_kind,
-                 InstructionSet instruction_set,
-                 const InstructionSetFeatures* instruction_set_features,
                  HashSet<std::string>* image_classes,
                  size_t thread_count,
                  int swap_fd,
@@ -129,14 +127,6 @@
 
   VerificationResults* GetVerificationResults() const;
 
-  InstructionSet GetInstructionSet() const {
-    return instruction_set_;
-  }
-
-  const InstructionSetFeatures* GetInstructionSetFeatures() const {
-    return instruction_set_features_;
-  }
-
   const CompilerOptions& GetCompilerOptions() const {
     return *compiler_options_;
   }
@@ -451,9 +441,6 @@
   std::unique_ptr<Compiler> compiler_;
   Compiler::Kind compiler_kind_;
 
-  const InstructionSet instruction_set_;
-  const InstructionSetFeatures* const instruction_set_features_;
-
   // All class references that require constructor barriers. If the class reference is not in the
   // set then the result has not yet been computed.
   mutable ReaderWriterMutex requires_constructor_barrier_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index cc1af3e..62d547d 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -20,6 +20,8 @@
 
 #include "android-base/stringprintf.h"
 
+#include "arch/instruction_set.h"
+#include "arch/instruction_set_features.h"
 #include "base/runtime_debug.h"
 #include "base/variant_map.h"
 #include "cmdline_parser.h"
@@ -37,13 +39,14 @@
       tiny_method_threshold_(kDefaultTinyMethodThreshold),
       num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
       inline_max_code_units_(kUnsetInlineMaxCodeUnits),
+      instruction_set_(kRuntimeISA == InstructionSet::kArm ? InstructionSet::kThumb2 : kRuntimeISA),
+      instruction_set_features_(nullptr),
       no_inline_from_(),
       dex_files_for_oat_file_(),
       image_classes_(),
       boot_image_(false),
       core_image_(false),
       app_image_(false),
-      top_k_profile_threshold_(kDefaultTopKProfileThreshold),
       debuggable_(false),
       generate_debug_info_(kDefaultGenerateDebugInfo),
       generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
@@ -55,6 +58,7 @@
       dump_timings_(false),
       dump_pass_timings_(false),
       dump_stats_(false),
+      top_k_profile_threshold_(kDefaultTopKProfileThreshold),
       verbose_methods_(),
       abort_on_hard_verifier_failure_(false),
       abort_on_soft_verifier_failure_(false),
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 908ff33..601c914 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
 #define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
 
+#include <memory>
 #include <ostream>
 #include <string>
 #include <vector>
@@ -30,11 +31,17 @@
 
 namespace art {
 
+namespace jit {
+class JitCompiler;
+}  // namespace jit
+
 namespace verifier {
 class VerifierDepsTest;
 }  // namespace verifier
 
 class DexFile;
+enum class InstructionSet;
+class InstructionSetFeatures;
 
 class CompilerOptions FINAL {
  public:
@@ -231,6 +238,15 @@
     return abort_on_soft_verifier_failure_;
   }
 
+  InstructionSet GetInstructionSet() const {
+    return instruction_set_;
+  }
+
+  const InstructionSetFeatures* GetInstructionSetFeatures() const {
+    return instruction_set_features_.get();
+  }
+
+
   const std::vector<const DexFile*>& GetNoInlineFromDexFile() const {
     return no_inline_from_;
   }
@@ -312,6 +328,9 @@
   size_t num_dex_methods_threshold_;
   size_t inline_max_code_units_;
 
+  InstructionSet instruction_set_;
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
+
   // 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<>.
@@ -327,8 +346,6 @@
   bool boot_image_;
   bool core_image_;
   bool app_image_;
-  // When using a profile file only the top K% of the profiled samples will be compiled.
-  double top_k_profile_threshold_;
   bool debuggable_;
   bool generate_debug_info_;
   bool generate_mini_debug_info_;
@@ -341,6 +358,9 @@
   bool dump_pass_timings_;
   bool dump_stats_;
 
+  // When using a profile file only the top K% of the profiled samples will be compiled.
+  double top_k_profile_threshold_;
+
   // Vector of methods to have verbose output enabled for.
   std::vector<std::string> verbose_methods_;
 
@@ -380,6 +400,7 @@
   friend class Dex2Oat;
   friend class DexToDexDecompilerTest;
   friend class CommonCompilerTest;
+  friend class jit::JitCompiler;
   friend class verifier::VerifierDepsTest;
 
   template <class Base>
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 0de00a8..d7bd828 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -33,6 +33,7 @@
 #include "jit/debugger_interface.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
+#include "jit/jit_logger.h"
 #include "oat_file-inl.h"
 #include "oat_quick_method_header.h"
 #include "object_lock.h"
@@ -50,7 +51,7 @@
   VLOG(jit) << "loading jit compiler";
   auto* const jit_compiler = JitCompiler::Create();
   CHECK(jit_compiler != nullptr);
-  *generate_debug_info = jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo();
+  *generate_debug_info = jit_compiler->GetCompilerOptions().GetGenerateDebugInfo();
   VLOG(jit) << "Done loading jit compiler";
   return jit_compiler;
 }
@@ -72,10 +73,11 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
   DCHECK(jit_compiler != nullptr);
-  if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) {
+  const CompilerOptions& compiler_options = jit_compiler->GetCompilerOptions();
+  if (compiler_options.GetGenerateDebugInfo()) {
     const ArrayRef<mirror::Class*> types_array(types, count);
     std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForClasses(
-        kRuntimeISA, jit_compiler->GetCompilerDriver()->GetInstructionSetFeatures(), types_array);
+        kRuntimeISA, compiler_options.GetInstructionSetFeatures(), types_array);
     MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_);
     // We never free debug info for types, so we don't need to provide a handle
     // (which would have been otherwise used as identifier to remove it later).
@@ -103,44 +105,50 @@
   // Set debuggability based on the runtime value.
   compiler_options_->SetDebuggable(Runtime::Current()->IsJavaDebuggable());
 
-  const InstructionSet instruction_set = kRuntimeISA;
+  const InstructionSet instruction_set = compiler_options_->GetInstructionSet();
+  if (kRuntimeISA == InstructionSet::kArm) {
+    DCHECK_EQ(instruction_set, InstructionSet::kThumb2);
+  } else {
+    DCHECK_EQ(instruction_set, kRuntimeISA);
+  }
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features;
   for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) {
     VLOG(compiler) << "JIT compiler option " << option;
     std::string error_msg;
     if (option.starts_with("--instruction-set-variant=")) {
       StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
       VLOG(compiler) << "JIT instruction set variant " << str;
-      instruction_set_features_ = InstructionSetFeatures::FromVariant(
+      instruction_set_features = InstructionSetFeatures::FromVariant(
           instruction_set, str.as_string(), &error_msg);
-      if (instruction_set_features_ == nullptr) {
+      if (instruction_set_features == nullptr) {
         LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
       }
     } else if (option.starts_with("--instruction-set-features=")) {
       StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
       VLOG(compiler) << "JIT instruction set features " << str;
-      if (instruction_set_features_ == nullptr) {
-        instruction_set_features_ = InstructionSetFeatures::FromVariant(
+      if (instruction_set_features == nullptr) {
+        instruction_set_features = InstructionSetFeatures::FromVariant(
             instruction_set, "default", &error_msg);
-        if (instruction_set_features_ == nullptr) {
+        if (instruction_set_features == nullptr) {
           LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
         }
       }
-      instruction_set_features_ =
-          instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg);
-      if (instruction_set_features_ == nullptr) {
+      instruction_set_features =
+          instruction_set_features->AddFeaturesFromString(str.as_string(), &error_msg);
+      if (instruction_set_features == nullptr) {
         LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
       }
     }
   }
-  if (instruction_set_features_ == nullptr) {
-    instruction_set_features_ = InstructionSetFeatures::FromCppDefines();
+  if (instruction_set_features == nullptr) {
+    instruction_set_features = InstructionSetFeatures::FromCppDefines();
   }
+  compiler_options_->instruction_set_features_ = std::move(instruction_set_features);
+
   compiler_driver_.reset(new CompilerDriver(
       compiler_options_.get(),
       /* verification_results */ nullptr,
       Compiler::kOptimizing,
-      instruction_set,
-      instruction_set_features_.get(),
       /* image_classes */ nullptr,
       /* thread_count */ 1,
       /* swap_fd */ -1,
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index 31dc9e2..5840fec 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -18,18 +18,19 @@
 #define ART_COMPILER_JIT_JIT_COMPILER_H_
 
 #include "base/mutex.h"
-#include "compiled_method.h"
-#include "driver/compiler_driver.h"
-#include "driver/compiler_options.h"
-#include "jit_logger.h"
 
 namespace art {
 
 class ArtMethod;
-class InstructionSetFeatures;
+class CompiledMethod;
+class CompilerDriver;
+class CompilerOptions;
+class Thread;
 
 namespace jit {
 
+class JitLogger;
+
 class JitCompiler {
  public:
   static JitCompiler* Create();
@@ -39,8 +40,8 @@
   bool CompileMethod(Thread* self, ArtMethod* method, bool osr)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  CompilerOptions* GetCompilerOptions() const {
-    return compiler_options_.get();
+  const CompilerOptions& GetCompilerOptions() const {
+    return *compiler_options_.get();
   }
   CompilerDriver* GetCompilerDriver() const {
     return compiler_driver_.get();
@@ -49,7 +50,6 @@
  private:
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
   std::unique_ptr<JitLogger> jit_logger_;
 
   JitCompiler();
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 0902bf2..62e8e02 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -34,7 +34,6 @@
 #include "class_linker.h"
 #include "debug/dwarf/debug_frame_opcode_writer.h"
 #include "dex/dex_file-inl.h"
-#include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "jni/jni_env_ext.h"
@@ -115,7 +114,7 @@
 //   convention.
 //
 template <PointerSize kPointerSize>
-static JniCompiledMethod ArtJniCompileMethodInternal(CompilerDriver* driver,
+static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& compiler_options,
                                                      uint32_t access_flags,
                                                      uint32_t method_idx,
                                                      const DexFile& dex_file) {
@@ -124,8 +123,9 @@
   const bool is_static = (access_flags & kAccStatic) != 0;
   const bool is_synchronized = (access_flags & kAccSynchronized) != 0;
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
-  InstructionSet instruction_set = driver->GetInstructionSet();
-  const InstructionSetFeatures* instruction_set_features = driver->GetInstructionSetFeatures();
+  InstructionSet instruction_set = compiler_options.GetInstructionSet();
+  const InstructionSetFeatures* instruction_set_features =
+      compiler_options.GetInstructionSetFeatures();
 
   // i.e. if the method was annotated with @FastNative
   const bool is_fast_native = (access_flags & kAccFastNative) != 0u;
@@ -216,7 +216,6 @@
   // Assembler that holds generated instructions
   std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm =
       GetMacroAssembler<kPointerSize>(&allocator, instruction_set, instruction_set_features);
-  const CompilerOptions& compiler_options = driver->GetCompilerOptions();
   jni_asm->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo());
   jni_asm->SetEmitRunTimeChecksInDebugMode(compiler_options.EmitRunTimeChecksInDebugMode());
 
@@ -771,16 +770,16 @@
   }
 }
 
-JniCompiledMethod ArtQuickJniCompileMethod(CompilerDriver* compiler,
+JniCompiledMethod ArtQuickJniCompileMethod(const CompilerOptions& compiler_options,
                                            uint32_t access_flags,
                                            uint32_t method_idx,
                                            const DexFile& dex_file) {
-  if (Is64BitInstructionSet(compiler->GetInstructionSet())) {
+  if (Is64BitInstructionSet(compiler_options.GetInstructionSet())) {
     return ArtJniCompileMethodInternal<PointerSize::k64>(
-        compiler, access_flags, method_idx, dex_file);
+        compiler_options, access_flags, method_idx, dex_file);
   } else {
     return ArtJniCompileMethodInternal<PointerSize::k32>(
-        compiler, access_flags, method_idx, dex_file);
+        compiler_options, access_flags, method_idx, dex_file);
   }
 }
 
diff --git a/compiler/jni/quick/jni_compiler.h b/compiler/jni/quick/jni_compiler.h
index 1141994..313fcd3 100644
--- a/compiler/jni/quick/jni_compiler.h
+++ b/compiler/jni/quick/jni_compiler.h
@@ -25,7 +25,7 @@
 namespace art {
 
 class ArtMethod;
-class CompilerDriver;
+class CompilerOptions;
 class DexFile;
 
 class JniCompiledMethod {
@@ -62,7 +62,7 @@
   std::vector<uint8_t> cfi_;
 };
 
-JniCompiledMethod ArtQuickJniCompileMethod(CompilerDriver* compiler,
+JniCompiledMethod ArtQuickJniCompileMethod(const CompilerOptions& compiler_options,
                                            uint32_t access_flags,
                                            uint32_t method_idx,
                                            const DexFile& dex_file);
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 2589869..f53e60b 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -877,53 +877,45 @@
 }
 
 std::unique_ptr<CodeGenerator> CodeGenerator::Create(HGraph* graph,
-                                                     InstructionSet instruction_set,
-                                                     const InstructionSetFeatures& isa_features,
                                                      const CompilerOptions& compiler_options,
                                                      OptimizingCompilerStats* stats) {
   ArenaAllocator* allocator = graph->GetAllocator();
-  switch (instruction_set) {
+  switch (compiler_options.GetInstructionSet()) {
 #ifdef ART_ENABLE_CODEGEN_arm
     case InstructionSet::kArm:
     case InstructionSet::kThumb2: {
       return std::unique_ptr<CodeGenerator>(
-          new (allocator) arm::CodeGeneratorARMVIXL(
-              graph, *isa_features.AsArmInstructionSetFeatures(), compiler_options, stats));
+          new (allocator) arm::CodeGeneratorARMVIXL(graph, compiler_options, stats));
     }
 #endif
 #ifdef ART_ENABLE_CODEGEN_arm64
     case InstructionSet::kArm64: {
       return std::unique_ptr<CodeGenerator>(
-          new (allocator) arm64::CodeGeneratorARM64(
-              graph, *isa_features.AsArm64InstructionSetFeatures(), compiler_options, stats));
+          new (allocator) arm64::CodeGeneratorARM64(graph, compiler_options, stats));
     }
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips
     case InstructionSet::kMips: {
       return std::unique_ptr<CodeGenerator>(
-          new (allocator) mips::CodeGeneratorMIPS(
-              graph, *isa_features.AsMipsInstructionSetFeatures(), compiler_options, stats));
+          new (allocator) mips::CodeGeneratorMIPS(graph, compiler_options, stats));
     }
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips64
     case InstructionSet::kMips64: {
       return std::unique_ptr<CodeGenerator>(
-          new (allocator) mips64::CodeGeneratorMIPS64(
-              graph, *isa_features.AsMips64InstructionSetFeatures(), compiler_options, stats));
+          new (allocator) mips64::CodeGeneratorMIPS64(graph, compiler_options, stats));
     }
 #endif
 #ifdef ART_ENABLE_CODEGEN_x86
     case InstructionSet::kX86: {
       return std::unique_ptr<CodeGenerator>(
-          new (allocator) x86::CodeGeneratorX86(
-              graph, *isa_features.AsX86InstructionSetFeatures(), compiler_options, stats));
+          new (allocator) x86::CodeGeneratorX86(graph, compiler_options, stats));
     }
 #endif
 #ifdef ART_ENABLE_CODEGEN_x86_64
     case InstructionSet::kX86_64: {
       return std::unique_ptr<CodeGenerator>(
-          new (allocator) x86_64::CodeGeneratorX86_64(
-              graph, *isa_features.AsX86_64InstructionSetFeatures(), compiler_options, stats));
+          new (allocator) x86_64::CodeGeneratorX86_64(graph, compiler_options, stats));
     }
 #endif
     default:
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 03ae498..59f858e 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -188,8 +188,6 @@
   // Compiles the graph to executable instructions.
   void Compile(CodeAllocator* allocator);
   static std::unique_ptr<CodeGenerator> Create(HGraph* graph,
-                                               InstructionSet instruction_set,
-                                               const InstructionSetFeatures& isa_features,
                                                const CompilerOptions& compiler_options,
                                                OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGenerator();
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 85c5659..979a5d4 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1374,7 +1374,6 @@
 }
 
 CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph,
-                                       const Arm64InstructionSetFeatures& isa_features,
                                        const CompilerOptions& compiler_options,
                                        OptimizingCompilerStats* stats)
     : CodeGenerator(graph,
@@ -1391,7 +1390,6 @@
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetAllocator(), this),
       assembler_(graph->GetAllocator()),
-      isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       uint64_literals_(std::less<uint64_t>(),
@@ -1729,6 +1727,10 @@
   stream << DRegister(reg);
 }
 
+const Arm64InstructionSetFeatures& CodeGeneratorARM64::GetInstructionSetFeatures() const {
+  return *GetCompilerOptions().GetInstructionSetFeatures()->AsArm64InstructionSetFeatures();
+}
+
 void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
   if (constant->IsIntConstant()) {
     __ Mov(Register(destination), constant->AsIntConstant()->GetValue());
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 11ff78b..e62c16c 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -399,7 +399,6 @@
 class CodeGeneratorARM64 : public CodeGenerator {
  public:
   CodeGeneratorARM64(HGraph* graph,
-                     const Arm64InstructionSetFeatures& isa_features,
                      const CompilerOptions& compiler_options,
                      OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGeneratorARM64() {}
@@ -472,9 +471,7 @@
     return InstructionSet::kArm64;
   }
 
-  const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const {
-    return isa_features_;
-  }
+  const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const;
 
   void Initialize() OVERRIDE {
     block_labels_.resize(GetGraph()->GetBlocks().size());
@@ -890,7 +887,6 @@
   InstructionCodeGeneratorARM64 instruction_visitor_;
   ParallelMoveResolverARM64 move_resolver_;
   Arm64Assembler assembler_;
-  const Arm64InstructionSetFeatures& isa_features_;
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 6804340..6c8d563 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -1502,6 +1502,10 @@
   stream << vixl32::SRegister(reg);
 }
 
+const ArmInstructionSetFeatures& CodeGeneratorARMVIXL::GetInstructionSetFeatures() const {
+  return *GetCompilerOptions().GetInstructionSetFeatures()->AsArmInstructionSetFeatures();
+}
+
 static uint32_t ComputeSRegisterListMask(const SRegisterList& regs) {
   uint32_t mask = 0;
   for (uint32_t i = regs.GetFirstSRegister().GetCode();
@@ -2319,7 +2323,6 @@
 }
 
 CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph,
-                                           const ArmInstructionSetFeatures& isa_features,
                                            const CompilerOptions& compiler_options,
                                            OptimizingCompilerStats* stats)
     : CodeGenerator(graph,
@@ -2336,7 +2339,6 @@
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetAllocator(), this),
       assembler_(graph->GetAllocator()),
-      isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 4893d3c..ae19cdb 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -428,7 +428,6 @@
 class CodeGeneratorARMVIXL : public CodeGenerator {
  public:
   CodeGeneratorARMVIXL(HGraph* graph,
-                       const ArmInstructionSetFeatures& isa_features,
                        const CompilerOptions& compiler_options,
                        OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGeneratorARMVIXL() {}
@@ -475,6 +474,9 @@
 
   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kThumb2; }
+
+  const ArmInstructionSetFeatures& GetInstructionSetFeatures() const;
+
   // Helper method to move a 32-bit value between two locations.
   void Move32(Location destination, Location source);
 
@@ -523,8 +525,6 @@
 
   void Finalize(CodeAllocator* allocator) OVERRIDE;
 
-  const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { return isa_features_; }
-
   bool NeedsTwoRegisters(DataType::Type type) const OVERRIDE {
     return type == DataType::Type::kFloat64 || type == DataType::Type::kInt64;
   }
@@ -888,7 +888,6 @@
   ParallelMoveResolverARMVIXL move_resolver_;
 
   ArmVIXLAssembler assembler_;
-  const ArmInstructionSetFeatures& isa_features_;
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 112eb51..8c38824 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -997,7 +997,6 @@
 };
 
 CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
-                                     const MipsInstructionSetFeatures& isa_features,
                                      const CompilerOptions& compiler_options,
                                      OptimizingCompilerStats* stats)
     : CodeGenerator(graph,
@@ -1014,8 +1013,8 @@
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetAllocator(), this),
-      assembler_(graph->GetAllocator(), &isa_features),
-      isa_features_(isa_features),
+      assembler_(graph->GetAllocator(),
+                 compiler_options.GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
@@ -1912,6 +1911,10 @@
   stream << FRegister(reg);
 }
 
+const MipsInstructionSetFeatures& CodeGeneratorMIPS::GetInstructionSetFeatures() const {
+  return *GetCompilerOptions().GetInstructionSetFeatures()->AsMipsInstructionSetFeatures();
+}
+
 constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
 
 void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 9fdb385..9758d35 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -370,7 +370,6 @@
 class CodeGeneratorMIPS : public CodeGenerator {
  public:
   CodeGeneratorMIPS(HGraph* graph,
-                    const MipsInstructionSetFeatures& isa_features,
                     const CompilerOptions& compiler_options,
                     OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGeneratorMIPS() {}
@@ -509,9 +508,7 @@
 
   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; }
 
-  const MipsInstructionSetFeatures& GetInstructionSetFeatures() const {
-    return isa_features_;
-  }
+  const MipsInstructionSetFeatures& GetInstructionSetFeatures() const;
 
   MipsLabel* GetLabelOf(HBasicBlock* block) const {
     return CommonGetLabelOf<MipsLabel>(block_labels_, block);
@@ -695,7 +692,6 @@
   InstructionCodeGeneratorMIPS instruction_visitor_;
   ParallelMoveResolverMIPS move_resolver_;
   MipsAssembler assembler_;
-  const MipsInstructionSetFeatures& isa_features_;
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 9f86364..9682377 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -940,7 +940,6 @@
 };
 
 CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph,
-                                         const Mips64InstructionSetFeatures& isa_features,
                                          const CompilerOptions& compiler_options,
                                          OptimizingCompilerStats* stats)
     : CodeGenerator(graph,
@@ -957,8 +956,8 @@
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetAllocator(), this),
-      assembler_(graph->GetAllocator(), &isa_features),
-      isa_features_(isa_features),
+      assembler_(graph->GetAllocator(),
+                 compiler_options.GetInstructionSetFeatures()->AsMips64InstructionSetFeatures()),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       uint64_literals_(std::less<uint64_t>(),
@@ -1772,6 +1771,10 @@
   stream << FpuRegister(reg);
 }
 
+const Mips64InstructionSetFeatures& CodeGeneratorMIPS64::GetInstructionSetFeatures() const {
+  return *GetCompilerOptions().GetInstructionSetFeatures()->AsMips64InstructionSetFeatures();
+}
+
 void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint,
                                         HInstruction* instruction,
                                         uint32_t dex_pc,
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 25c886f..96306d1 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -352,7 +352,6 @@
 class CodeGeneratorMIPS64 : public CodeGenerator {
  public:
   CodeGeneratorMIPS64(HGraph* graph,
-                      const Mips64InstructionSetFeatures& isa_features,
                       const CompilerOptions& compiler_options,
                       OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGeneratorMIPS64() {}
@@ -484,9 +483,7 @@
 
   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips64; }
 
-  const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const {
-    return isa_features_;
-  }
+  const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const;
 
   Mips64Label* GetLabelOf(HBasicBlock* block) const {
     return CommonGetLabelOf<Mips64Label>(block_labels_, block);
@@ -657,7 +654,6 @@
   InstructionCodeGeneratorMIPS64 instruction_visitor_;
   ParallelMoveResolverMIPS64 move_resolver_;
   Mips64Assembler assembler_;
-  const Mips64InstructionSetFeatures& isa_features_;
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 12872ed..b03d72c 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -958,6 +958,10 @@
   stream << XmmRegister(reg);
 }
 
+const X86InstructionSetFeatures& CodeGeneratorX86::GetInstructionSetFeatures() const {
+  return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86InstructionSetFeatures();
+}
+
 size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
   __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
   return kX86WordSize;
@@ -1009,7 +1013,6 @@
 }
 
 CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
-                                   const X86InstructionSetFeatures& isa_features,
                                    const CompilerOptions& compiler_options,
                                    OptimizingCompilerStats* stats)
     : CodeGenerator(graph,
@@ -1027,7 +1030,6 @@
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetAllocator(), this),
       assembler_(graph->GetAllocator()),
-      isa_features_(isa_features),
       boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 7d18e2b..e947b9d 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -316,7 +316,6 @@
 class CodeGeneratorX86 : public CodeGenerator {
  public:
   CodeGeneratorX86(HGraph* graph,
-                   const X86InstructionSetFeatures& isa_features,
                    const CompilerOptions& compiler_options,
                    OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGeneratorX86() {}
@@ -390,6 +389,8 @@
     return InstructionSet::kX86;
   }
 
+  const X86InstructionSetFeatures& GetInstructionSetFeatures() const;
+
   // Helper method to move a 32bits value between two locations.
   void Move32(Location destination, Location source);
   // Helper method to move a 64bits value between two locations.
@@ -474,10 +475,6 @@
 
   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
 
-  const X86InstructionSetFeatures& GetInstructionSetFeatures() const {
-    return isa_features_;
-  }
-
   void AddMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base, int32_t offset) {
     method_address_offset_.Put(method_base->GetId(), offset);
   }
@@ -640,7 +637,6 @@
   InstructionCodeGeneratorX86 instruction_visitor_;
   ParallelMoveResolverX86 move_resolver_;
   X86Assembler assembler_;
-  const X86InstructionSetFeatures& isa_features_;
 
   // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo.
   // Also used for type/string patches for kBootImageRelRo (same linker patch as for methods).
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 9631c15..28f3abf 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1185,6 +1185,10 @@
   stream << FloatRegister(reg);
 }
 
+const X86_64InstructionSetFeatures& CodeGeneratorX86_64::GetInstructionSetFeatures() const {
+  return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86_64InstructionSetFeatures();
+}
+
 size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
   __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
   return kX86_64WordSize;
@@ -1239,7 +1243,6 @@
 // Use a fake return address register to mimic Quick.
 static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
 CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
-                                         const X86_64InstructionSetFeatures& isa_features,
                                          const CompilerOptions& compiler_options,
                                          OptimizingCompilerStats* stats)
       : CodeGenerator(graph,
@@ -1258,7 +1261,6 @@
         instruction_visitor_(graph, this),
         move_resolver_(graph->GetAllocator(), this),
         assembler_(graph->GetAllocator()),
-        isa_features_(isa_features),
         constant_area_start_(0),
         boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
         method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index cf862d3..0937f55 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -296,7 +296,6 @@
 class CodeGeneratorX86_64 : public CodeGenerator {
  public:
   CodeGeneratorX86_64(HGraph* graph,
-                  const X86_64InstructionSetFeatures& isa_features,
                   const CompilerOptions& compiler_options,
                   OptimizingCompilerStats* stats = nullptr);
   virtual ~CodeGeneratorX86_64() {}
@@ -370,6 +369,8 @@
     return InstructionSet::kX86_64;
   }
 
+  const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const;
+
   // Emit a write barrier.
   void MarkGCCard(CpuRegister temp,
                   CpuRegister card,
@@ -440,10 +441,6 @@
 
   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
 
-  const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const {
-    return isa_features_;
-  }
-
   // Fast path implementation of ReadBarrier::Barrier for a heap
   // reference field load when Baker's read barriers are used.
   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -606,7 +603,6 @@
   InstructionCodeGeneratorX86_64 instruction_visitor_;
   ParallelMoveResolverX86_64 move_resolver_;
   X86_64Assembler assembler_;
-  const X86_64InstructionSetFeatures& isa_features_;
 
   // Offset to the start of the constant area in the assembled code.
   // Used for fixups to the constant area.
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index a0fd5ff..86687e6 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -89,7 +89,8 @@
     HGraph* graph = CreateCFG(data);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
-    RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
+    OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
+    RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected);
   }
 }
 
@@ -100,7 +101,8 @@
     HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
-    RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
+    OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
+    RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected);
   }
 }
 
@@ -460,7 +462,8 @@
       block->InsertInstructionBefore(move, block->GetLastInstruction());
     };
 
-    RunCode(target_config, graph, hook_before_codegen, true, 0);
+    OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
+    RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, 0);
   }
 }
 
@@ -506,7 +509,8 @@
             new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
         block->InsertInstructionBefore(move, block->GetLastInstruction());
       };
-      RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+      OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
+      RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
     }
   }
 }
@@ -573,7 +577,8 @@
             new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
         block->InsertInstructionBefore(move, block->GetLastInstruction());
       };
-      RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+      OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
+      RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
     }
   }
 }
@@ -682,7 +687,8 @@
   block->AddInstruction(new (GetAllocator()) HReturn(comparison));
 
   graph->BuildDominatorTree();
-  RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
+  OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
+  RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, true, expected_result);
 }
 
 TEST_F(CodegenTest, ComparisonsInt) {
@@ -713,10 +719,9 @@
 
 #ifdef ART_ENABLE_CODEGEN_arm
 TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
-  std::unique_ptr<const ArmInstructionSetFeatures> features(
-      ArmInstructionSetFeatures::FromCppDefines());
+  OverrideInstructionSetFeatures(InstructionSet::kThumb2, "default");
   HGraph* graph = CreateGraph();
-  arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
+  arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_);
 
   codegen.Initialize();
 
@@ -737,10 +742,9 @@
 #ifdef ART_ENABLE_CODEGEN_arm64
 // Regression test for b/34760542.
 TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
-  std::unique_ptr<const Arm64InstructionSetFeatures> features(
-      Arm64InstructionSetFeatures::FromCppDefines());
+  OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
   HGraph* graph = CreateGraph();
-  arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
+  arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
 
   codegen.Initialize();
 
@@ -787,10 +791,9 @@
 
 // Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
 TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
-  std::unique_ptr<const Arm64InstructionSetFeatures> features(
-      Arm64InstructionSetFeatures::FromCppDefines());
+  OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
   HGraph* graph = CreateGraph();
-  arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
+  arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
 
   codegen.Initialize();
 
@@ -824,9 +827,9 @@
 
 #ifdef ART_ENABLE_CODEGEN_mips
 TEST_F(CodegenTest, MipsClobberRA) {
-  std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
-      MipsInstructionSetFeatures::FromCppDefines());
-  if (!CanExecute(InstructionSet::kMips) || features_mips->IsR6()) {
+  OverrideInstructionSetFeatures(InstructionSet::kMips, "mips32r");
+  CHECK(!instruction_set_features_->AsMipsInstructionSetFeatures()->IsR6());
+  if (!CanExecute(InstructionSet::kMips)) {
     // HMipsComputeBaseMethodAddress and the NAL instruction behind it
     // should only be generated on non-R6.
     return;
@@ -860,7 +863,7 @@
 
   graph->BuildDominatorTree();
 
-  mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
+  mips::CodeGeneratorMIPS codegenMIPS(graph, *compiler_options_);
   // Since there isn't HLoadClass or HLoadString, we need to manually indicate
   // that RA is clobbered and the method entry code should generate a stack frame
   // and preserve RA in it. And this is what we're testing here.
diff --git a/compiler/optimizing/codegen_test_utils.h b/compiler/optimizing/codegen_test_utils.h
index 792cfb5..9181126 100644
--- a/compiler/optimizing/codegen_test_utils.h
+++ b/compiler/optimizing/codegen_test_utils.h
@@ -17,17 +17,11 @@
 #ifndef ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
 #define ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
 
-#include "arch/arm/instruction_set_features_arm.h"
 #include "arch/arm/registers_arm.h"
-#include "arch/arm64/instruction_set_features_arm64.h"
 #include "arch/instruction_set.h"
-#include "arch/mips/instruction_set_features_mips.h"
 #include "arch/mips/registers_mips.h"
-#include "arch/mips64/instruction_set_features_mips64.h"
 #include "arch/mips64/registers_mips64.h"
-#include "arch/x86/instruction_set_features_x86.h"
 #include "arch/x86/registers_x86.h"
-#include "arch/x86_64/instruction_set_features_x86_64.h"
 #include "code_simulator.h"
 #include "code_simulator_container.h"
 #include "common_compiler_test.h"
@@ -101,10 +95,8 @@
 // to just overwrite the code generator.
 class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
  public:
-  TestCodeGeneratorARMVIXL(HGraph* graph,
-                           const ArmInstructionSetFeatures& isa_features,
-                           const CompilerOptions& compiler_options)
-      : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
+  TestCodeGeneratorARMVIXL(HGraph* graph, const CompilerOptions& compiler_options)
+      : arm::CodeGeneratorARMVIXL(graph, compiler_options) {
     AddAllocatedRegister(Location::RegisterLocation(arm::R6));
     AddAllocatedRegister(Location::RegisterLocation(arm::R7));
   }
@@ -145,10 +137,8 @@
 //   function.
 class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 {
  public:
-  TestCodeGeneratorARM64(HGraph* graph,
-                         const Arm64InstructionSetFeatures& isa_features,
-                         const CompilerOptions& compiler_options)
-      : arm64::CodeGeneratorARM64(graph, isa_features, compiler_options) {}
+  TestCodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options)
+      : arm64::CodeGeneratorARM64(graph, compiler_options) {}
 
   void MaybeGenerateMarkingRegisterCheck(int codem ATTRIBUTE_UNUSED,
                                          Location temp_loc ATTRIBUTE_UNUSED) OVERRIDE {
@@ -165,10 +155,8 @@
 #ifdef ART_ENABLE_CODEGEN_x86
 class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
  public:
-  TestCodeGeneratorX86(HGraph* graph,
-                       const X86InstructionSetFeatures& isa_features,
-                       const CompilerOptions& compiler_options)
-      : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
+  TestCodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
+      : x86::CodeGeneratorX86(graph, compiler_options) {
     // Save edi, we need it for getting enough registers for long multiplication.
     AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
   }
@@ -324,11 +312,11 @@
 
 template <typename Expected>
 static void RunCode(CodegenTargetConfig target_config,
+                    const CompilerOptions& compiler_options,
                     HGraph* graph,
                     std::function<void(HGraph*)> hook_before_codegen,
                     bool has_result,
                     Expected expected) {
-  CompilerOptions compiler_options;
   std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph,
                                                                            compiler_options));
   RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
@@ -336,55 +324,37 @@
 
 #ifdef ART_ENABLE_CODEGEN_arm
 CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
-  std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
-      ArmInstructionSetFeatures::FromCppDefines());
-  return new (graph->GetAllocator())
-      TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
+  return new (graph->GetAllocator()) TestCodeGeneratorARMVIXL(graph, compiler_options);
 }
 #endif
 
 #ifdef ART_ENABLE_CODEGEN_arm64
 CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
-  std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
-      Arm64InstructionSetFeatures::FromCppDefines());
-  return new (graph->GetAllocator())
-      TestCodeGeneratorARM64(graph, *features_arm64.get(), compiler_options);
+  return new (graph->GetAllocator()) TestCodeGeneratorARM64(graph, compiler_options);
 }
 #endif
 
 #ifdef ART_ENABLE_CODEGEN_x86
 CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  return new (graph->GetAllocator()) TestCodeGeneratorX86(
-      graph, *features_x86.get(), compiler_options);
+  return new (graph->GetAllocator()) TestCodeGeneratorX86(graph, compiler_options);
 }
 #endif
 
 #ifdef ART_ENABLE_CODEGEN_x86_64
 CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
-  std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
-     X86_64InstructionSetFeatures::FromCppDefines());
-  return new (graph->GetAllocator())
-      x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
+  return new (graph->GetAllocator()) x86_64::CodeGeneratorX86_64(graph, compiler_options);
 }
 #endif
 
 #ifdef ART_ENABLE_CODEGEN_mips
 CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
-  std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
-      MipsInstructionSetFeatures::FromCppDefines());
-  return new (graph->GetAllocator())
-      mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
+  return new (graph->GetAllocator()) mips::CodeGeneratorMIPS(graph, compiler_options);
 }
 #endif
 
 #ifdef ART_ENABLE_CODEGEN_mips64
 CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
-  std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
-      Mips64InstructionSetFeatures::FromCppDefines());
-  return new (graph->GetAllocator())
-      mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
+  return new (graph->GetAllocator()) mips64::CodeGeneratorMIPS64(graph, compiler_options);
 }
 #endif
 
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index d271047..b1436f8 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -16,8 +16,6 @@
 
 #include <functional>
 
-#include "arch/x86/instruction_set_features_x86.h"
-#include "code_generator_x86.h"
 #include "constant_folding.h"
 #include "dead_code_elimination.h"
 #include "driver/compiler_options.h"
@@ -60,9 +58,6 @@
     std::string actual_before = printer_before.str();
     EXPECT_EQ(expected_before, actual_before);
 
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegenX86(graph_, *features_x86.get(), CompilerOptions());
     HConstantFolding(graph_, "constant_folding").Run();
     GraphChecker graph_checker_cf(graph_);
     graph_checker_cf.Run();
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index adb6ce1..2774535 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -16,8 +16,6 @@
 
 #include "dead_code_elimination.h"
 
-#include "arch/x86/instruction_set_features_x86.h"
-#include "code_generator_x86.h"
 #include "driver/compiler_options.h"
 #include "graph_checker.h"
 #include "optimizing_unit_test.h"
@@ -45,9 +43,6 @@
   std::string actual_before = printer_before.str();
   ASSERT_EQ(actual_before, expected_before);
 
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), CompilerOptions());
   HDeadCodeElimination(graph, nullptr /* stats */, "dead_code_elimination").Run();
   GraphChecker graph_checker(graph);
   graph_checker.Run();
diff --git a/compiler/optimizing/emit_swap_mips_test.cc b/compiler/optimizing/emit_swap_mips_test.cc
index b63914f..293c1ab 100644
--- a/compiler/optimizing/emit_swap_mips_test.cc
+++ b/compiler/optimizing/emit_swap_mips_test.cc
@@ -28,11 +28,12 @@
 class EmitSwapMipsTest : public OptimizingUnitTest {
  public:
   void SetUp() OVERRIDE {
+    instruction_set_ = InstructionSet::kMips;
+    instruction_set_features_ = MipsInstructionSetFeatures::FromCppDefines();
+    OptimizingUnitTest::SetUp();
     graph_ = CreateGraph();
-    isa_features_ = MipsInstructionSetFeatures::FromCppDefines();
-    codegen_ = new (graph_->GetAllocator()) mips::CodeGeneratorMIPS(graph_,
-                                                                    *isa_features_.get(),
-                                                                    CompilerOptions());
+    codegen_.reset(
+        new (graph_->GetAllocator()) mips::CodeGeneratorMIPS(graph_, *compiler_options_));
     moves_ = new (GetAllocator()) HParallelMove(GetAllocator());
     test_helper_.reset(
         new AssemblerTestInfrastructure(GetArchitectureString(),
@@ -47,8 +48,10 @@
 
   void TearDown() OVERRIDE {
     test_helper_.reset();
-    isa_features_.reset();
+    codegen_.reset();
+    graph_ = nullptr;
     ResetPoolAndAllocator();
+    OptimizingUnitTest::TearDown();
   }
 
   // Get the typically used name for this architecture.
@@ -106,10 +109,9 @@
  protected:
   HGraph* graph_;
   HParallelMove* moves_;
-  mips::CodeGeneratorMIPS* codegen_;
+  std::unique_ptr<mips::CodeGeneratorMIPS> codegen_;
   mips::MipsAssembler* assembler_;
   std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
-  std::unique_ptr<const MipsInstructionSetFeatures> isa_features_;
 };
 
 TEST_F(EmitSwapMipsTest, TwoRegisters) {
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 72d53d2..a104070 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1783,7 +1783,7 @@
       graph_->GetArenaStack(),
       callee_dex_file,
       method_index,
-      compiler_driver_->GetInstructionSet(),
+      codegen_->GetCompilerOptions().GetInstructionSet(),
       invoke_type,
       graph_->IsDebuggable(),
       /* osr */ false,
@@ -1820,8 +1820,8 @@
     return false;
   }
 
-  if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph,
-                                                  compiler_driver_->GetInstructionSet())) {
+  if (!RegisterAllocator::CanAllocateRegistersFor(
+          *callee_graph, codegen_->GetCompilerOptions().GetInstructionSet())) {
     LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedRegisterAllocator)
         << "Method " << callee_dex_file.PrettyMethod(method_index)
         << " cannot be inlined because of the register allocator";
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index 9fa5b74..50bfe84 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -16,11 +16,9 @@
 
 #include <fstream>
 
-#include "arch/x86/instruction_set_features_x86.h"
 #include "base/arena_allocator.h"
 #include "builder.h"
 #include "code_generator.h"
-#include "code_generator_x86.h"
 #include "dex/dex_file.h"
 #include "dex/dex_instruction.h"
 #include "driver/compiler_options.h"
@@ -43,10 +41,8 @@
 void LinearizeTest::TestCode(const std::vector<uint16_t>& data,
                              const uint32_t (&expected_order)[number_of_blocks]) {
   HGraph* graph = CreateCFG(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   ASSERT_EQ(graph->GetLinearOrder().size(), number_of_blocks);
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 6666066..0fb90fb 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-#include "arch/x86/instruction_set_features_x86.h"
 #include "base/arena_allocator.h"
 #include "builder.h"
 #include "code_generator.h"
-#include "code_generator_x86.h"
 #include "dex/dex_file.h"
 #include "dex/dex_instruction.h"
 #include "driver/compiler_options.h"
@@ -63,10 +61,8 @@
 
   HGraph* graph = BuildGraph(data);
 
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
@@ -109,10 +105,8 @@
     Instruction::RETURN | 0 << 8);
 
   HGraph* graph = BuildGraph(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
@@ -158,10 +152,8 @@
     Instruction::RETURN | 0 << 8);
 
   HGraph* graph = BuildGraph(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   // Test for the 4 constant.
@@ -235,10 +227,8 @@
 
   HGraph* graph = BuildGraph(data);
   RemoveSuspendChecks(graph);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   // Test for the 0 constant.
@@ -312,10 +302,8 @@
     Instruction::RETURN | 0 << 8);
 
   HGraph* graph = BuildGraph(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   // Test for the 0 constant.
@@ -388,10 +376,8 @@
     Instruction::RETURN);
 
   HGraph* graph = BuildGraph(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   // Test for the 0 constant.
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 6621a03..72f995e 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-#include "arch/x86/instruction_set_features_x86.h"
 #include "base/arena_allocator.h"
 #include "builder.h"
 #include "code_generator.h"
-#include "code_generator_x86.h"
 #include "dex/dex_file.h"
 #include "dex/dex_instruction.h"
 #include "driver/compiler_options.h"
@@ -50,10 +48,8 @@
   HGraph* graph = CreateCFG(data);
   // `Inline` conditions into ifs.
   PrepareForRegisterAllocation(graph).Run();
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
-  SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
+  std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
+  SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
   liveness.Analyze();
 
   std::ostringstream buffer;
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index eda6bd1..72aa253 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -23,7 +23,7 @@
 #include "arch/mips64/instruction_set_features_mips64.h"
 #include "arch/x86/instruction_set_features_x86.h"
 #include "arch/x86_64/instruction_set_features_x86_64.h"
-#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "linear_order.h"
 #include "mirror/array-inl.h"
 #include "mirror/string.h"
@@ -427,12 +427,12 @@
 //
 
 HLoopOptimization::HLoopOptimization(HGraph* graph,
-                                     CompilerDriver* compiler_driver,
+                                     const CompilerOptions* compiler_options,
                                      HInductionVarAnalysis* induction_analysis,
                                      OptimizingCompilerStats* stats,
                                      const char* name)
     : HOptimization(graph, name, stats),
-      compiler_driver_(compiler_driver),
+      compiler_options_(compiler_options),
       induction_range_(induction_analysis),
       loop_allocator_(nullptr),
       global_allocator_(graph_->GetAllocator()),
@@ -454,8 +454,8 @@
       vector_header_(nullptr),
       vector_body_(nullptr),
       vector_index_(nullptr),
-      arch_loop_helper_(ArchNoOptsLoopHelper::Create(compiler_driver_ != nullptr
-                                                          ? compiler_driver_->GetInstructionSet()
+      arch_loop_helper_(ArchNoOptsLoopHelper::Create(compiler_options_ != nullptr
+                                                          ? compiler_options_->GetInstructionSet()
                                                           : InstructionSet::kNone,
                                                       global_allocator_)) {
 }
@@ -756,9 +756,9 @@
 //
 
 bool HLoopOptimization::TryUnrollingForBranchPenaltyReduction(LoopNode* node) {
-  // Don't run peeling/unrolling if compiler_driver_ is nullptr (i.e., running under tests)
+  // Don't run peeling/unrolling if compiler_options_ is nullptr (i.e., running under tests)
   // as InstructionSet is needed.
-  if (compiler_driver_ == nullptr) {
+  if (compiler_options_ == nullptr) {
     return false;
   }
 
@@ -802,9 +802,9 @@
 }
 
 bool HLoopOptimization::TryPeelingForLoopInvariantExitsElimination(LoopNode* node) {
-  // Don't run peeling/unrolling if compiler_driver_ is nullptr (i.e., running under tests)
+  // Don't run peeling/unrolling if compiler_options_ is nullptr (i.e., running under tests)
   // as InstructionSet is needed.
-  if (compiler_driver_ == nullptr) {
+  if (compiler_options_ == nullptr) {
     return false;
   }
 
@@ -1459,7 +1459,7 @@
 }
 
 uint32_t HLoopOptimization::GetVectorSizeInBytes() {
-  switch (compiler_driver_->GetInstructionSet()) {
+  switch (compiler_options_->GetInstructionSet()) {
     case InstructionSet::kArm:
     case InstructionSet::kThumb2:
       return 8;  // 64-bit SIMD
@@ -1469,8 +1469,8 @@
 }
 
 bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrictions) {
-  const InstructionSetFeatures* features = compiler_driver_->GetInstructionSetFeatures();
-  switch (compiler_driver_->GetInstructionSet()) {
+  const InstructionSetFeatures* features = compiler_options_->GetInstructionSetFeatures();
+  switch (compiler_options_->GetInstructionSet()) {
     case InstructionSet::kArm:
     case InstructionSet::kThumb2:
       // Allow vectorization for all ARM devices, because Android assumes that
diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h
index 191a93d..9743b25 100644
--- a/compiler/optimizing/loop_optimization.h
+++ b/compiler/optimizing/loop_optimization.h
@@ -27,7 +27,7 @@
 
 namespace art {
 
-class CompilerDriver;
+class CompilerOptions;
 class ArchNoOptsLoopHelper;
 
 /**
@@ -38,7 +38,7 @@
 class HLoopOptimization : public HOptimization {
  public:
   HLoopOptimization(HGraph* graph,
-                    CompilerDriver* compiler_driver,
+                    const CompilerOptions* compiler_options,
                     HInductionVarAnalysis* induction_analysis,
                     OptimizingCompilerStats* stats,
                     const char* name = kLoopOptimizationPassName);
@@ -243,8 +243,8 @@
   void RemoveDeadInstructions(const HInstructionList& list);
   bool CanRemoveCycle();  // Whether the current 'iset_' is removable.
 
-  // Compiler driver (to query ISA features).
-  const CompilerDriver* compiler_driver_;
+  // Compiler options (to query ISA features).
+  const CompilerOptions* compiler_options_;
 
   // Range information based on prior induction variable analysis.
   InductionVarRange induction_range_;
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index c21bd65..c7cc661 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -29,7 +29,8 @@
   LoopOptimizationTest()
       : graph_(CreateGraph()),
         iva_(new (GetAllocator()) HInductionVarAnalysis(graph_)),
-        loop_opt_(new (GetAllocator()) HLoopOptimization(graph_, nullptr, iva_, nullptr)) {
+        loop_opt_(new (GetAllocator()) HLoopOptimization(
+            graph_, /* compiler_options */ nullptr, iva_, /* stats */ nullptr)) {
     BuildGraph();
   }
 
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index d37c43d..a38bd24 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -40,6 +40,7 @@
 #include "constructor_fence_redundancy_elimination.h"
 #include "dead_code_elimination.h"
 #include "dex/code_item_accessors-inl.h"
+#include "driver/compiler_options.h"
 #include "driver/dex_compilation_unit.h"
 #include "gvn.h"
 #include "induction_var_analysis.h"
@@ -224,7 +225,7 @@
       case OptimizationPass::kLoopOptimization:
         CHECK(most_recent_induction != nullptr);
         opt = new (allocator) HLoopOptimization(
-            graph, driver, most_recent_induction, stats, pass_name);
+            graph, &codegen->GetCompilerOptions(), most_recent_induction, stats, pass_name);
         break;
       case OptimizationPass::kBoundsCheckElimination:
         CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr);
@@ -286,7 +287,7 @@
         break;
       case OptimizationPass::kScheduling:
         opt = new (allocator) HInstructionScheduling(
-            graph, driver->GetInstructionSet(), codegen, pass_name);
+            graph, codegen->GetCompilerOptions().GetInstructionSet(), codegen, pass_name);
         break;
       //
       // Arch-specific passes.
diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc
index 2e189fd..1c1cf28 100644
--- a/compiler/optimizing/optimizing_cfi_test.cc
+++ b/compiler/optimizing/optimizing_cfi_test.cc
@@ -47,25 +47,20 @@
   static constexpr bool kGenerateExpected = false;
 
   OptimizingCFITest()
-      : pool_and_allocator_(),
-        opts_(),
-        isa_features_(),
-        graph_(nullptr),
+      : graph_(nullptr),
         code_gen_(),
         blocks_(GetAllocator()->Adapter()) {}
 
-  ArenaAllocator* GetAllocator() { return pool_and_allocator_.GetAllocator(); }
-
   void SetUpFrame(InstructionSet isa) {
+    OverrideInstructionSetFeatures(isa, "default");
+
     // Ensure that slow-debug is off, so that there is no unexpected read-barrier check emitted.
     SetRuntimeDebugFlagsEnabled(false);
 
     // Setup simple context.
-    std::string error;
-    isa_features_ = InstructionSetFeatures::FromVariant(isa, "default", &error);
     graph_ = CreateGraph();
     // Generate simple frame with some spills.
-    code_gen_ = CodeGenerator::Create(graph_, isa, *isa_features_, opts_);
+    code_gen_ = CodeGenerator::Create(graph_, *compiler_options_);
     code_gen_->GetAssembler()->cfi().SetEnabled(true);
     code_gen_->InitializeCodeGenerationData();
     const int frame_size = 64;
@@ -148,9 +143,6 @@
     DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
   };
 
-  ArenaPoolAndAllocator pool_and_allocator_;
-  CompilerOptions opts_;
-  std::unique_ptr<const InstructionSetFeatures> isa_features_;
   HGraph* graph_;
   std::unique_ptr<CodeGenerator> code_gen_;
   ArenaVector<HBasicBlock*> blocks_;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 79ac6b9..84863e4 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -287,7 +287,7 @@
   uintptr_t GetEntryPointOf(ArtMethod* method) const OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize(
-        InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet())));
+        InstructionSetPointerSize(GetCompilerDriver()->GetCompilerOptions().GetInstructionSet())));
   }
 
   void Init() OVERRIDE;
@@ -460,7 +460,7 @@
                                               const DexCompilationUnit& dex_compilation_unit,
                                               PassObserver* pass_observer,
                                               VariableSizedHandleScope* handles) const {
-  switch (GetCompilerDriver()->GetInstructionSet()) {
+  switch (codegen->GetCompilerOptions().GetInstructionSet()) {
 #if defined(ART_ENABLE_CODEGEN_arm)
     case InstructionSet::kThumb2:
     case InstructionSet::kArm: {
@@ -758,7 +758,8 @@
                                               VariableSizedHandleScope* handles) const {
   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptBytecodeCompilation);
   CompilerDriver* compiler_driver = GetCompilerDriver();
-  InstructionSet instruction_set = compiler_driver->GetInstructionSet();
+  const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
+  InstructionSet instruction_set = compiler_options.GetInstructionSet();
   const DexFile& dex_file = *dex_compilation_unit.GetDexFile();
   uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex();
   const DexFile::CodeItem* code_item = dex_compilation_unit.GetCodeItem();
@@ -782,7 +783,6 @@
   // Implementation of the space filter: do not compile a code item whose size in
   // code units is bigger than 128.
   static constexpr size_t kSpaceFilterOptimizingThreshold = 128;
-  const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
   if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace)
       && (CodeItemInstructionAccessor(dex_file, code_item).InsnsSizeInCodeUnits() >
           kSpaceFilterOptimizingThreshold)) {
@@ -796,7 +796,7 @@
       arena_stack,
       dex_file,
       method_idx,
-      compiler_driver->GetInstructionSet(),
+      compiler_options.GetInstructionSet(),
       kInvalidInvokeType,
       compiler_driver->GetCompilerOptions().GetDebuggable(),
       osr);
@@ -813,9 +813,7 @@
 
   std::unique_ptr<CodeGenerator> codegen(
       CodeGenerator::Create(graph,
-                            instruction_set,
-                            *compiler_driver->GetInstructionSetFeatures(),
-                            compiler_driver->GetCompilerOptions(),
+                            compiler_options,
                             compilation_stats_.get()));
   if (codegen.get() == nullptr) {
     MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledNoCodegen);
@@ -903,7 +901,8 @@
     VariableSizedHandleScope* handles) const {
   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptIntrinsicCompilation);
   CompilerDriver* compiler_driver = GetCompilerDriver();
-  InstructionSet instruction_set = compiler_driver->GetInstructionSet();
+  const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
+  InstructionSet instruction_set = compiler_options.GetInstructionSet();
   const DexFile& dex_file = *dex_compilation_unit.GetDexFile();
   uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex();
 
@@ -921,7 +920,7 @@
       arena_stack,
       dex_file,
       method_idx,
-      compiler_driver->GetInstructionSet(),
+      compiler_driver->GetCompilerOptions().GetInstructionSet(),
       kInvalidInvokeType,
       compiler_driver->GetCompilerOptions().GetDebuggable(),
       /* osr */ false);
@@ -932,15 +931,12 @@
 
   std::unique_ptr<CodeGenerator> codegen(
       CodeGenerator::Create(graph,
-                            instruction_set,
-                            *compiler_driver->GetInstructionSetFeatures(),
-                            compiler_driver->GetCompilerOptions(),
+                            compiler_options,
                             compilation_stats_.get()));
   if (codegen.get() == nullptr) {
     return nullptr;
   }
-  codegen->GetAssembler()->cfi().SetEnabled(
-      compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo());
+  codegen->GetAssembler()->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo());
 
   PassObserver pass_observer(graph,
                              codegen.get(),
@@ -1095,7 +1091,7 @@
 
   if (kIsDebugBuild &&
       IsCompilingWithCoreImage() &&
-      IsInstructionSetSupported(compiler_driver->GetInstructionSet())) {
+      IsInstructionSetSupported(compiler_driver->GetCompilerOptions().GetInstructionSet())) {
     // For testing purposes, we put a special marker on method names
     // that should be compiled with this compiler (when the
     // instruction set is supported). This makes sure we're not
@@ -1112,7 +1108,8 @@
                                                uint32_t method_idx,
                                                const DexFile& dex_file,
                                                Handle<mirror::DexCache> dex_cache) const {
-  if (GetCompilerDriver()->GetCompilerOptions().IsBootImage()) {
+  const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
+  if (compiler_options.IsBootImage()) {
     ScopedObjectAccess soa(Thread::Current());
     Runtime* runtime = Runtime::Current();
     ArtMethod* method = runtime->GetClassLinker()->LookupResolvedMethod(
@@ -1154,7 +1151,7 @@
   }
 
   JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod(
-      GetCompilerDriver(), access_flags, method_idx, dex_file);
+      compiler_options, access_flags, method_idx, dex_file);
   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiledNativeStub);
   return CompiledMethod::SwapAllocCompiledMethod(
       GetCompilerDriver(),
@@ -1218,8 +1215,9 @@
   ArenaAllocator allocator(runtime->GetJitArenaPool());
 
   if (UNLIKELY(method->IsNative())) {
+    const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
     JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod(
-        GetCompilerDriver(), access_flags, method_idx, *dex_file);
+        compiler_options, access_flags, method_idx, *dex_file);
     ScopedNullHandle<mirror::ObjectArray<mirror::Object>> roots;
     ArenaSet<ArtMethod*, std::less<ArtMethod*>> cha_single_implementation_list(
         allocator.Adapter(kArenaAllocCHA));
@@ -1243,7 +1241,6 @@
       return false;
     }
 
-    const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
     if (compiler_options.GenerateAnyDebugInfo()) {
       const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
       const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
@@ -1420,8 +1417,8 @@
 
   // Create entry for the single method that we just compiled.
   std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT(
-      GetCompilerDriver()->GetInstructionSet(),
-      GetCompilerDriver()->GetInstructionSetFeatures(),
+      compiler_options.GetInstructionSet(),
+      compiler_options.GetInstructionSetFeatures(),
       mini_debug_info,
       ArrayRef<const debug::MethodDebugInfo>(&info, 1));
   MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index a70b066..7144775 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -40,6 +40,12 @@
 
 class RegisterAllocatorTest : public OptimizingUnitTest {
  protected:
+  void SetUp() OVERRIDE {
+    // This test is using the x86 ISA.
+    OverrideInstructionSetFeatures(InstructionSet::kX86, "default");
+    OptimizingUnitTest::SetUp();
+  }
+
   // These functions need to access private variables of LocationSummary, so we declare it
   // as a member of RegisterAllocatorTest, which we make a friend class.
   void SameAsFirstInputHint(Strategy strategy);
@@ -81,9 +87,7 @@
 
 bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) {
   HGraph* graph = CreateCFG(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   liveness.Analyze();
   std::unique_ptr<RegisterAllocator> register_allocator =
@@ -98,9 +102,7 @@
  */
 TEST_F(RegisterAllocatorTest, ValidateIntervals) {
   HGraph* graph = CreateGraph();
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
 
   // Test with two intervals of the same range.
@@ -324,9 +326,7 @@
     Instruction::GOTO | 0xF900);
 
   HGraph* graph = CreateCFG(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   liveness.Analyze();
   std::unique_ptr<RegisterAllocator> register_allocator =
@@ -359,9 +359,7 @@
     Instruction::RETURN_VOID);
 
   HGraph* graph = CreateCFG(data);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   liveness.Analyze();
 
@@ -412,9 +410,7 @@
 
   HGraph* graph = CreateCFG(data);
   SsaDeadPhiElimination(graph).Run();
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   liveness.Analyze();
   std::unique_ptr<RegisterAllocator> register_allocator =
@@ -438,9 +434,7 @@
 
   HGraph* graph = CreateCFG(data);
   SsaDeadPhiElimination(graph).Run();
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   liveness.Analyze();
   RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
@@ -566,9 +560,7 @@
 
   {
     HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -584,9 +576,7 @@
 
   {
     HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -604,9 +594,7 @@
 
   {
     HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -624,9 +612,7 @@
 
   {
     HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -689,9 +675,7 @@
 
   {
     HGraph* graph = BuildFieldReturn(&field, &ret);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -705,9 +689,7 @@
 
   {
     HGraph* graph = BuildFieldReturn(&field, &ret);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -761,9 +743,7 @@
 
   {
     HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -778,9 +758,7 @@
 
   {
     HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+    x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
     SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
     liveness.Analyze();
 
@@ -834,9 +812,7 @@
 void RegisterAllocatorTest::ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
   HInstruction *div;
   HGraph* graph = BuildDiv(&div);
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   liveness.Analyze();
 
@@ -934,9 +910,7 @@
       new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
   locations->SetOut(Location::RequiresRegister());
 
-  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-      X86InstructionSetFeatures::FromCppDefines());
-  x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
+  x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
   SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
   // Populate the instructions in the liveness object, to please the register allocator.
   for (size_t i = 0; i < 32; ++i) {
diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc
index d4cae72..7079e07 100644
--- a/compiler/optimizing/scheduler_test.cc
+++ b/compiler/optimizing/scheduler_test.cc
@@ -192,7 +192,9 @@
       HInstructionScheduling scheduling(graph, target_config.GetInstructionSet());
       scheduling.Run(/*only_optimize_loop_blocks*/ false, /*schedule_randomly*/ true);
 
+      OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
       RunCode(target_config,
+              *compiler_options_,
               graph,
               [](HGraph* graph_arg) { RemoveSuspendChecks(graph_arg); },
               has_result, expected);
diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc
index ae5e4e7..a683c69 100644
--- a/compiler/optimizing/ssa_liveness_analysis_test.cc
+++ b/compiler/optimizing/ssa_liveness_analysis_test.cc
@@ -28,18 +28,11 @@
 namespace art {
 
 class SsaLivenessAnalysisTest : public OptimizingUnitTest {
- public:
-  SsaLivenessAnalysisTest()
-      : graph_(CreateGraph()),
-        compiler_options_(),
-        instruction_set_(kRuntimeISA) {
-    std::string error_msg;
-    instruction_set_features_ =
-        InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg);
-    codegen_ = CodeGenerator::Create(graph_,
-                                     instruction_set_,
-                                     *instruction_set_features_,
-                                     compiler_options_);
+ protected:
+  void SetUp() OVERRIDE {
+    OptimizingUnitTest::SetUp();
+    graph_ = CreateGraph();
+    codegen_ = CodeGenerator::Create(graph_, *compiler_options_);
     CHECK(codegen_ != nullptr) << instruction_set_ << " is not a supported target architecture.";
     // Create entry block.
     entry_ = new (GetAllocator()) HBasicBlock(graph_);
@@ -57,9 +50,6 @@
   }
 
   HGraph* graph_;
-  CompilerOptions compiler_options_;
-  InstructionSet instruction_set_;
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
   std::unique_ptr<CodeGenerator> codegen_;
   HBasicBlock* entry_;
 };
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 708f6ff..a802442 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -610,7 +610,6 @@
  public:
   explicit Dex2Oat(TimingLogger* timings) :
       compiler_kind_(Compiler::kOptimizing),
-      instruction_set_(kRuntimeISA == InstructionSet::kArm ? InstructionSet::kThumb2 : kRuntimeISA),
       // Take the default set of instruction features from the build.
       image_file_location_oat_checksum_(0),
       image_file_location_oat_data_begin_(0),
@@ -700,25 +699,26 @@
   }
 
   void ParseInstructionSetVariant(const std::string& option, ParserOptions* parser_options) {
-    instruction_set_features_ = InstructionSetFeatures::FromVariant(
-        instruction_set_, option, &parser_options->error_msg);
-    if (instruction_set_features_.get() == nullptr) {
+    compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant(
+        compiler_options_->instruction_set_, option, &parser_options->error_msg);
+    if (compiler_options_->instruction_set_features_ == nullptr) {
       Usage("%s", parser_options->error_msg.c_str());
     }
   }
 
   void ParseInstructionSetFeatures(const std::string& option, ParserOptions* parser_options) {
-    if (instruction_set_features_ == nullptr) {
-      instruction_set_features_ = InstructionSetFeatures::FromVariant(
-          instruction_set_, "default", &parser_options->error_msg);
-      if (instruction_set_features_.get() == nullptr) {
+    if (compiler_options_->instruction_set_features_ == nullptr) {
+      compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant(
+          compiler_options_->instruction_set_, "default", &parser_options->error_msg);
+      if (compiler_options_->instruction_set_features_ == nullptr) {
         Usage("Problem initializing default instruction set features variant: %s",
               parser_options->error_msg.c_str());
       }
     }
-    instruction_set_features_ =
-        instruction_set_features_->AddFeaturesFromString(option, &parser_options->error_msg);
-    if (instruction_set_features_ == nullptr) {
+    compiler_options_->instruction_set_features_ =
+        compiler_options_->instruction_set_features_->AddFeaturesFromString(
+            option, &parser_options->error_msg);
+    if (compiler_options_->instruction_set_features_ == nullptr) {
       Usage("Error parsing '%s': %s", option.c_str(), parser_options->error_msg.c_str());
     }
   }
@@ -870,23 +870,23 @@
 
     // If no instruction set feature was given, use the default one for the target
     // instruction set.
-    if (instruction_set_features_.get() == nullptr) {
-      instruction_set_features_ = InstructionSetFeatures::FromVariant(
-         instruction_set_, "default", &parser_options->error_msg);
-      if (instruction_set_features_.get() == nullptr) {
+    if (compiler_options_->instruction_set_features_.get() == nullptr) {
+      compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant(
+          compiler_options_->instruction_set_, "default", &parser_options->error_msg);
+      if (compiler_options_->instruction_set_features_ == nullptr) {
         Usage("Problem initializing default instruction set features variant: %s",
               parser_options->error_msg.c_str());
       }
     }
 
-    if (instruction_set_ == kRuntimeISA) {
+    if (compiler_options_->instruction_set_ == kRuntimeISA) {
       std::unique_ptr<const InstructionSetFeatures> runtime_features(
           InstructionSetFeatures::FromCppDefines());
-      if (!instruction_set_features_->Equals(runtime_features.get())) {
+      if (!compiler_options_->GetInstructionSetFeatures()->Equals(runtime_features.get())) {
         LOG(WARNING) << "Mismatch between dex2oat instruction set features ("
-            << *instruction_set_features_ << ") and those of dex2oat executable ("
-            << *runtime_features <<") for the command line:\n"
-            << CommandLine();
+            << *compiler_options_->GetInstructionSetFeatures()
+            << ") and those of dex2oat executable (" << *runtime_features
+            << ") for the command line:\n" << CommandLine();
       }
     }
 
@@ -896,7 +896,7 @@
 
     // Checks are all explicit until we know the architecture.
     // Set the compilation target's implicit checks options.
-    switch (instruction_set_) {
+    switch (compiler_options_->GetInstructionSet()) {
       case InstructionSet::kArm:
       case InstructionSet::kThumb2:
       case InstructionSet::kArm64:
@@ -1215,10 +1215,10 @@
     AssignIfExists(args, M::Backend, &compiler_kind_);
     parser_options->requested_specific_compiler = args.Exists(M::Backend);
 
-    AssignIfExists(args, M::TargetInstructionSet, &instruction_set_);
+    AssignIfExists(args, M::TargetInstructionSet, &compiler_options_->instruction_set_);
     // arm actually means thumb2.
-    if (instruction_set_ == InstructionSet::kArm) {
-      instruction_set_ = InstructionSet::kThumb2;
+    if (compiler_options_->instruction_set_ == InstructionSet::kArm) {
+      compiler_options_->instruction_set_ = InstructionSet::kThumb2;
     }
 
     AssignTrueIfExists(args, M::Host, &is_host_);
@@ -1628,8 +1628,6 @@
         if (!oat_writers_[i]->WriteAndOpenDexFiles(
             vdex_files_[i].get(),
             rodata_.back(),
-            instruction_set_,
-            instruction_set_features_.get(),
             key_value_store_.get(),
             verify,
             update_input_vdex_,
@@ -1847,8 +1845,6 @@
     driver_.reset(new CompilerDriver(compiler_options_.get(),
                                      verification_results_.get(),
                                      compiler_kind_,
-                                     instruction_set_,
-                                     instruction_set_features_.get(),
                                      &compiler_options_->image_classes_,
                                      thread_count_,
                                      swap_fd_,
@@ -2021,7 +2017,7 @@
         VLOG(compiler) << "App image base=" << reinterpret_cast<void*>(image_base_);
       }
 
-      image_writer_.reset(new linker::ImageWriter(*driver_,
+      image_writer_.reset(new linker::ImageWriter(*compiler_options_,
                                                   image_base_,
                                                   compiler_options_->GetCompilePic(),
                                                   IsAppImage(),
@@ -2076,8 +2072,8 @@
 
     {
       TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_);
-      linker::MultiOatRelativePatcher patcher(instruction_set_,
-                                              instruction_set_features_.get(),
+      linker::MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(),
+                                              compiler_options_->GetInstructionSetFeatures(),
                                               driver_->GetCompiledMethodStorage());
       for (size_t i = 0, size = oat_files_.size(); i != size; ++i) {
         std::unique_ptr<linker::ElfWriter>& elf_writer = elf_writers_[i];
@@ -2486,17 +2482,14 @@
     elf_writers_.reserve(oat_files_.size());
     oat_writers_.reserve(oat_files_.size());
     for (const std::unique_ptr<File>& oat_file : oat_files_) {
-      elf_writers_.emplace_back(linker::CreateElfWriterQuick(instruction_set_,
-                                                             instruction_set_features_.get(),
-                                                             compiler_options_.get(),
-                                                             oat_file.get()));
+      elf_writers_.emplace_back(linker::CreateElfWriterQuick(*compiler_options_, oat_file.get()));
       elf_writers_.back()->Start();
       bool do_oat_writer_layout = DoDexLayoutOptimizations() || DoOatLayoutOptimizations();
       if (profile_compilation_info_ != nullptr && profile_compilation_info_->IsEmpty()) {
         do_oat_writer_layout = false;
       }
       oat_writers_.emplace_back(new linker::OatWriter(
-          IsBootImage(),
+          *compiler_options_,
           timings_,
           do_oat_writer_layout ? profile_compilation_info_.get() : nullptr,
           compact_dex_level_));
@@ -2544,7 +2537,8 @@
 
     raw_options.push_back(std::make_pair("compilercallbacks", callbacks));
     raw_options.push_back(
-        std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_)));
+        std::make_pair("imageinstructionset",
+                       GetInstructionSetString(compiler_options_->GetInstructionSet())));
 
     // Only allow no boot image for the runtime if we're compiling one. When we compile an app,
     // we don't want fallback mode, it will abort as we do not push a boot classpath (it might
@@ -2607,7 +2601,7 @@
     SetThreadName(kIsDebugBuild ? "dex2oatd" : "dex2oat");
 
     runtime_.reset(Runtime::Current());
-    runtime_->SetInstructionSet(instruction_set_);
+    runtime_->SetInstructionSet(compiler_options_->GetInstructionSet());
     for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) {
       CalleeSaveType type = CalleeSaveType(i);
       if (!runtime_->HasCalleeSaveMethod(type)) {
@@ -2802,9 +2796,6 @@
   std::unique_ptr<CompilerOptions> compiler_options_;
   Compiler::Kind compiler_kind_;
 
-  InstructionSet instruction_set_;
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
-
   uint32_t image_file_location_oat_checksum_;
   uintptr_t image_file_location_oat_data_begin_;
   int32_t image_patch_delta_;
diff --git a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
index 3fe97e1..3d7277a 100644
--- a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
+++ b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
@@ -197,10 +197,7 @@
     OptimizingUnitTestHelper helper;
     HGraph* graph = helper.CreateGraph();
     std::string error_msg;
-    ArmFeaturesUniquePtr features =
-        ArmInstructionSetFeatures::FromVariant("default", &error_msg);
-    CompilerOptions options;
-    arm::CodeGeneratorARMVIXL codegen(graph, *features, options);
+    arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_);
     ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter());
     codegen.EmitThunkCode(patch, &code, debug_name);
     return std::vector<uint8_t>(code.begin(), code.end());
diff --git a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
index 393733d..07e6860 100644
--- a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
+++ b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
@@ -176,10 +176,7 @@
     OptimizingUnitTestHelper helper;
     HGraph* graph = helper.CreateGraph();
     std::string error_msg;
-    Arm64FeaturesUniquePtr features =
-        Arm64InstructionSetFeatures::FromVariant("default", &error_msg);
-    CompilerOptions options;
-    arm64::CodeGeneratorARM64 codegen(graph, *features, options);
+    arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
     ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter());
     codegen.EmitThunkCode(patch, &code, debug_name);
     return std::vector<uint8_t>(code.begin(), code.end());
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 58bd1b0..8f6ff70 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -96,9 +96,7 @@
 template <typename ElfTypes>
 class ElfWriterQuick FINAL : public ElfWriter {
  public:
-  ElfWriterQuick(InstructionSet instruction_set,
-                 const InstructionSetFeatures* features,
-                 const CompilerOptions* compiler_options,
+  ElfWriterQuick(const CompilerOptions& compiler_options,
                  File* elf_file);
   ~ElfWriterQuick();
 
@@ -129,8 +127,7 @@
                                std::vector<uint8_t>* buffer);
 
  private:
-  const InstructionSetFeatures* instruction_set_features_;
-  const CompilerOptions* const compiler_options_;
+  const CompilerOptions& compiler_options_;
   File* const elf_file_;
   size_t rodata_size_;
   size_t text_size_;
@@ -147,30 +144,18 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
 };
 
-std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set,
-                                                const InstructionSetFeatures* features,
-                                                const CompilerOptions* compiler_options,
+std::unique_ptr<ElfWriter> CreateElfWriterQuick(const CompilerOptions& compiler_options,
                                                 File* elf_file) {
-  if (Is64BitInstructionSet(instruction_set)) {
-    return std::make_unique<ElfWriterQuick<ElfTypes64>>(instruction_set,
-                                                        features,
-                                                        compiler_options,
-                                                        elf_file);
+  if (Is64BitInstructionSet(compiler_options.GetInstructionSet())) {
+    return std::make_unique<ElfWriterQuick<ElfTypes64>>(compiler_options, elf_file);
   } else {
-    return std::make_unique<ElfWriterQuick<ElfTypes32>>(instruction_set,
-                                                        features,
-                                                        compiler_options,
-                                                        elf_file);
+    return std::make_unique<ElfWriterQuick<ElfTypes32>>(compiler_options, elf_file);
   }
 }
 
 template <typename ElfTypes>
-ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set,
-                                         const InstructionSetFeatures* features,
-                                         const CompilerOptions* compiler_options,
-                                         File* elf_file)
+ElfWriterQuick<ElfTypes>::ElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file)
     : ElfWriter(),
-      instruction_set_features_(features),
       compiler_options_(compiler_options),
       elf_file_(elf_file),
       rodata_size_(0u),
@@ -180,7 +165,9 @@
       dex_section_size_(0u),
       output_stream_(
           std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(elf_file))),
-      builder_(new ElfBuilder<ElfTypes>(instruction_set, features, output_stream_.get())) {}
+      builder_(new ElfBuilder<ElfTypes>(compiler_options_.GetInstructionSet(),
+                                        compiler_options_.GetInstructionSetFeatures(),
+                                        output_stream_.get())) {}
 
 template <typename ElfTypes>
 ElfWriterQuick<ElfTypes>::~ElfWriterQuick() {}
@@ -188,7 +175,7 @@
 template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::Start() {
   builder_->Start();
-  if (compiler_options_->GetGenerateBuildId()) {
+  if (compiler_options_.GetGenerateBuildId()) {
     builder_->GetBuildId()->AllocateVirtualMemory(builder_->GetBuildId()->GetSize());
     builder_->WriteBuildIdSection();
   }
@@ -272,12 +259,12 @@
 
 template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(const debug::DebugInfo& debug_info) {
-  if (!debug_info.Empty() && compiler_options_->GetGenerateMiniDebugInfo()) {
+  if (!debug_info.Empty() && compiler_options_.GetGenerateMiniDebugInfo()) {
     // Prepare the mini-debug-info in background while we do other I/O.
     Thread* self = Thread::Current();
     debug_info_task_ = std::unique_ptr<DebugInfoTask>(
         new DebugInfoTask(builder_->GetIsa(),
-                          instruction_set_features_,
+                          compiler_options_.GetInstructionSetFeatures(),
                           builder_->GetText()->GetAddress(),
                           text_size_,
                           builder_->GetDex()->Exists() ? builder_->GetDex()->GetAddress() : 0,
@@ -293,11 +280,11 @@
 template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::WriteDebugInfo(const debug::DebugInfo& debug_info) {
   if (!debug_info.Empty()) {
-    if (compiler_options_->GetGenerateDebugInfo()) {
+    if (compiler_options_.GetGenerateDebugInfo()) {
       // Generate all the debug information we can.
       debug::WriteDebugInfo(builder_.get(), debug_info, kCFIFormat, true /* write_oat_patches */);
     }
-    if (compiler_options_->GetGenerateMiniDebugInfo()) {
+    if (compiler_options_.GetGenerateMiniDebugInfo()) {
       // Wait for the mini-debug-info generation to finish and write it to disk.
       Thread* self = Thread::Current();
       DCHECK(debug_info_thread_pool_ != nullptr);
@@ -310,7 +297,7 @@
 template <typename ElfTypes>
 bool ElfWriterQuick<ElfTypes>::End() {
   builder_->End();
-  if (compiler_options_->GetGenerateBuildId()) {
+  if (compiler_options_.GetGenerateBuildId()) {
     uint8_t build_id[ElfBuilder<ElfTypes>::kBuildIdLen];
     ComputeFileBuildId(&build_id);
     builder_->WriteBuildId(build_id);
diff --git a/dex2oat/linker/elf_writer_quick.h b/dex2oat/linker/elf_writer_quick.h
index 274d18b..333c6e3 100644
--- a/dex2oat/linker/elf_writer_quick.h
+++ b/dex2oat/linker/elf_writer_quick.h
@@ -30,9 +30,7 @@
 
 namespace linker {
 
-std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set,
-                                                const InstructionSetFeatures* features,
-                                                const CompilerOptions* compiler_options,
+std::unique_ptr<ElfWriter> CreateElfWriterQuick(const CompilerOptions& compiler_options,
                                                 File* elf_file);
 
 }  // namespace linker
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 66b37fb..fa8c778 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -35,6 +35,7 @@
 #include "compiler_callbacks.h"
 #include "debug/method_debug_info.h"
 #include "dex/quick_compiler_callbacks.h"
+#include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 #include "gc/space/image_space.h"
 #include "image_writer.h"
@@ -211,7 +212,7 @@
     ++image_idx;
   }
   // TODO: compile_pic should be a test argument.
-  std::unique_ptr<ImageWriter> writer(new ImageWriter(*driver,
+  std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_options_,
                                                       kRequestedImageBase,
                                                       /*compile_pic*/false,
                                                       /*compile_app_image*/false,
@@ -242,12 +243,9 @@
       std::vector<std::unique_ptr<ElfWriter>> elf_writers;
       std::vector<std::unique_ptr<OatWriter>> oat_writers;
       for (ScratchFile& oat_file : out_helper.oat_files) {
-        elf_writers.emplace_back(CreateElfWriterQuick(driver->GetInstructionSet(),
-                                                      driver->GetInstructionSetFeatures(),
-                                                      &driver->GetCompilerOptions(),
-                                                      oat_file.GetFile()));
+        elf_writers.emplace_back(CreateElfWriterQuick(*compiler_options_, oat_file.GetFile()));
         elf_writers.back()->Start();
-        oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true,
+        oat_writers.emplace_back(new OatWriter(*compiler_options_,
                                                &timings,
                                                /*profile_compilation_info*/nullptr,
                                                CompactDexLevel::kCompactDexLevelNone));
@@ -272,8 +270,6 @@
         bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles(
             out_helper.vdex_files[i].GetFile(),
             rodata.back(),
-            driver->GetInstructionSet(),
-            driver->GetInstructionSetFeatures(),
             &key_value_store,
             /* verify */ false,           // Dex files may be dex-to-dex-ed, don't verify.
             /* update_input_vdex */ false,
@@ -299,8 +295,8 @@
 
       DCHECK_EQ(out_helper.vdex_files.size(), out_helper.oat_files.size());
       for (size_t i = 0, size = out_helper.oat_files.size(); i != size; ++i) {
-        MultiOatRelativePatcher patcher(driver->GetInstructionSet(),
-                                        driver->GetInstructionSetFeatures(),
+        MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(),
+                                        compiler_options_->GetInstructionSetFeatures(),
                                         driver->GetCompiledMethodStorage());
         OatWriter* const oat_writer = oat_writers[i].get();
         ElfWriter* const elf_writer = elf_writers[i].get();
@@ -381,7 +377,8 @@
   for (const std::string& image_class : image_classes) {
     image_classes_.insert(image_class);
   }
-  CreateCompilerDriver(Compiler::kOptimizing, kRuntimeISA, kIsTargetBuild ? 2U : 16U);
+  number_of_threads_ = kIsTargetBuild ? 2U : 16U;
+  CreateCompilerDriver();
   // Set inline filter values.
   compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
   image_classes_.clear();
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index bb730d3..8778cd8 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -37,7 +37,6 @@
 #include "compiled_method.h"
 #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"
@@ -137,7 +136,7 @@
 }
 
 bool ImageWriter::PrepareImageAddressSpace(TimingLogger* timings) {
-  target_ptr_size_ = InstructionSetPointerSize(compiler_driver_.GetInstructionSet());
+  target_ptr_size_ = InstructionSetPointerSize(compiler_options_.GetInstructionSet());
   gc::Heap* const heap = Runtime::Current()->GetHeap();
   {
     ScopedObjectAccess soa(Thread::Current());
@@ -439,10 +438,10 @@
 }
 
 void ImageWriter::PrepareDexCacheArraySlots() {
-  // Prepare dex cache array starts based on the ordering specified in the CompilerDriver.
+  // Prepare dex cache array starts based on the ordering specified in the CompilerOptions.
   // Set the slot size early to avoid DCHECK() failures in IsImageBinSlotAssigned()
   // when AssignImageBinSlot() assigns their indexes out or order.
-  for (const DexFile* dex_file : compiler_driver_.GetCompilerOptions().GetDexFilesForOatFile()) {
+  for (const DexFile* dex_file : compiler_options_.GetDexFilesForOatFile()) {
     auto it = dex_file_oat_index_map_.find(dex_file);
     DCHECK(it != dex_file_oat_index_map_.end()) << dex_file->GetLocation();
     ImageInfo& image_info = GetImageInfo(it->second);
@@ -852,8 +851,7 @@
   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_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp));
+  result = result || !compiler_options_.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.
@@ -943,7 +941,7 @@
     return true;
   }
   std::string temp;
-  if (!compiler_driver_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp))) {
+  if (!compiler_options_.IsImageClass(klass->GetDescriptor(&temp))) {
     return false;
   }
   if (compile_app_image_) {
@@ -1229,7 +1227,7 @@
 }
 
 void ImageWriter::DumpImageClasses() {
-  for (const std::string& image_class : compiler_driver_.GetCompilerOptions().GetImageClasses()) {
+  for (const std::string& image_class : compiler_options_.GetImageClasses()) {
     LOG(INFO) << " " << image_class;
   }
 }
@@ -1738,7 +1736,7 @@
   WorkStack work_stack;
 
   // Special case interned strings to put them in the image they are likely to be resolved from.
-  for (const DexFile* dex_file : compiler_driver_.GetCompilerOptions().GetDexFilesForOatFile()) {
+  for (const DexFile* dex_file : compiler_options_.GetDexFilesForOatFile()) {
     auto it = dex_file_oat_index_map_.find(dex_file);
     DCHECK(it != dex_file_oat_index_map_.end()) << dex_file->GetLocation();
     const size_t oat_index = it->second;
@@ -2819,7 +2817,7 @@
 }
 
 ImageWriter::ImageWriter(
-    const CompilerDriver& compiler_driver,
+    const CompilerOptions& compiler_options,
     uintptr_t image_begin,
     bool compile_pic,
     bool compile_app_image,
@@ -2827,12 +2825,12 @@
     const std::vector<const char*>& oat_filenames,
     const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map,
     const HashSet<std::string>* dirty_image_objects)
-    : compiler_driver_(compiler_driver),
+    : compiler_options_(compiler_options),
       global_image_begin_(reinterpret_cast<uint8_t*>(image_begin)),
       image_objects_offset_begin_(0),
       compile_pic_(compile_pic),
       compile_app_image_(compile_app_image),
-      target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())),
+      target_ptr_size_(InstructionSetPointerSize(compiler_options.GetInstructionSet())),
       image_infos_(oat_filenames.size()),
       dirty_methods_(0u),
       clean_methods_(0u),
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 2fcf5fd..4111e84 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -39,7 +39,6 @@
 #include "base/safe_map.h"
 #include "base/utils.h"
 #include "class_table.h"
-#include "driver/compiler_driver.h"
 #include "image.h"
 #include "intern_table.h"
 #include "lock_word.h"
@@ -63,6 +62,7 @@
 }  // namespace mirror
 
 class ClassLoaderVisitor;
+class CompilerOptions;
 class ImTable;
 class ImtConflictTable;
 class TimingLogger;
@@ -74,7 +74,7 @@
 // Write a Space built during compilation for use during execution.
 class ImageWriter FINAL {
  public:
-  ImageWriter(const CompilerDriver& compiler_driver,
+  ImageWriter(const CompilerOptions& compiler_options,
               uintptr_t image_begin,
               bool compile_pic,
               bool compile_app_image,
@@ -511,9 +511,8 @@
   // classes since we do not want any boot class loader classes in the image. This means that
   // we also cannot have any classes which refer to these boot class loader non image classes.
   // PruneAppImageClass also prunes if klass depends on a non-image class according to the compiler
-  // driver.
-  bool PruneAppImageClass(ObjPtr<mirror::Class> klass)
-      REQUIRES_SHARED(Locks::mutator_lock_);
+  // options.
+  bool PruneAppImageClass(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
   // early_exit is true if we had a cyclic dependency anywhere down the chain.
   bool PruneAppImageClassInternal(ObjPtr<mirror::Class> klass,
@@ -575,7 +574,7 @@
 
   void CopyAndFixupPointer(void** target, void* value);
 
-  const CompilerDriver& compiler_driver_;
+  const CompilerOptions& compiler_options_;
 
   // Beginning target image address for the first image.
   uint8_t* global_image_begin_;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 0ed9579..154f9ca 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -355,7 +355,7 @@
   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
     << "file_offset=" << file_offset << " offset_=" << offset_
 
-OatWriter::OatWriter(bool compiling_boot_image,
+OatWriter::OatWriter(const CompilerOptions& compiler_options,
                      TimingLogger* timings,
                      ProfileCompilationInfo* info,
                      CompactDexLevel compact_dex_level)
@@ -366,9 +366,8 @@
     zipped_dex_files_(),
     zipped_dex_file_locations_(),
     compiler_driver_(nullptr),
-    compiler_options_(nullptr),
+    compiler_options_(compiler_options),
     image_writer_(nullptr),
-    compiling_boot_image_(compiling_boot_image),
     extract_dex_files_into_vdex_(true),
     dex_files_(nullptr),
     vdex_size_(0u),
@@ -649,8 +648,6 @@
 bool OatWriter::WriteAndOpenDexFiles(
     File* vdex_file,
     OutputStream* oat_rodata,
-    InstructionSet instruction_set,
-    const InstructionSetFeatures* instruction_set_features,
     SafeMap<std::string, std::string>* key_value_store,
     bool verify,
     bool update_input_vdex,
@@ -672,9 +669,7 @@
   // Reserve space for Vdex header and checksums.
   vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) +
       oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
-  oat_size_ = InitOatHeader(instruction_set,
-                            instruction_set_features,
-                            dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
+  oat_size_ = InitOatHeader(dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
                             key_value_store);
 
   ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
@@ -708,7 +703,6 @@
                            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;
 }
@@ -719,10 +713,10 @@
   relative_patcher_ = relative_patcher;
   SetMultiOatRelativePatcherAdjustment();
 
-  if (compiling_boot_image_) {
+  if (GetCompilerOptions().IsBootImage()) {
     CHECK(image_writer_ != nullptr);
   }
-  InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+  InstructionSet instruction_set = compiler_options_.GetInstructionSet();
   CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
 
   {
@@ -769,7 +763,7 @@
   bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
-  if (compiling_boot_image_) {
+  if (GetCompilerOptions().IsBootImage()) {
     CHECK_EQ(image_writer_ != nullptr,
              oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
   }
@@ -1551,7 +1545,7 @@
                          size_t offset,
                          const std::vector<const DexFile*>* dex_files)
       : OatDexMethodVisitor(writer, offset),
-        pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
+        pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
         class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
         dex_files_(dex_files),
         class_linker_(Runtime::Current()->GetClassLinker()) {}
@@ -1619,7 +1613,7 @@
     Thread* self = Thread::Current();
     ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
     ArtMethod* method;
-    if (writer_->HasBootImage()) {
+    if (writer_->GetCompilerOptions().IsBootImage()) {
       const InvokeType invoke_type = it.GetMethodInvokeType(
           dex_file_->GetClassDef(class_def_index_));
       // Unchecked as we hold mutator_lock_ on entry.
@@ -1702,7 +1696,7 @@
         writer_(writer),
         offset_(relative_offset),
         dex_file_(nullptr),
-        pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
+        pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
         class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
         out_(out),
         file_offset_(file_offset),
@@ -1710,7 +1704,7 @@
         dex_cache_(nullptr),
         no_thread_suspension_("OatWriter patching") {
     patched_code_.reserve(16 * KB);
-    if (writer_->HasBootImage()) {
+    if (writer_->GetCompilerOptions().IsBootImage()) {
       // If we're creating the image, the address space must be ready so that we can apply patches.
       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
     }
@@ -1958,7 +1952,7 @@
       const void* oat_code_offset =
           target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
       if (oat_code_offset != 0) {
-        DCHECK(!writer_->HasBootImage());
+        DCHECK(!writer_->GetCompilerOptions().IsBootImage());
         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
@@ -1995,13 +1989,13 @@
     ObjPtr<mirror::String> string =
         linker->LookupString(patch.TargetStringIndex(), GetDexCache(patch.TargetStringDexFile()));
     DCHECK(string != nullptr);
-    DCHECK(writer_->HasBootImage() ||
+    DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
            Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
     return string;
   }
 
   uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK(writer_->HasBootImage());
+    DCHECK(writer_->GetCompilerOptions().IsBootImage());
     method = writer_->image_writer_->GetImageMethodAddress(method);
     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
@@ -2011,7 +2005,7 @@
 
   uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK(writer_->HasBootImage());
+    DCHECK(writer_->GetCompilerOptions().IsBootImage());
     object = writer_->image_writer_->GetImageAddress(object.Ptr());
     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
@@ -2021,7 +2015,7 @@
 
   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (writer_->HasBootImage()) {
+    if (writer_->GetCompilerOptions().IsBootImage()) {
       object = writer_->image_writer_->GetImageAddress(object);
     } else {
       // NOTE: We're using linker patches for app->boot references when the image can
@@ -2042,7 +2036,7 @@
   void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     uint32_t address = target_offset;
-    if (writer_->HasBootImage()) {
+    if (writer_->GetCompilerOptions().IsBootImage()) {
       size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
       // TODO: Clean up offset types.
       // The target_offset must be treated as signed for cross-oat patching.
@@ -2212,13 +2206,11 @@
   return true;
 }
 
-size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
-                                const InstructionSetFeatures* instruction_set_features,
-                                uint32_t num_dex_files,
+size_t OatWriter::InitOatHeader(uint32_t num_dex_files,
                                 SafeMap<std::string, std::string>* key_value_store) {
   TimingLogger::ScopedTiming split("InitOatHeader", timings_);
-  oat_header_.reset(OatHeader::Create(instruction_set,
-                                      instruction_set_features,
+  oat_header_.reset(OatHeader::Create(GetCompilerOptions().GetInstructionSet(),
+                                      GetCompilerOptions().GetInstructionSetFeatures(),
                                       num_dex_files,
                                       key_value_store));
   size_oat_header_ += sizeof(OatHeader);
@@ -2399,7 +2391,7 @@
   oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
   oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
   if (GetCompilerOptions().IsBootImage()) {
-    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    InstructionSet instruction_set = compiler_options_.GetInstructionSet();
     const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo();
     size_t adjusted_offset = offset;
 
@@ -2522,7 +2514,7 @@
   }
 
   DCHECK_EQ(bss_size_, 0u);
-  if (HasBootImage()) {
+  if (GetCompilerOptions().IsBootImage()) {
     DCHECK(bss_string_entries_.empty());
   }
   if (bss_method_entries_.empty() &&
@@ -3294,7 +3286,7 @@
 
 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
   if (GetCompilerOptions().IsBootImage()) {
-    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    InstructionSet instruction_set = compiler_options_.GetInstructionSet();
 
     #define DO_TRAMPOLINE(field) \
       do { \
@@ -3652,7 +3644,7 @@
     dex_file = dex_file_loader.Open(location,
                                     zip_entry->GetCrc32(),
                                     std::move(mem_map),
-                                    /* verify */ !compiling_boot_image_,
+                                    /* verify */ !GetCompilerOptions().IsBootImage(),
                                     /* verify_checksum */ true,
                                     &error_msg);
   } else if (oat_dex_file->source_.IsRawFile()) {
@@ -3664,7 +3656,7 @@
     }
     TimingLogger::ScopedTiming extract("Open", timings_);
     dex_file = dex_file_loader.OpenDex(dup_fd, location,
-                                       /* verify */ !compiling_boot_image_,
+                                       /* verify */ !GetCompilerOptions().IsBootImage(),
                                        /* verify_checksum */ true,
                                        /* mmap_shared */ false,
                                        &error_msg);
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index ccafe05..63fe57f 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -119,7 +119,7 @@
     kDefault = kCreate
   };
 
-  OatWriter(bool compiling_boot_image,
+  OatWriter(const CompilerOptions& compiler_options,
             TimingLogger* timings,
             ProfileCompilationInfo* info,
             CompactDexLevel compact_dex_level);
@@ -173,8 +173,6 @@
   // and the compiler will just re-use the existing vdex file.
   bool WriteAndOpenDexFiles(File* vdex_file,
                             OutputStream* oat_rodata,
-                            InstructionSet instruction_set,
-                            const InstructionSetFeatures* instruction_set_features,
                             SafeMap<std::string, std::string>* key_value_store,
                             bool verify,
                             bool update_input_vdex,
@@ -212,10 +210,6 @@
     return image_writer_ != nullptr;
   }
 
-  bool HasBootImage() const {
-    return compiling_boot_image_;
-  }
-
   const OatHeader& GetOatHeader() const {
     return *oat_header_;
   }
@@ -261,8 +255,7 @@
   }
 
   const CompilerOptions& GetCompilerOptions() const {
-    DCHECK(compiler_options_ != nullptr);
-    return *compiler_options_;
+    return compiler_options_;
   }
 
  private:
@@ -327,10 +320,7 @@
                     /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map,
                     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
 
-  size_t InitOatHeader(InstructionSet instruction_set,
-                       const InstructionSetFeatures* instruction_set_features,
-                       uint32_t num_dex_files,
-                       SafeMap<std::string, std::string>* key_value_store);
+  size_t InitOatHeader(uint32_t num_dex_files, SafeMap<std::string, std::string>* key_value_store);
   size_t InitClassOffsets(size_t offset);
   size_t InitOatClasses(size_t offset);
   size_t InitOatMaps(size_t offset);
@@ -390,9 +380,8 @@
   dchecked_vector<debug::MethodDebugInfo> method_info_;
 
   const CompilerDriver* compiler_driver_;
-  const CompilerOptions* compiler_options_;
+  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.
   bool extract_dex_files_into_vdex_;
 
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index e43a7f3..85eaa84 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -86,33 +86,17 @@
     }
   }
 
-  void SetupCompiler(Compiler::Kind compiler_kind,
-                     InstructionSet insn_set,
-                     const std::vector<std::string>& compiler_options,
-                     /*out*/std::string* error_msg) {
-    ASSERT_TRUE(error_msg != nullptr);
-    insn_features_ = InstructionSetFeatures::FromVariant(insn_set, "default", error_msg);
-    ASSERT_TRUE(insn_features_ != nullptr) << *error_msg;
-    compiler_options_.reset(new CompilerOptions);
+  void SetupCompiler(const std::vector<std::string>& compiler_options) {
+    std::string error_msg;
     if (!compiler_options_->ParseCompilerOptions(compiler_options,
                                                  false /* ignore_unrecognized */,
-                                                 error_msg)) {
-      LOG(FATAL) << *error_msg;
+                                                 &error_msg)) {
+      LOG(FATAL) << error_msg;
       UNREACHABLE();
     }
-    verification_results_.reset(new VerificationResults(compiler_options_.get()));
     callbacks_.reset(new QuickCompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp));
     callbacks_->SetVerificationResults(verification_results_.get());
     Runtime::Current()->SetCompilerCallbacks(callbacks_.get());
-    compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
-                                              verification_results_.get(),
-                                              compiler_kind,
-                                              insn_set,
-                                              insn_features_.get(),
-                                              /* image_classes */ nullptr,
-                                              /* thread_count */ 2,
-                                              /* swap_fd */ -1,
-                                              /* profile_compilation_info */ nullptr));
   }
 
   bool WriteElf(File* vdex_file,
@@ -121,7 +105,8 @@
                 SafeMap<std::string, std::string>& key_value_store,
                 bool verify) {
     TimingLogger timings("WriteElf", false, false);
-    OatWriter oat_writer(/*compiling_boot_image*/false,
+    ClearBootImageOption();
+    OatWriter oat_writer(*compiler_options_,
                          &timings,
                          /*profile_compilation_info*/nullptr,
                          CompactDexLevel::kCompactDexLevelNone);
@@ -145,7 +130,8 @@
                 bool verify,
                 ProfileCompilationInfo* profile_compilation_info) {
     TimingLogger timings("WriteElf", false, false);
-    OatWriter oat_writer(/*compiling_boot_image*/false,
+    ClearBootImageOption();
+    OatWriter oat_writer(*compiler_options_,
                          &timings,
                          profile_compilation_info,
                          CompactDexLevel::kCompactDexLevelNone);
@@ -164,7 +150,8 @@
                 SafeMap<std::string, std::string>& key_value_store,
                 bool verify) {
     TimingLogger timings("WriteElf", false, false);
-    OatWriter oat_writer(/*compiling_boot_image*/false,
+    ClearBootImageOption();
+    OatWriter oat_writer(*compiler_options_,
                          &timings,
                          /*profile_compilation_info*/nullptr,
                          CompactDexLevel::kCompactDexLevelNone);
@@ -180,9 +167,7 @@
                   SafeMap<std::string, std::string>& key_value_store,
                   bool verify) {
     std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick(
-        compiler_driver_->GetInstructionSet(),
-        compiler_driver_->GetInstructionSetFeatures(),
-        &compiler_driver_->GetCompilerOptions(),
+        compiler_driver_->GetCompilerOptions(),
         oat_file);
     elf_writer->Start();
     OutputStream* oat_rodata = elf_writer->StartRoData();
@@ -191,8 +176,6 @@
     if (!oat_writer.WriteAndOpenDexFiles(
         vdex_file,
         oat_rodata,
-        compiler_driver_->GetInstructionSet(),
-        compiler_driver_->GetInstructionSetFeatures(),
         &key_value_store,
         verify,
         /* update_input_vdex */ false,
@@ -210,8 +193,8 @@
       ScopedObjectAccess soa(Thread::Current());
       class_linker->RegisterDexFile(*dex_file, nullptr);
     }
-    MultiOatRelativePatcher patcher(compiler_driver_->GetInstructionSet(),
-                                    instruction_set_features_.get(),
+    MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(),
+                                    compiler_options_->GetInstructionSetFeatures(),
                                     compiler_driver_->GetCompiledMethodStorage());
     oat_writer.Initialize(compiler_driver_.get(), nullptr, dex_files);
     oat_writer.PrepareLayout(&patcher);
@@ -278,7 +261,6 @@
   void TestZipFileInput(bool verify);
   void TestZipFileInputWithEmptyDex();
 
-  std::unique_ptr<const InstructionSetFeatures> insn_features_;
   std::unique_ptr<QuickCompilerCallbacks> callbacks_;
 
   std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps_;
@@ -400,11 +382,8 @@
   TimingLogger timings("OatTest::WriteRead", false, false);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
-  // TODO: make selectable.
-  Compiler::Kind compiler_kind = Compiler::kQuick;
-  InstructionSet insn_set = kIsTargetBuild ? InstructionSet::kThumb2 : InstructionSet::kX86;
   std::string error_msg;
-  SetupCompiler(compiler_kind, insn_set, std::vector<std::string>(), /*out*/ &error_msg);
+  SetupCompiler(std::vector<std::string>());
 
   jobject class_loader = nullptr;
   if (kCompile) {
@@ -524,14 +503,9 @@
 TEST_F(OatTest, EmptyTextSection) {
   TimingLogger timings("OatTest::EmptyTextSection", false, false);
 
-  // TODO: make selectable.
-  Compiler::Kind compiler_kind = Compiler::kQuick;
-  InstructionSet insn_set = kRuntimeISA;
-  if (insn_set == InstructionSet::kArm) insn_set = InstructionSet::kThumb2;
-  std::string error_msg;
   std::vector<std::string> compiler_options;
   compiler_options.push_back("--compiler-filter=extract");
-  SetupCompiler(compiler_kind, insn_set, compiler_options, /*out*/ &error_msg);
+  SetupCompiler(compiler_options);
 
   jobject class_loader;
   {
@@ -560,6 +534,7 @@
                           /* verify */ false);
   ASSERT_TRUE(success);
 
+  std::string error_msg;
   std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
                                                   tmp_oat.GetFilename(),
                                                   tmp_oat.GetFilename(),
diff --git a/dex2oat/linker/relative_patcher_test.h b/dex2oat/linker/relative_patcher_test.h
index b4123ee..b913c7c 100644
--- a/dex2oat/linker/relative_patcher_test.h
+++ b/dex2oat/linker/relative_patcher_test.h
@@ -22,6 +22,7 @@
 #include "base/array_ref.h"
 #include "base/globals.h"
 #include "base/macros.h"
+#include "common_compiler_test.h"
 #include "compiled_method-inl.h"
 #include "dex/verification_results.h"
 #include "dex/method_reference.h"
@@ -38,38 +39,39 @@
 namespace linker {
 
 // Base class providing infrastructure for architecture-specific tests.
-class RelativePatcherTest : public testing::Test {
+class RelativePatcherTest : public CommonCompilerTest {
  protected:
   RelativePatcherTest(InstructionSet instruction_set, const std::string& variant)
-      : compiler_options_(),
-        verification_results_(&compiler_options_),
-        driver_(&compiler_options_,
-                &verification_results_,
-                Compiler::kQuick,
-                instruction_set,
-                /* instruction_set_features*/ nullptr,
-                /* image_classes */ nullptr,
-                /* thread_count */ 1u,
-                /* swap_fd */ -1,
-                /* profile_compilation_info */ nullptr),
-        error_msg_(),
-        instruction_set_(instruction_set),
-        features_(InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg_)),
+      : variant_(variant),
         method_offset_map_(),
-        patcher_(RelativePatcher::Create(instruction_set,
-                                         features_.get(),
-                                         &thunk_provider_,
-                                         &method_offset_map_)),
+        patcher_(nullptr),
         bss_begin_(0u),
         compiled_method_refs_(),
         compiled_methods_(),
         patched_code_(),
         output_(),
         out_("test output stream", &output_) {
-    CHECK(error_msg_.empty()) << instruction_set << "/" << variant;
+    // Override CommonCompilerTest's defaults.
+    instruction_set_ = instruction_set;
+    number_of_threads_ = 1u;
     patched_code_.reserve(16 * KB);
   }
 
+  void SetUp() OVERRIDE {
+    OverrideInstructionSetFeatures(instruction_set_, variant_);
+    CommonCompilerTest::SetUp();
+
+    patcher_ = RelativePatcher::Create(compiler_options_->GetInstructionSet(),
+                                       compiler_options_->GetInstructionSetFeatures(),
+                                       &thunk_provider_,
+                                       &method_offset_map_);
+  }
+
+  void TearDown() OVERRIDE {
+    patcher_.reset();
+    CommonCompilerTest::TearDown();
+  }
+
   MethodReference MethodRef(uint32_t method_idx) {
     CHECK_NE(method_idx, 0u);
     return MethodReference(nullptr, method_idx);
@@ -81,7 +83,7 @@
       const ArrayRef<const LinkerPatch>& patches = ArrayRef<const LinkerPatch>()) {
     compiled_method_refs_.push_back(method_ref);
     compiled_methods_.emplace_back(new CompiledMethod(
-        &driver_,
+        compiler_driver_.get(),
         instruction_set_,
         code,
         /* frame_size_in_bytes */ 0u,
@@ -333,12 +335,7 @@
   static const uint32_t kTrampolineSize = 4u;
   static const uint32_t kTrampolineOffset = 0u;
 
-  CompilerOptions compiler_options_;
-  VerificationResults verification_results_;
-  CompilerDriver driver_;  // Needed for constructing CompiledMethod.
-  std::string error_msg_;
-  InstructionSet instruction_set_;
-  std::unique_ptr<const InstructionSetFeatures> features_;
+  std::string variant_;
   ThunkProvider thunk_provider_;
   MethodOffsetMap method_offset_map_;
   std::unique_ptr<RelativePatcher> patcher_;