Create CompilerOptions

Package up most compiler related options in CompilerOptions. Details include:
- Includes compiler filter, method thresholds, SEA IR mode.
- Excludes those needed during Runtime::Init such as CompilerCallbacks and VerificationResults.
- Pass CompilerOptions to CompilerDriver.
- Remove CompilerOptions from Runtime.
- Add ability to pass options for app and image dex2oat to runtime via
  -Xcompiler-option and -Ximage-compiler-option respectively.

Other
- Replace 2x CompilerCallbacks implementations with one.
- Factor out execv code for use by both image and oat generation.
- More OatFile error_msg reporting.
- DCHECK for SuspendAll found trying to run valgrind.

Change-Id: Iecb57da907be0c856d00c3cd634b5042a229e620
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 591d92a..6800f7b 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -211,7 +211,7 @@
                               class_loader, dex_file);
 
   cu.NewTimingSplit("MIROpt:CheckFilters");
-  if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) {
+  if (cu.mir_graph->SkipCompilation()) {
     return NULL;
   }
 
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index ab55333..7ce8f69 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -18,6 +18,7 @@
 #include "dataflow_iterator-inl.h"
 #include "dex/quick/dex_file_method_inliner.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "driver/compiler_options.h"
 
 namespace art {
 
@@ -958,7 +959,7 @@
   }
 
   // Complex, logic-intensive?
-  if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) &&
+  if (cu_->compiler_driver->GetCompilerOptions().IsSmallMethod(GetNumDalvikInsns()) &&
       stats->branch_ratio > 0.3) {
     return false;
   }
@@ -984,7 +985,7 @@
   }
 
   // If significant in size and high proportion of expensive operations, skip.
-  if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) &&
+  if (cu_->compiler_driver->GetCompilerOptions().IsSmallMethod(GetNumDalvikInsns()) &&
       (stats->heavyweight_ratio > 0.3)) {
     return true;
   }
@@ -996,12 +997,14 @@
   * Will eventually want this to be a bit more sophisticated and happen at verification time.
   * Ultimate goal is to drive with profile data.
   */
-bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) {
-  if (compiler_filter == Runtime::kEverything) {
+bool MIRGraph::SkipCompilation() {
+  const CompilerOptions& compiler_options = cu_->compiler_driver->GetCompilerOptions();
+  CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter();
+  if (compiler_filter == CompilerOptions::kEverything) {
     return false;
   }
 
-  if (compiler_filter == Runtime::kInterpretOnly) {
+  if (compiler_filter == CompilerOptions::kInterpretOnly) {
     LOG(WARNING) << "InterpretOnly should ideally be filtered out prior to parsing.";
     return true;
   }
@@ -1010,17 +1013,17 @@
   size_t small_cutoff = 0;
   size_t default_cutoff = 0;
   switch (compiler_filter) {
-    case Runtime::kBalanced:
-      small_cutoff = Runtime::Current()->GetSmallMethodThreshold();
-      default_cutoff = Runtime::Current()->GetLargeMethodThreshold();
+    case CompilerOptions::kBalanced:
+      small_cutoff = compiler_options.GetSmallMethodThreshold();
+      default_cutoff = compiler_options.GetLargeMethodThreshold();
       break;
-    case Runtime::kSpace:
-      small_cutoff = Runtime::Current()->GetTinyMethodThreshold();
-      default_cutoff = Runtime::Current()->GetSmallMethodThreshold();
+    case CompilerOptions::kSpace:
+      small_cutoff = compiler_options.GetTinyMethodThreshold();
+      default_cutoff = compiler_options.GetSmallMethodThreshold();
       break;
-    case Runtime::kSpeed:
-      small_cutoff = Runtime::Current()->GetHugeMethodThreshold();
-      default_cutoff = Runtime::Current()->GetHugeMethodThreshold();
+    case CompilerOptions::kSpeed:
+      small_cutoff = compiler_options.GetHugeMethodThreshold();
+      default_cutoff = compiler_options.GetHugeMethodThreshold();
       break;
     default:
       LOG(FATAL) << "Unexpected compiler_filter_: " << compiler_filter;
@@ -1033,17 +1036,17 @@
    * Filter 1: Huge methods are likely to be machine generated, but some aren't.
    * If huge, assume we won't compile, but allow futher analysis to turn it back on.
    */
-  if (GetNumDalvikInsns() > Runtime::Current()->GetHugeMethodThreshold()) {
+  if (compiler_options.IsHugeMethod(GetNumDalvikInsns())) {
     skip_compilation = true;
     // If we're got a huge number of basic blocks, don't bother with further analysis.
-    if (static_cast<size_t>(num_blocks_) > (Runtime::Current()->GetHugeMethodThreshold() / 2)) {
+    if (static_cast<size_t>(num_blocks_) > (compiler_options.GetHugeMethodThreshold() / 2)) {
       return true;
     }
-  } else if (GetNumDalvikInsns() > Runtime::Current()->GetLargeMethodThreshold() &&
+  } else if (compiler_options.IsLargeMethod(GetNumDalvikInsns()) &&
     /* If it's large and contains no branches, it's likely to be machine generated initialization */
       (GetBranchCount() == 0)) {
     return true;
-  } else if (compiler_filter == Runtime::kSpeed) {
+  } else if (compiler_filter == CompilerOptions::kSpeed) {
     // If not huge, compile.
     return false;
   }
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index d844aac..2174f67 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -372,7 +372,7 @@
    * Examine the graph to determine whether it's worthwile to spend the time compiling
    * this method.
    */
-  bool SkipCompilation(Runtime::CompilerFilter compiler_filter);
+  bool SkipCompilation();
 
   /*
    * Parse dex method and add MIR at current insert point.  Returns id (which is
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index edccec5..947c22d 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -19,6 +19,8 @@
 #include "base/stl_util.h"
 #include "base/mutex.h"
 #include "base/mutex-inl.h"
+#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "thread.h"
 #include "thread-inl.h"
 #include "verified_method.h"
@@ -27,8 +29,9 @@
 
 namespace art {
 
-VerificationResults::VerificationResults()
-    : verified_methods_lock_("compiler verified methods lock"),
+VerificationResults::VerificationResults(const CompilerOptions* compiler_options)
+    : compiler_options_(compiler_options),
+      verified_methods_lock_("compiler verified methods lock"),
       verified_methods_(),
       rejected_classes_lock_("compiler rejected classes lock"),
       rejected_classes_() {
@@ -43,6 +46,7 @@
 }
 
 bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
+  DCHECK(method_verifier != NULL);
   MethodReference ref = method_verifier->GetMethodReference();
   bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
   // TODO: Check also for virtual/interface invokes when DEX-to-DEX supports devirtualization.
@@ -95,16 +99,18 @@
 bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref,
                                                     const uint32_t access_flags) {
 #ifdef ART_SEA_IR_MODE
-    bool use_sea = Runtime::Current()->IsSeaIRMode();
-    use_sea = use_sea && (std::string::npos != PrettyMethod(
-                          method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
-    if (use_sea) return true;
+  bool use_sea = compiler_options_->GetSeaIrMode();
+  use_sea = use_sea && (std::string::npos != PrettyMethod(
+                        method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
+  if (use_sea) {
+    return true;
+  }
 #endif
   // Don't compile class initializers, ever.
   if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
     return false;
   }
-  return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
+  return (compiler_options_->GetCompilerFilter() != CompilerOptions::kInterpretOnly);
 }
 
 }  // namespace art
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 2eb0713..278182f 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -33,11 +33,13 @@
 class MethodVerifier;
 }  // namespace verifier
 
+class CompilerOptions;
 class VerifiedMethod;
 
+// Used by CompilerCallbacks to track verification information from the Runtime.
 class VerificationResults {
   public:
-    VerificationResults();
+    explicit VerificationResults(const CompilerOptions* compiler_options);
     ~VerificationResults();
 
     bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
@@ -50,15 +52,17 @@
     void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
     bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
 
-    static bool IsCandidateForCompilation(MethodReference& method_ref,
-                                          const uint32_t access_flags);
+    bool IsCandidateForCompilation(MethodReference& method_ref,
+                                   const uint32_t access_flags);
 
   private:
+    const CompilerOptions* compiler_options_;
+
     // Verified methods.
     typedef SafeMap<MethodReference, const VerifiedMethod*,
         MethodReferenceComparator> VerifiedMethodMap;
     ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-    VerifiedMethodMap verified_methods_;
+    VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_);
 
     // Rejected classes.
     ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
diff --git a/compiler/driver/compiler_callbacks_impl.h b/compiler/driver/compiler_callbacks_impl.h
new file mode 100644
index 0000000..ab57832
--- /dev/null
+++ b/compiler/driver/compiler_callbacks_impl.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
+#define ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
+
+#include "compiler_callbacks.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "verifier/method_verifier-inl.h"
+
+namespace art {
+
+class CompilerCallbacksImpl : public CompilerCallbacks {
+  public:
+    CompilerCallbacksImpl(VerificationResults* verification_results,
+                          DexFileToMethodInlinerMap* method_inliner_map)
+        : verification_results_(verification_results),
+          method_inliner_map_(method_inliner_map) {
+      CHECK(verification_results != nullptr);
+      CHECK(method_inliner_map != nullptr);
+    }
+
+    virtual ~CompilerCallbacksImpl() { }
+
+    virtual bool MethodVerified(verifier::MethodVerifier* verifier)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+      bool result = verification_results_->ProcessVerifiedMethod(verifier);
+      if (result) {
+        MethodReference ref = verifier->GetMethodReference();
+        method_inliner_map_->GetMethodInliner(ref.dex_file)
+            ->AnalyseMethodCode(verifier);
+      }
+      return result;
+    }
+    virtual void ClassRejected(ClassReference ref) {
+      verification_results_->AddRejectedClass(ref);
+    }
+
+  private:
+    VerificationResults* verification_results_;
+    DexFileToMethodInlinerMap* method_inliner_map_;
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5adb792..530abc8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -293,14 +293,16 @@
                                               jobject class_loader,
                                               const art::DexFile& dex_file);
 
-CompilerDriver::CompilerDriver(VerificationResults* verification_results,
+CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
+                               VerificationResults* verification_results,
                                DexFileToMethodInlinerMap* method_inliner_map,
                                CompilerBackend::Kind compiler_backend_kind,
                                InstructionSet instruction_set,
                                InstructionSetFeatures instruction_set_features,
                                bool image, DescriptorSet* image_classes, size_t thread_count,
                                bool dump_stats, bool dump_passes, CumulativeLogger* timer)
-    : verification_results_(verification_results),
+    : compiler_options_(compiler_options),
+      verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
       compiler_backend_(CompilerBackend::Create(compiler_backend_kind)),
       instruction_set_(instruction_set),
@@ -325,6 +327,9 @@
       dedupe_mapping_table_("dedupe mapping table"),
       dedupe_vmap_table_("dedupe vmap table"),
       dedupe_gc_map_("dedupe gc map") {
+  DCHECK(compiler_options_ != nullptr);
+  DCHECK(verification_results_ != nullptr);
+  DCHECK(method_inliner_map_ != nullptr);
 
   CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
 
@@ -1929,7 +1934,7 @@
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     MethodReference method_ref(&dex_file, method_idx);
-    bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags);
+    bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
 
     if (compile) {
       // NOTE: if compiler declines to compile this method, it will return NULL.
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 092fe52..5009779 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -45,6 +45,7 @@
 }  // namespace verifier
 
 class AOTCompilationStats;
+class CompilerOptions;
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
 class InlineIGetIPutData;
@@ -94,7 +95,8 @@
   // enabled.  "image_classes" lets the compiler know what classes it
   // can assume will be in the image, with NULL implying all available
   // classes.
-  explicit CompilerDriver(VerificationResults* verification_results,
+  explicit CompilerDriver(const CompilerOptions* compiler_options,
+                          VerificationResults* verification_results,
                           DexFileToMethodInlinerMap* method_inliner_map,
                           CompilerBackend::Kind compiler_backend_kind,
                           InstructionSet instruction_set,
@@ -129,6 +131,11 @@
     return instruction_set_features_;
   }
 
+  const CompilerOptions& GetCompilerOptions() const {
+    DCHECK(compiler_options_ != nullptr);
+    return *compiler_options_;
+  }
+
   CompilerBackend* GetCompilerBackend() const {
     return compiler_backend_.get();
   }
@@ -551,6 +558,7 @@
   std::vector<const CallPatchInformation*> methods_to_patch_;
   std::vector<const TypePatchInformation*> classes_to_patch_;
 
+  const CompilerOptions* compiler_options_;
   VerificationResults* verification_results_;
   DexFileToMethodInlinerMap* method_inliner_map_;
 
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
new file mode 100644
index 0000000..9f6745b
--- /dev/null
+++ b/compiler/driver/compiler_options.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
+#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
+
+namespace art {
+
+class CompilerOptions {
+ public:
+  enum CompilerFilter {
+    kInterpretOnly,       // Compile nothing.
+    kSpace,               // Maximize space savings.
+    kBalanced,            // Try to get the best performance return on compilation investment.
+    kSpeed,               // Maximize runtime performance.
+    kEverything           // Force compilation (Note: excludes compilaton of class initializers).
+  };
+
+  // Guide heuristics to determine whether to compile method if profile data not available.
+  static const CompilerFilter kDefaultCompilerFilter = kSpeed;
+  static const size_t kDefaultHugeMethodThreshold = 10000;
+  static const size_t kDefaultLargeMethodThreshold = 600;
+  static const size_t kDefaultSmallMethodThreshold = 60;
+  static const size_t kDefaultTinyMethodThreshold = 20;
+  static const size_t kDefaultNumDexMethodsThreshold = 900;
+
+  CompilerOptions() :
+    compiler_filter_(kDefaultCompilerFilter),
+    huge_method_threshold_(kDefaultHugeMethodThreshold),
+    large_method_threshold_(kDefaultLargeMethodThreshold),
+    small_method_threshold_(kDefaultSmallMethodThreshold),
+    tiny_method_threshold_(kDefaultTinyMethodThreshold),
+    num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold)
+#ifdef ART_SEA_IR_MODE
+    , sea_ir_mode_(false)
+#endif
+    {}
+
+  CompilerOptions(CompilerFilter compiler_filter,
+                  size_t huge_method_threshold,
+                  size_t large_method_threshold,
+                  size_t small_method_threshold,
+                  size_t tiny_method_threshold,
+                  size_t num_dex_methods_threshold
+#ifdef ART_SEA_IR_MODE
+                  , bool sea_ir_mode
+#endif
+                  ) :  // NOLINT(whitespace/parens)
+    compiler_filter_(compiler_filter),
+    huge_method_threshold_(huge_method_threshold),
+    large_method_threshold_(large_method_threshold),
+    small_method_threshold_(small_method_threshold),
+    tiny_method_threshold_(tiny_method_threshold),
+    num_dex_methods_threshold_(num_dex_methods_threshold)
+#ifdef ART_SEA_IR_MODE
+    , sea_ir_mode_(sea_ir_mode)
+#endif
+    {}
+
+  CompilerFilter GetCompilerFilter() const {
+    return compiler_filter_;
+  }
+
+  void SetCompilerFilter(CompilerFilter compiler_filter) {
+    compiler_filter_ = compiler_filter;
+  }
+
+  size_t GetHugeMethodThreshold() const {
+    return huge_method_threshold_;
+  }
+
+  size_t GetLargeMethodThreshold() const {
+    return large_method_threshold_;
+  }
+
+  size_t GetSmallMethodThreshold() const {
+    return small_method_threshold_;
+  }
+
+  size_t GetTinyMethodThreshold() const {
+    return tiny_method_threshold_;
+  }
+
+  bool IsHugeMethod(size_t num_dalvik_instructions) const {
+    return num_dalvik_instructions > huge_method_threshold_;
+  }
+
+  bool IsLargeMethod(size_t num_dalvik_instructions) const {
+    return num_dalvik_instructions > large_method_threshold_;
+  }
+
+  bool IsSmallMethod(size_t num_dalvik_instructions) const {
+    return num_dalvik_instructions > small_method_threshold_;
+  }
+
+  bool IsTinyMethod(size_t num_dalvik_instructions) const {
+    return num_dalvik_instructions > tiny_method_threshold_;
+  }
+
+  size_t GetNumDexMethodsThreshold() const {
+    return num_dex_methods_threshold_;
+  }
+
+#ifdef ART_SEA_IR_MODE
+  bool GetSeaIrMode();
+#endif
+
+ private:
+  CompilerFilter compiler_filter_;
+  size_t huge_method_threshold_;
+  size_t large_method_threshold_;
+  size_t small_method_threshold_;
+  size_t tiny_method_threshold_;
+  size_t num_dex_methods_threshold_;
+
+#ifdef ART_SEA_IR_MODE
+  bool sea_ir_mode_;
+#endif
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 10d2c5c..29acc86 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -91,11 +91,14 @@
   InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
 
   InstructionSetFeatures insn_features;
-  verification_results_.reset(new VerificationResults);
+  compiler_options_.reset(new CompilerOptions);
+  verification_results_.reset(new VerificationResults(compiler_options_.get()));
   method_inliner_map_.reset(new DexFileToMethodInlinerMap);
-  callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+  callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(),
+                                             method_inliner_map_.get()));
   timer_.reset(new CumulativeLogger("Compilation times"));
-  compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
+  compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
+                                            verification_results_.get(),
                                             method_inliner_map_.get(),
                                             compiler_backend, insn_set,
                                             insn_features, false, NULL, 2, true, true,
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index bfda17d..6c879d0 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -34,7 +34,9 @@
 #include "compiler_callbacks.h"
 #include "dex_file-inl.h"
 #include "dex/verification_results.h"
+#include "driver/compiler_callbacks_impl.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "elf_fixup.h"
 #include "elf_stripper.h"
 #include "gc/space/image_space.h"
@@ -54,15 +56,22 @@
 #include "scoped_thread_state_change.h"
 #include "sirt_ref.h"
 #include "vector_output_stream.h"
-#include "verifier/method_verifier.h"
-#include "verifier/method_verifier-inl.h"
 #include "well_known_classes.h"
 #include "zip_archive.h"
 
-#include "dex/quick/dex_file_to_method_inliner_map.h"
-
 namespace art {
 
+static int original_argc;
+static char** original_argv;
+
+static std::string CommandLine() {
+  std::vector<std::string> command;
+  for (int i = 0; i < original_argc; ++i) {
+    command.push_back(original_argv[i]);
+  }
+  return Join(command, ' ');
+}
+
 static void UsageErrorV(const char* fmt, va_list ap) {
   std::string error;
   StringAppendV(&error, fmt, ap);
@@ -82,6 +91,8 @@
   UsageErrorV(fmt, ap);
   va_end(ap);
 
+  UsageError("Command: %s", CommandLine().c_str());
+
   UsageError("Usage: dex2oat [options]...");
   UsageError("");
   UsageError("  --dex-file=<dex-file>: specifies a .dex file to compile.");
@@ -147,6 +158,46 @@
   UsageError("      Example: --compiler-backend=Portable");
   UsageError("      Default: Quick");
   UsageError("");
+  UsageError("  --compiler-filter=(interpret-only|space|balanced|speed|everything): select");
+  UsageError("      compiler filter.");
+  UsageError("      Example: --compiler-filter=everything");
+#if ART_SMALL_MODE
+  UsageError("      Default: interpret-only");
+#else
+  UsageError("      Default: speed");
+#endif
+  UsageError("");
+  UsageError("  --huge-method-max=<method-instruction-count>: the threshold size for a huge");
+  UsageError("      method for compiler filter tuning.");
+  UsageError("      Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold);
+  UsageError("      Default: %d", CompilerOptions::kDefaultHugeMethodThreshold);
+  UsageError("");
+  UsageError("  --huge-method-max=<method-instruction-count>: threshold size for a huge");
+  UsageError("      method for compiler filter tuning.");
+  UsageError("      Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold);
+  UsageError("      Default: %d", CompilerOptions::kDefaultHugeMethodThreshold);
+  UsageError("");
+  UsageError("  --large-method-max=<method-instruction-count>: threshold size for a large");
+  UsageError("      method for compiler filter tuning.");
+  UsageError("      Example: --large-method-max=%d", CompilerOptions::kDefaultLargeMethodThreshold);
+  UsageError("      Default: %d", CompilerOptions::kDefaultLargeMethodThreshold);
+  UsageError("");
+  UsageError("  --small-method-max=<method-instruction-count>: threshold size for a small");
+  UsageError("      method for compiler filter tuning.");
+  UsageError("      Example: --small-method-max=%d", CompilerOptions::kDefaultSmallMethodThreshold);
+  UsageError("      Default: %d", CompilerOptions::kDefaultSmallMethodThreshold);
+  UsageError("");
+  UsageError("  --tiny-method-max=<method-instruction-count>: threshold size for a tiny");
+  UsageError("      method for compiler filter tuning.");
+  UsageError("      Example: --tiny-method-max=%d", CompilerOptions::kDefaultTinyMethodThreshold);
+  UsageError("      Default: %d", CompilerOptions::kDefaultTinyMethodThreshold);
+  UsageError("");
+  UsageError("  --num-dex-methods=<method-count>: threshold size for a small dex file for");
+  UsageError("      compiler filter tuning. If the input has fewer than this many methods");
+  UsageError("      and the filter is not interpret-only, overrides the filter to use speed");
+  UsageError("      Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold);
+  UsageError("      Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold);
+  UsageError("");
   UsageError("  --host: used with Portable backend to link against host runtime libraries");
   UsageError("");
   UsageError("  --dump-timing: display a breakdown of where time was spent");
@@ -163,15 +214,25 @@
 class Dex2Oat {
  public:
   static bool Create(Dex2Oat** p_dex2oat,
-                     Runtime::Options& options,
+                     const Runtime::Options& runtime_options,
+                     const CompilerOptions& compiler_options,
                      CompilerBackend::Kind compiler_backend,
                      InstructionSet instruction_set,
                      InstructionSetFeatures instruction_set_features,
+                     VerificationResults* verification_results,
+                     DexFileToMethodInlinerMap* method_inliner_map,
                      size_t thread_count)
       SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
-    UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(compiler_backend, instruction_set,
-                                           instruction_set_features, thread_count));
-    if (!dex2oat->CreateRuntime(options, instruction_set)) {
+    CHECK(verification_results != nullptr);
+    CHECK(method_inliner_map != nullptr);
+    UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
+                                           compiler_backend,
+                                           instruction_set,
+                                           instruction_set_features,
+                                           verification_results,
+                                           method_inliner_map,
+                                           thread_count));
+    if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {
       *p_dex2oat = NULL;
       return false;
     }
@@ -275,8 +336,9 @@
       Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
     }
 
-    UniquePtr<CompilerDriver> driver(new CompilerDriver(verification_results_.get(),
-                                                        method_inliner_map_.get(),
+    UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
+                                                        verification_results_,
+                                                        method_inliner_map_,
                                                         compiler_backend_,
                                                         instruction_set_,
                                                         instruction_set_features_,
@@ -353,53 +415,30 @@
   }
 
  private:
-  class Dex2OatCompilerCallbacks : public CompilerCallbacks {
-    public:
-      Dex2OatCompilerCallbacks(VerificationResults* verification_results,
-                               DexFileToMethodInlinerMap* method_inliner_map)
-          : verification_results_(verification_results),
-            method_inliner_map_(method_inliner_map) { }
-      virtual ~Dex2OatCompilerCallbacks() { }
-
-      virtual bool MethodVerified(verifier::MethodVerifier* verifier)
-          SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-        bool result = verification_results_->ProcessVerifiedMethod(verifier);
-        if (result) {
-          MethodReference ref = verifier->GetMethodReference();
-          method_inliner_map_->GetMethodInliner(ref.dex_file)
-              ->AnalyseMethodCode(verifier);
-        }
-        return result;
-      }
-      virtual void ClassRejected(ClassReference ref) {
-        verification_results_->AddRejectedClass(ref);
-      }
-
-    private:
-      VerificationResults* verification_results_;
-      DexFileToMethodInlinerMap* method_inliner_map_;
-  };
-
-  explicit Dex2Oat(CompilerBackend::Kind compiler_backend,
+  explicit Dex2Oat(const CompilerOptions* compiler_options,
+                   CompilerBackend::Kind compiler_backend,
                    InstructionSet instruction_set,
                    InstructionSetFeatures instruction_set_features,
+                   VerificationResults* verification_results,
+                   DexFileToMethodInlinerMap* method_inliner_map,
                    size_t thread_count)
-      : compiler_backend_(compiler_backend),
+      : compiler_options_(compiler_options),
+        compiler_backend_(compiler_backend),
         instruction_set_(instruction_set),
         instruction_set_features_(instruction_set_features),
-        verification_results_(new VerificationResults),
-        method_inliner_map_(new DexFileToMethodInlinerMap),
-        callbacks_(verification_results_.get(), method_inliner_map_.get()),
+        verification_results_(verification_results),
+        method_inliner_map_(method_inliner_map),
         runtime_(nullptr),
         thread_count_(thread_count),
         start_ns_(NanoTime()) {
+    CHECK(compiler_options != nullptr);
+    CHECK(verification_results != nullptr);
+    CHECK(method_inliner_map != nullptr);
   }
 
-  bool CreateRuntime(Runtime::Options& options, InstructionSet instruction_set)
+  bool CreateRuntime(const Runtime::Options& runtime_options, InstructionSet instruction_set)
       SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
-    options.push_back(
-        std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_)));
-    if (!Runtime::Create(options, false)) {
+    if (!Runtime::Create(runtime_options, false)) {
       LOG(ERROR) << "Failed to create runtime";
       return false;
     }
@@ -448,14 +487,14 @@
     return false;
   }
 
+  const CompilerOptions* compiler_options_;
   const CompilerBackend::Kind compiler_backend_;
 
   const InstructionSet instruction_set_;
   const InstructionSetFeatures instruction_set_features_;
 
-  UniquePtr<VerificationResults> verification_results_;
-  UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
-  Dex2OatCompilerCallbacks callbacks_;
+  VerificationResults* verification_results_;
+  DexFileToMethodInlinerMap* method_inliner_map_;
   Runtime* runtime_;
   size_t thread_count_;
   uint64_t start_ns_;
@@ -656,6 +695,9 @@
 }
 
 static int dex2oat(int argc, char** argv) {
+  original_argc = argc;
+  original_argv = argv;
+
   TimingLogger timings("compiler", false, false);
   CumulativeLogger compiler_phases_timings("compilation times");
 
@@ -690,6 +732,12 @@
   CompilerBackend::Kind compiler_backend = kUsePortableCompiler
       ? CompilerBackend::kPortable
       : CompilerBackend::kQuick;
+  const char* compiler_filter_string = NULL;
+  int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
+  int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
+  int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold;
+  int tiny_method_threshold = CompilerOptions::kDefaultTinyMethodThreshold;
+  int num_dex_methods_threshold = CompilerOptions::kDefaultNumDexMethodsThreshold;
 
   // Take the default set of instruction features from the build.
   InstructionSetFeatures instruction_set_features =
@@ -713,7 +761,6 @@
   bool dump_slow_timing = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
 
-
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
     bool log_options = false;
@@ -729,6 +776,9 @@
       if (!ParseInt(zip_fd_str, &zip_fd)) {
         Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str);
       }
+      if (zip_fd < 0) {
+        Usage("--zip-fd passed a negative value %d", zip_fd);
+      }
     } else if (option.starts_with("--zip-location=")) {
       zip_location = option.substr(strlen("--zip-location=")).data();
     } else if (option.starts_with("--oat-file=")) {
@@ -740,6 +790,9 @@
       if (!ParseInt(oat_fd_str, &oat_fd)) {
         Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str);
       }
+      if (oat_fd < 0) {
+        Usage("--oat-fd passed a negative value %d", oat_fd);
+      }
     } else if (option == "--watch-dog") {
       watch_dog_enabled = true;
     } else if (option == "--no-watch-dog") {
@@ -793,6 +846,48 @@
       } else if (backend_str == "Portable") {
         compiler_backend = CompilerBackend::kPortable;
       }
+    } else if (option.starts_with("--compiler-filter=")) {
+      compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
+    } else if (option.starts_with("--huge-method-max=")) {
+      const char* threshold = option.substr(strlen("--huge-method-max=")).data();
+      if (!ParseInt(threshold, &huge_method_threshold)) {
+        Usage("Failed to parse --huge-method-max '%s' as an integer", threshold);
+      }
+      if (huge_method_threshold < 0) {
+        Usage("--huge-method-max passed a negative value %s", huge_method_threshold);
+      }
+    } else if (option.starts_with("--large-method-max=")) {
+      const char* threshold = option.substr(strlen("--large-method-max=")).data();
+      if (!ParseInt(threshold, &large_method_threshold)) {
+        Usage("Failed to parse --large-method-max '%s' as an integer", threshold);
+      }
+      if (large_method_threshold < 0) {
+        Usage("--large-method-max passed a negative value %s", large_method_threshold);
+      }
+    } else if (option.starts_with("--small-method-max=")) {
+      const char* threshold = option.substr(strlen("--small-method-max=")).data();
+      if (!ParseInt(threshold, &small_method_threshold)) {
+        Usage("Failed to parse --small-method-max '%s' as an integer", threshold);
+      }
+      if (small_method_threshold < 0) {
+        Usage("--small-method-max passed a negative value %s", small_method_threshold);
+      }
+    } else if (option.starts_with("--tiny-method-max=")) {
+      const char* threshold = option.substr(strlen("--tiny-method-max=")).data();
+      if (!ParseInt(threshold, &tiny_method_threshold)) {
+        Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold);
+      }
+      if (tiny_method_threshold < 0) {
+        Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold);
+      }
+    } else if (option.starts_with("--num-dex-methods=")) {
+      const char* threshold = option.substr(strlen("--num-dex-methods=")).data();
+      if (!ParseInt(threshold, &num_dex_methods_threshold)) {
+        Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold);
+      }
+      if (num_dex_methods_threshold < 0) {
+        Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold);
+      }
     } else if (option == "--host") {
       is_host = true;
     } else if (option == "--runtime-arg") {
@@ -915,6 +1010,44 @@
     oat_unstripped += oat_filename;
   }
 
+  if (compiler_filter_string == NULL) {
+    if (image) {
+      compiler_filter_string = "everything";
+    } else {
+#if ART_SMALL_MODE
+      compiler_filter_string = "interpret-only";
+#else
+      compiler_filter_string = "speed";
+#endif
+    }
+  }
+  CHECK(compiler_filter_string != nullptr);
+  CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
+  if (strcmp(compiler_filter_string, "interpret-only") == 0) {
+    compiler_filter = CompilerOptions::kInterpretOnly;
+  } else if (strcmp(compiler_filter_string, "space") == 0) {
+    compiler_filter = CompilerOptions::kSpace;
+  } else if (strcmp(compiler_filter_string, "balanced") == 0) {
+    compiler_filter = CompilerOptions::kBalanced;
+  } else if (strcmp(compiler_filter_string, "speed") == 0) {
+    compiler_filter = CompilerOptions::kSpeed;
+  } else if (strcmp(compiler_filter_string, "everything") == 0) {
+    compiler_filter = CompilerOptions::kEverything;
+  } else {
+    Usage("Unknown --compiler-filter value %s", compiler_filter_string);
+  }
+
+  CompilerOptions compiler_options(compiler_filter,
+                                   huge_method_threshold,
+                                   large_method_threshold,
+                                   small_method_threshold,
+                                   tiny_method_threshold,
+                                   num_dex_methods_threshold
+#ifdef ART_SEA_IR_MODE
+                                   , compiler_options.sea_ir_ = true;
+#endif
+                                   );  // NOLINT(whitespace/parens)
+
   // Done with usage checks, enable watchdog if requested
   WatchDog watch_dog(watch_dog_enabled);
 
@@ -940,22 +1073,9 @@
   }
 
   timings.StartSplit("dex2oat Setup");
-  LOG(INFO) << "dex2oat: " << oat_location;
+  LOG(INFO) << "dex2oat: " << CommandLine();
 
-  if (image) {
-    bool has_compiler_filter = false;
-    for (const char* r : runtime_args) {
-      if (strncmp(r, "-compiler-filter:", 17) == 0) {
-        has_compiler_filter = true;
-        break;
-      }
-    }
-    if (!has_compiler_filter) {
-      runtime_args.push_back("-compiler-filter:everything");
-    }
-  }
-
-  Runtime::Options options;
+  Runtime::Options runtime_options;
   std::vector<const DexFile*> boot_class_path;
   if (boot_image_option.empty()) {
     size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
@@ -963,24 +1083,33 @@
       LOG(ERROR) << "Failed to open some dex files: " << failure_count;
       return EXIT_FAILURE;
     }
-    options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+    runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
   } else {
-    options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+    runtime_options.push_back(std::make_pair(boot_image_option.c_str(),
+                                             reinterpret_cast<void*>(NULL)));
   }
   if (host_prefix.get() != NULL) {
-    options.push_back(std::make_pair("host-prefix", host_prefix->c_str()));
+    runtime_options.push_back(std::make_pair("host-prefix", host_prefix->c_str()));
   }
   for (size_t i = 0; i < runtime_args.size(); i++) {
-    options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
+    runtime_options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
   }
 
-#ifdef ART_SEA_IR_MODE
-  options.push_back(std::make_pair("-sea_ir", reinterpret_cast<void*>(NULL)));
-#endif
+  VerificationResults verification_results(&compiler_options);
+  DexFileToMethodInlinerMap method_inliner_map;
+  CompilerCallbacksImpl callbacks(&verification_results, &method_inliner_map);
+  runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
 
   Dex2Oat* p_dex2oat;
-  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set,
-      instruction_set_features, thread_count)) {
+  if (!Dex2Oat::Create(&p_dex2oat,
+                       runtime_options,
+                       compiler_options,
+                       compiler_backend,
+                       instruction_set,
+                       instruction_set_features,
+                       &verification_results,
+                       &method_inliner_map,
+                       thread_count)) {
     LOG(ERROR) << "Failed to create dex2oat";
     return EXIT_FAILURE;
   }
@@ -1050,7 +1179,8 @@
         std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i));
         UniquePtr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
         if (tmp_file.get() == nullptr) {
-            PLOG(ERROR) << "Failed to open file " << tmp_file_name << ". Try: adb shell chmod 777 /data/local/tmp";
+            PLOG(ERROR) << "Failed to open file " << tmp_file_name
+                        << ". Try: adb shell chmod 777 /data/local/tmp";
             continue;
         }
         tmp_file->WriteFully(dex_file->Begin(), dex_file->Size());
@@ -1070,15 +1200,15 @@
    * If we're not in interpret-only mode, go ahead and compile small applications. Don't
    * bother to check if we're doing the image.
    */
-  if (!image && (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly)) {
+  if (!image && (compiler_options.GetCompilerFilter() != CompilerOptions::kInterpretOnly)) {
     size_t num_methods = 0;
     for (size_t i = 0; i != dex_files.size(); ++i) {
       const DexFile* dex_file = dex_files[i];
       CHECK(dex_file != NULL);
       num_methods += dex_file->NumMethodIds();
     }
-    if (num_methods <= Runtime::Current()->GetNumDexMethodsThreshold()) {
-      Runtime::Current()->SetCompilerFilter(Runtime::kSpeed);
+    if (num_methods <= compiler_options.GetNumDexMethodsThreshold()) {
+      compiler_options.SetCompilerFilter(CompilerOptions::kSpeed);
       VLOG(compiler) << "Below method threshold, compiling anyways";
     }
   }
@@ -1222,13 +1352,13 @@
 
   // Everything was successfully written, do an explicit exit here to avoid running Runtime
   // destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
-  if (!kIsDebugBuild || (RUNNING_ON_VALGRIND == 0)) {
+  if (!kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) {
     dex2oat->LogCompletionTime();
     exit(EXIT_SUCCESS);
   }
 
   return EXIT_SUCCESS;
-}
+}  // NOLINT(readability/fn_size)
 }  // namespace art
 
 int main(int argc, char** argv) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 48ec5ab..52dd541 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -550,101 +550,41 @@
   const char* class_path = Runtime::Current()->GetClassPathString().c_str();
 
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  std::string boot_image_option_string("--boot-image=");
-  boot_image_option_string += heap->GetImageSpace()->GetImageFilename();
-  const char* boot_image_option = boot_image_option_string.c_str();
+  std::string boot_image_option("--boot-image=");
+  boot_image_option += heap->GetImageSpace()->GetImageFilename();
 
-  std::string dex_file_option_string("--dex-file=");
-  dex_file_option_string += dex_filename;
-  const char* dex_file_option = dex_file_option_string.c_str();
+  std::string dex_file_option("--dex-file=");
+  dex_file_option += dex_filename;
 
-  std::string oat_fd_option_string("--oat-fd=");
-  StringAppendF(&oat_fd_option_string, "%d", oat_fd);
-  const char* oat_fd_option = oat_fd_option_string.c_str();
+  std::string oat_fd_option("--oat-fd=");
+  StringAppendF(&oat_fd_option, "%d", oat_fd);
 
-  std::string oat_location_option_string("--oat-location=");
-  oat_location_option_string += oat_cache_filename;
-  const char* oat_location_option = oat_location_option_string.c_str();
+  std::string oat_location_option("--oat-location=");
+  oat_location_option += oat_cache_filename;
 
-  std::string oat_compiler_filter_string("-compiler-filter:");
-  Runtime::CompilerFilter filter = Runtime::Current()->GetCompilerFilter();
-  switch (filter) {
-    case Runtime::kInterpretOnly:
-      oat_compiler_filter_string += "interpret-only";
-      break;
-    case Runtime::kSpace:
-      oat_compiler_filter_string += "space";
-      break;
-    case Runtime::kBalanced:
-      oat_compiler_filter_string += "balanced";
-      break;
-    case Runtime::kSpeed:
-      oat_compiler_filter_string += "speed";
-      break;
-    case Runtime::kEverything:
-      oat_compiler_filter_string += "everything";
-      break;
-    default:
-      LOG(FATAL) << "Unexpected case: " << filter;
+  std::vector<std::string> argv;
+  argv.push_back(dex2oat);
+  argv.push_back("--runtime-arg");
+  argv.push_back("-Xms64m");
+  argv.push_back("--runtime-arg");
+  argv.push_back("-Xmx64m");
+  argv.push_back("--runtime-arg");
+  argv.push_back("-classpath");
+  argv.push_back("--runtime-arg");
+  argv.push_back(class_path);
+  if (!kIsTargetBuild) {
+    argv.push_back("--host");
   }
-  const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str();
-
-  // fork and exec dex2oat
-  pid_t pid = fork();
-  if (pid == 0) {
-    // no allocation allowed between fork and exec
-
-    // change process groups, so we don't get reaped by ProcessManager
-    setpgid(0, 0);
-
-    // gLogVerbosity.class_linker = true;
-    VLOG(class_linker) << dex2oat
-                       << " --runtime-arg -Xms64m"
-                       << " --runtime-arg -Xmx64m"
-                       << " --runtime-arg -classpath"
-                       << " --runtime-arg " << class_path
-                       << " --runtime-arg " << oat_compiler_filter_option
-#if !defined(ART_TARGET)
-                       << " --host"
-#endif
-                       << " " << boot_image_option
-                       << " " << dex_file_option
-                       << " " << oat_fd_option
-                       << " " << oat_location_option;
-
-    execl(dex2oat, dex2oat,
-          "--runtime-arg", "-Xms64m",
-          "--runtime-arg", "-Xmx64m",
-          "--runtime-arg", "-classpath",
-          "--runtime-arg", class_path,
-          "--runtime-arg", oat_compiler_filter_option,
-#if !defined(ART_TARGET)
-          "--host",
-#endif
-          boot_image_option,
-          dex_file_option,
-          oat_fd_option,
-          oat_location_option,
-          NULL);
-
-    PLOG(FATAL) << "execl(" << dex2oat << ") failed";
-    return false;
-  } else {
-    // wait for dex2oat to finish
-    int status;
-    pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
-    if (got_pid != pid) {
-      *error_msg = StringPrintf("Failed to create oat file. Waitpid failed: wanted %d, got %d",
-                                pid, got_pid);
-      return false;
-    }
-    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-      *error_msg = StringPrintf("Failed to create oat file. %s failed with dex-file '%s'",
-                                dex2oat, dex_filename);
-      return false;
-    }
+  argv.push_back(boot_image_option);
+  argv.push_back(dex_file_option);
+  argv.push_back(oat_fd_option);
+  argv.push_back(oat_location_option);
+  const std::vector<std::string>& compiler_options = Runtime::Current()->GetCompilerOptions();
+  for (size_t i = 0; compiler_options.size(); ++i) {
+    argv.push_back(compiler_options[i].c_str());
   }
-  return true;
+
+  return Exec(argv, error_msg);
 }
 
 const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) {
diff --git a/runtime/common_test.h b/runtime/common_test.h
index 7f9b6b1..e3843be 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -28,7 +28,9 @@
 #include "../compiler/compiler_backend.h"
 #include "../compiler/dex/quick/dex_file_to_method_inliner_map.h"
 #include "../compiler/dex/verification_results.h"
+#include "../compiler/driver/compiler_callbacks_impl.h"
 #include "../compiler/driver/compiler_driver.h"
+#include "../compiler/driver/compiler_options.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/stringprintf.h"
@@ -458,11 +460,13 @@
         ? CompilerBackend::kPortable
         : CompilerBackend::kQuick;
 
-    verification_results_.reset(new VerificationResults);
+    compiler_options_.reset(new CompilerOptions);
+    verification_results_.reset(new VerificationResults(compiler_options_.get()));
     method_inliner_map_.reset(new DexFileToMethodInlinerMap);
-    callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+    callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(),
+                                               method_inliner_map_.get()));
     Runtime::Options options;
-    options.push_back(std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_)));
+    options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
     options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
     options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
     options.push_back(std::make_pair(min_heap_string.c_str(), reinterpret_cast<void*>(NULL)));
@@ -472,8 +476,8 @@
       return;
     }
     runtime_.reset(Runtime::Current());
-    // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
-    // give it away now and then switch to a more managable ScopedObjectAccess.
+    // Runtime::Create acquired the mutator_lock_ that is normally given away when we
+    // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
     {
       ScopedObjectAccess soa(Thread::Current());
@@ -512,7 +516,8 @@
       }
       class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
       timer_.reset(new CumulativeLogger("Compilation times"));
-      compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
+      compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
+                                                verification_results_.get(),
                                                 method_inliner_map_.get(),
                                                 compiler_backend, instruction_set,
                                                 instruction_set_features,
@@ -563,9 +568,10 @@
 
     compiler_driver_.reset();
     timer_.reset();
-    callbacks_.Reset(nullptr, nullptr);
+    callbacks_.reset();
     method_inliner_map_.reset();
     verification_results_.reset();
+    compiler_options_.reset();
     STLDeleteElements(&opened_dex_files_);
 
     Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
@@ -693,36 +699,6 @@
     image_reservation_.reset();
   }
 
-  class TestCompilerCallbacks : public CompilerCallbacks {
-   public:
-    TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) {}
-
-    void Reset(VerificationResults* verification_results,
-               DexFileToMethodInlinerMap* method_inliner_map) {
-        verification_results_ = verification_results;
-        method_inliner_map_ = method_inliner_map;
-    }
-
-    virtual bool MethodVerified(verifier::MethodVerifier* verifier)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-      CHECK(verification_results_);
-      bool result = verification_results_->ProcessVerifiedMethod(verifier);
-      if (result && method_inliner_map_ != nullptr) {
-        MethodReference ref = verifier->GetMethodReference();
-        method_inliner_map_->GetMethodInliner(ref.dex_file)
-            ->AnalyseMethodCode(verifier);
-      }
-      return result;
-    }
-    virtual void ClassRejected(ClassReference ref) {
-      verification_results_->AddRejectedClass(ref);
-    }
-
-   private:
-    VerificationResults* verification_results_;
-    DexFileToMethodInlinerMap* method_inliner_map_;
-  };
-
   std::string android_data_;
   std::string dalvik_cache_;
   const DexFile* java_lang_dex_file_;  // owned by runtime_
@@ -730,9 +706,10 @@
   UniquePtr<Runtime> runtime_;
   // Owned by the runtime
   ClassLinker* class_linker_;
+  UniquePtr<CompilerOptions> compiler_options_;
   UniquePtr<VerificationResults> verification_results_;
   UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
-  TestCompilerCallbacks callbacks_;
+  UniquePtr<CompilerCallbacksImpl> callbacks_;
   UniquePtr<CompilerDriver> compiler_driver_;
   UniquePtr<CumulativeLogger> timer_;
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index ebad8dd..86dee1d 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -89,52 +89,14 @@
     arg_vector.push_back("--host");
   }
 
+  const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions();
+  for (size_t i = 0; compiler_options.size(); ++i) {
+    arg_vector.push_back(compiler_options[i].c_str());
+  }
+
   std::string command_line(Join(arg_vector, ' '));
   LOG(INFO) << "GenerateImage: " << command_line;
-
-  // Convert the args to char pointers.
-  std::vector<char*> char_args;
-  for (std::vector<std::string>::iterator it = arg_vector.begin(); it != arg_vector.end();
-      ++it) {
-    char_args.push_back(const_cast<char*>(it->c_str()));
-  }
-  char_args.push_back(NULL);
-
-  // fork and exec dex2oat
-  pid_t pid = fork();
-  if (pid == 0) {
-    // no allocation allowed between fork and exec
-
-    // change process groups, so we don't get reaped by ProcessManager
-    setpgid(0, 0);
-
-    execv(dex2oat.c_str(), &char_args[0]);
-
-    PLOG(FATAL) << "execv(" << dex2oat << ") failed";
-    return false;
-  } else {
-    if (pid == -1) {
-      *error_msg = StringPrintf("Failed to generate image '%s' because fork failed: %s",
-                                image_file_name.c_str(), strerror(errno));
-      return false;
-    }
-
-    // wait for dex2oat to finish
-    int status;
-    pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
-    if (got_pid != pid) {
-      *error_msg = StringPrintf("Failed to generate image '%s' because waitpid failed: "
-                                "wanted %d, got %d: %s",
-                                image_file_name.c_str(), pid, got_pid, strerror(errno));
-      return false;
-    }
-    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-      *error_msg = StringPrintf("Failed to generate image '%s' because dex2oat failed: %s",
-                                image_file_name.c_str(), command_line.c_str());
-      return false;
-    }
-  }
-  return true;
+  return Exec(arg_vector, error_msg);
 }
 
 ImageSpace* ImageSpace::Create(const char* original_image_file_name) {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 00a8506..61f023c 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -84,6 +84,7 @@
   // This won't work for portable runtime execution because it doesn't process relocations.
   UniquePtr<File> file(OS::OpenFileForReading(filename.c_str()));
   if (file.get() == NULL) {
+    *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno));
     return NULL;
   }
   return OpenElfFile(file.get(), location, requested_base, false, executable, error_msg);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3ccea36..1ef15f7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -77,13 +77,6 @@
       is_zygote_(false),
       is_concurrent_gc_enabled_(true),
       is_explicit_gc_disabled_(false),
-      compiler_filter_(kSpeed),
-      huge_method_threshold_(0),
-      large_method_threshold_(0),
-      small_method_threshold_(0),
-      tiny_method_threshold_(0),
-      num_dex_methods_threshold_(0),
-      sea_ir_mode_(false),
       default_stack_size_(0),
       heap_(nullptr),
       max_spins_before_thin_lock_inflation_(Monitor::kDefaultMaxSpinsBeforeThinLockInflation),
@@ -452,14 +445,6 @@
   parsed->hook_exit_ = exit;
   parsed->hook_abort_ = NULL;  // We don't call abort(3) by default; see Runtime::Abort.
 
-  parsed->compiler_filter_ = Runtime::kDefaultCompilerFilter;
-  parsed->huge_method_threshold_ = Runtime::kDefaultHugeMethodThreshold;
-  parsed->large_method_threshold_ = Runtime::kDefaultLargeMethodThreshold;
-  parsed->small_method_threshold_ = Runtime::kDefaultSmallMethodThreshold;
-  parsed->tiny_method_threshold_ = Runtime::kDefaultTinyMethodThreshold;
-  parsed->num_dex_methods_threshold_ = Runtime::kDefaultNumDexMethodsThreshold;
-
-  parsed->sea_ir_mode_ = false;
 //  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
 //  gLogVerbosity.compiler = true;  // TODO: don't check this in!
 //  gLogVerbosity.verifier = true;  // TODO: don't check this in!
@@ -721,28 +706,22 @@
     } else if (StartsWith(option, "-Xprofile-backoff:")) {
       parsed->profile_backoff_coefficient_ = ParseDoubleOrDie(
           option, ':', 1.0, 10.0, ignore_unrecognized, parsed->profile_backoff_coefficient_);
-    } else if (option == "-compiler-filter:interpret-only") {
-      parsed->compiler_filter_ = kInterpretOnly;
-    } else if (option == "-compiler-filter:space") {
-      parsed->compiler_filter_ = kSpace;
-    } else if (option == "-compiler-filter:balanced") {
-      parsed->compiler_filter_ = kBalanced;
-    } else if (option == "-compiler-filter:speed") {
-      parsed->compiler_filter_ = kSpeed;
-    } else if (option == "-compiler-filter:everything") {
-      parsed->compiler_filter_ = kEverything;
-    } else if (option == "-sea_ir") {
-      parsed->sea_ir_mode_ = true;
-    } else if (StartsWith(option, "-huge-method-max:")) {
-      parsed->huge_method_threshold_ = ParseIntegerOrDie(option, ':');
-    } else if (StartsWith(option, "-large-method-max:")) {
-      parsed->large_method_threshold_ = ParseIntegerOrDie(option, ':');
-    } else if (StartsWith(option, "-small-method-max:")) {
-      parsed->small_method_threshold_ = ParseIntegerOrDie(option, ':');
-    } else if (StartsWith(option, "-tiny-method-max:")) {
-      parsed->tiny_method_threshold_ = ParseIntegerOrDie(option, ':');
-    } else if (StartsWith(option, "-num-dex-methods-max:")) {
-      parsed->num_dex_methods_threshold_ = ParseIntegerOrDie(option, ':');
+    } else if (option == "-Xcompiler-option") {
+      i++;
+      if (i == options.size()) {
+        // TODO: usage
+        LOG(FATAL) << "Missing required compiler option for " << option;
+        return NULL;
+      }
+      parsed->compiler_options_.push_back(options[i].first);
+    } else if (option == "-Ximage-compiler-option") {
+      i++;
+      if (i == options.size()) {
+        // TODO: usage
+        LOG(FATAL) << "Missing required compiler option for " << option;
+        return NULL;
+      }
+      parsed->image_compiler_options_.push_back(options[i].first);
     } else {
       if (!ignore_unrecognized) {
         // TODO: print usage via vfprintf
@@ -988,14 +967,6 @@
   is_zygote_ = options->is_zygote_;
   is_explicit_gc_disabled_ = options->is_explicit_gc_disabled_;
 
-  compiler_filter_ = options->compiler_filter_;
-  huge_method_threshold_ = options->huge_method_threshold_;
-  large_method_threshold_ = options->large_method_threshold_;
-  small_method_threshold_ = options->small_method_threshold_;
-  tiny_method_threshold_ = options->tiny_method_threshold_;
-  num_dex_methods_threshold_ = options->num_dex_methods_threshold_;
-
-  sea_ir_mode_ = options->sea_ir_mode_;
   vfprintf_ = options->hook_vfprintf_;
   exit_ = options->hook_exit_;
   abort_ = options->hook_abort_;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 223b8d5..8924921 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -72,26 +72,6 @@
  public:
   typedef std::vector<std::pair<std::string, const void*> > Options;
 
-  enum CompilerFilter {
-    kInterpretOnly,       // Compile nothing.
-    kSpace,               // Maximize space savings.
-    kBalanced,            // Try to get the best performance return on compilation investment.
-    kSpeed,               // Maximize runtime performance.
-    kEverything           // Force compilation (Note: excludes compilaton of class initializers).
-  };
-
-  // Guide heuristics to determine whether to compile method if profile data not available.
-#if ART_SMALL_MODE
-  static const CompilerFilter kDefaultCompilerFilter = kInterpretOnly;
-#else
-  static const CompilerFilter kDefaultCompilerFilter = kSpeed;
-#endif
-  static const size_t kDefaultHugeMethodThreshold = 10000;
-  static const size_t kDefaultLargeMethodThreshold = 600;
-  static const size_t kDefaultSmallMethodThreshold = 60;
-  static const size_t kDefaultTinyMethodThreshold = 20;
-  static const size_t kDefaultNumDexMethodsThreshold = 900;
-
   class ParsedOptions {
    public:
     // returns null if problem parsing and ignore_unrecognized is false
@@ -140,13 +120,8 @@
     void (*hook_exit_)(jint status);
     void (*hook_abort_)();
     std::vector<std::string> properties_;
-    CompilerFilter compiler_filter_;
-    size_t huge_method_threshold_;
-    size_t large_method_threshold_;
-    size_t small_method_threshold_;
-    size_t tiny_method_threshold_;
-    size_t num_dex_methods_threshold_;
-    bool sea_ir_mode_;
+    std::vector<std::string> compiler_options_;
+    std::vector<std::string> image_compiler_options_;
     bool profile_;
     std::string profile_output_filename_;
     int profile_period_s_;
@@ -178,42 +153,12 @@
     return is_explicit_gc_disabled_;
   }
 
-#ifdef ART_SEA_IR_MODE
-  bool IsSeaIRMode() const {
-    return sea_ir_mode_;
-  }
-#endif
-
-  void SetSeaIRMode(bool sea_ir_mode) {
-    sea_ir_mode_ = sea_ir_mode;
+  const std::vector<std::string>& GetCompilerOptions() const {
+    return compiler_options_;
   }
 
-  CompilerFilter GetCompilerFilter() const {
-    return compiler_filter_;
-  }
-
-  void SetCompilerFilter(CompilerFilter compiler_filter) {
-    compiler_filter_ = compiler_filter;
-  }
-
-  size_t GetHugeMethodThreshold() const {
-    return huge_method_threshold_;
-  }
-
-  size_t GetLargeMethodThreshold() const {
-    return large_method_threshold_;
-  }
-
-  size_t GetSmallMethodThreshold() const {
-    return small_method_threshold_;
-  }
-
-  size_t GetTinyMethodThreshold() const {
-    return tiny_method_threshold_;
-  }
-
-  size_t GetNumDexMethodsThreshold() const {
-      return num_dex_methods_threshold_;
+  const std::vector<std::string>& GetImageCompilerOptions() const {
+    return image_compiler_options_;
   }
 
   const std::string& GetHostPrefix() const {
@@ -525,14 +470,8 @@
   bool is_concurrent_gc_enabled_;
   bool is_explicit_gc_disabled_;
 
-  CompilerFilter compiler_filter_;
-  size_t huge_method_threshold_;
-  size_t large_method_threshold_;
-  size_t small_method_threshold_;
-  size_t tiny_method_threshold_;
-  size_t num_dex_methods_threshold_;
-
-  bool sea_ir_mode_;
+  std::vector<std::string> compiler_options_;
+  std::vector<std::string> image_compiler_options_;
 
   // The host prefix is used during cross compilation. It is removed
   // from the start of host paths such as:
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 74e6f1c..d311945 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -269,6 +269,7 @@
 
 void ThreadList::SuspendAll() {
   Thread* self = Thread::Current();
+  DCHECK(self != nullptr);
 
   VLOG(threads) << *self << " SuspendAll starting...";
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index aad21bc..8e6ddaf 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include "UniquePtr.h"
+#include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file-inl.h"
 #include "mirror/art_field-inl.h"
@@ -1203,4 +1204,56 @@
                  sizeof(OatHeader::kOatMagic)) == 0);
 }
 
+bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) {
+  const std::string command_line(Join(arg_vector, ' '));
+
+  CHECK_GE(arg_vector.size(), 1U) << command_line;
+
+  // Convert the args to char pointers.
+  const char* program = arg_vector[0].c_str();
+  std::vector<char*> args;
+  for (std::vector<std::string>::const_iterator it = arg_vector.begin(); it != arg_vector.end();
+      ++it) {
+    CHECK(*it != nullptr);
+    args.push_back(const_cast<char*>(it->c_str()));
+  }
+  args.push_back(NULL);
+
+  // fork and exec
+  pid_t pid = fork();
+  if (pid == 0) {
+    // no allocation allowed between fork and exec
+
+    // change process groups, so we don't get reaped by ProcessManager
+    setpgid(0, 0);
+
+    execv(program, &args[0]);
+
+    *error_msg = StringPrintf("Failed to execv(%s): %s", command_line.c_str(), strerror(errno));
+    return false;
+  } else {
+    if (pid == -1) {
+      *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
+                                command_line.c_str(), strerror(errno));
+      return false;
+    }
+
+    // wait for subprocess to finish
+    int status;
+    pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+    if (got_pid != pid) {
+      *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
+                                "wanted %d, got %d: %s",
+                                command_line.c_str(), pid, got_pid, strerror(errno));
+      return false;
+    }
+    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+      *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
+                                command_line.c_str());
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace art
diff --git a/runtime/utils.h b/runtime/utils.h
index e2d8966..0bb06de 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -396,6 +396,9 @@
 bool IsDexMagic(uint32_t magic);
 bool IsOatMagic(uint32_t magic);
 
+// Wrapper on fork/execv to run a command in a subprocess.
+bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg);
+
 class VoidFunctor {
  public:
   template <typename A>
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index b43177b..ff65e47 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -349,4 +349,26 @@
   CheckGetDalvikCacheFilenameOrDie("/system/framework/boot.art", "system@framework@boot.art");
 }
 
+TEST_F(UtilsTest, ExecSuccess) {
+  std::vector<std::string> command;
+  if (kIsTargetBuild) {
+    command.push_back("/system/bin/id");
+  } else {
+    command.push_back("/usr/bin/id");
+  }
+  std::string error_msg;
+  EXPECT_TRUE(Exec(command, &error_msg));
+  EXPECT_EQ(0U, error_msg.size()) << error_msg;
+}
+
+// TODO: Disabled due to hang tearing down CommonTest.
+// Renable after splitting into RuntimeTest and CompilerTest.
+TEST_F(UtilsTest, DISABLED_ExecError) {
+  std::vector<std::string> command;
+  command.push_back("bogus");
+  std::string error_msg;
+  EXPECT_FALSE(Exec(command, &error_msg));
+  EXPECT_NE(0U, error_msg.size());
+}
+
 }  // namespace art