Merge "Bump up stack overflow region for 64bit."
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 30f730c..219f1e2 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -93,6 +93,23 @@
 ART_USE_PORTABLE_COMPILER := true
 endif
 
+#
+# Used to enable optimizing compiler
+#
+ART_USE_OPTIMIZING_COMPILER := false
+ifneq ($(wildcard art/USE_OPTIMIZING_COMPILER),)
+$(info Enabling ART_USE_OPTIMIZING_COMPILER because of existence of art/USE_OPTIMIZING_COMPILER)
+ART_USE_OPTIMIZING_COMPILER := true
+endif
+ifeq ($(WITH_ART_USE_OPTIMIZING_COMPILER), true)
+ART_USE_OPTIMIZING_COMPILER := true
+endif
+
+ifeq ($(ART_USE_OPTIMIZING_COMPILER),true)
+DEX2OAT_FLAGS := --compiler-backend=Optimizing
+DALVIKVM_FLAGS := -Xcompiler-option --compiler-backend=Optimizing
+endif
+
 LLVM_ROOT_PATH := external/llvm
 # Don't fail a dalvik minimal host build.
 -include $(LLVM_ROOT_PATH)/llvm.mk
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 48e2bcd..bcd120b 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -75,6 +75,7 @@
 	optimizing/code_generator_arm.cc \
 	optimizing/code_generator_x86.cc \
 	optimizing/nodes.cc \
+	optimizing/optimizing_compiler.cc \
 	trampolines/trampoline_compiler.cc \
 	utils/arena_allocator.cc \
 	utils/arena_bit_vector.cc \
@@ -89,7 +90,8 @@
 	utils/x86/managed_register_x86.cc \
 	utils/scoped_arena_allocator.cc \
 	buffered_output_stream.cc \
-	compiler_backend.cc \
+	compilers.cc \
+	compiler.cc \
 	elf_fixup.cc \
 	elf_stripper.cc \
 	elf_writer.cc \
@@ -132,8 +134,7 @@
 endif
 
 LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \
-	dex/compiler_enums.h \
-	dex/quick/dex_file_method_inliner.h
+	dex/compiler_enums.h
 
 # $(1): target or host
 # $(2): ndebug or debug
@@ -210,7 +211,7 @@
     LOCAL_SHARED_LIBRARIES += libart
   endif
   ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-    LOCAL_SHARED_LIBRARIES += libbcc libbcinfo libLLVM
+    LOCAL_SHARED_LIBRARIES += libLLVM
     LOCAL_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
     ifeq ($$(art_target_or_host),target)
       LOCAL_STATIC_LIBRARIES_arm += libmcldARMInfo libmcldARMTarget
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index d28b0fe..49c1283 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -17,7 +17,7 @@
 #ifndef ART_COMPILER_COMMON_COMPILER_TEST_H_
 #define ART_COMPILER_COMMON_COMPILER_TEST_H_
 
-#include "compiler_backend.h"
+#include "compiler.h"
 #include "compiler_callbacks.h"
 #include "common_runtime_test.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
@@ -319,13 +319,13 @@
       }
 
       // TODO: make selectable
-      CompilerBackend::Kind compiler_backend
-          = (kUsePortableCompiler) ? CompilerBackend::kPortable : CompilerBackend::kQuick;
+      Compiler::Kind compiler_kind
+          = (kUsePortableCompiler) ? Compiler::kPortable : Compiler::kQuick;
       timer_.reset(new CumulativeLogger("Compilation times"));
       compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                                 verification_results_.get(),
                                                 method_inliner_map_.get(),
-                                                compiler_backend, instruction_set,
+                                                compiler_kind, instruction_set,
                                                 instruction_set_features,
                                                 true, new CompilerDriver::DescriptorSet,
                                                 2, true, true, timer_.get()));
diff --git a/compiler/compiler.cc b/compiler/compiler.cc
new file mode 100644
index 0000000..c88c38e
--- /dev/null
+++ b/compiler/compiler.cc
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+#include "compiler.h"
+#include "compilers.h"
+#include "driver/compiler_driver.h"
+#include "mirror/art_method-inl.h"
+
+#ifdef ART_USE_PORTABLE_COMPILER
+#include "dex/portable/mir_to_gbc.h"
+#include "elf_writer_mclinker.h"
+#endif
+
+namespace art {
+
+#ifdef ART_SEA_IR_MODE
+extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& driver,
+                                                   const art::DexFile::CodeItem* code_item,
+                                                   uint32_t access_flags,
+                                                   art::InvokeType invoke_type,
+                                                   uint16_t class_def_idx,
+                                                   uint32_t method_idx,
+                                                   jobject class_loader,
+                                                   const art::DexFile& dex_file);
+#endif
+
+
+CompiledMethod* Compiler::TryCompileWithSeaIR(art::CompilerDriver& driver,
+                                              const art::DexFile::CodeItem* code_item,
+                                              uint32_t access_flags,
+                                              art::InvokeType invoke_type,
+                                              uint16_t class_def_idx,
+                                              uint32_t method_idx,
+                                              jobject class_loader,
+                                              const art::DexFile& dex_file) {
+#ifdef ART_SEA_IR_MODE
+    bool use_sea = Runtime::Current()->IsSeaIRMode();
+    use_sea = use_sea &&
+        (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
+    if (use_sea) {
+      LOG(INFO) << "Using SEA IR to compile..." << std::endl;
+      return SeaIrCompileMethod(compiler,
+                                code_item,
+                                access_flags,
+                                invoke_type,
+                                class_def_idx,
+                                method_idx,
+                                class_loader,
+                                dex_file);
+  }
+#endif
+  return nullptr;
+}
+
+
+#ifdef ART_USE_PORTABLE_COMPILER
+
+extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
+
+extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
+
+extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
+                                                 const art::DexFile::CodeItem* code_item,
+                                                 uint32_t access_flags,
+                                                 art::InvokeType invoke_type,
+                                                 uint16_t class_def_idx,
+                                                 uint32_t method_idx,
+                                                 jobject class_loader,
+                                                 const art::DexFile& dex_file);
+
+extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
+                                                        uint32_t access_flags, uint32_t method_idx,
+                                                        const art::DexFile& dex_file);
+
+extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
+                                               std::string const& filename);
+
+
+class LLVMCompiler : public Compiler {
+ public:
+  LLVMCompiler() : Compiler(1000) {}
+
+  void Init(CompilerDriver& driver) const {
+    ArtInitCompilerContext(driver);
+  }
+
+  void UnInit(CompilerDriver& driver) const {
+    ArtUnInitCompilerContext(driver);
+  }
+
+  CompiledMethod* Compile(CompilerDriver& driver,
+                          const DexFile::CodeItem* code_item,
+                          uint32_t access_flags,
+                          InvokeType invoke_type,
+                          uint16_t class_def_idx,
+                          uint32_t method_idx,
+                          jobject class_loader,
+                          const DexFile& dex_file) const {
+    CompiledMethod* method = TryCompileWithSeaIR(driver,
+                                                 code_item,
+                                                 access_flags,
+                                                 invoke_type,
+                                                 class_def_idx,
+                                                 method_idx,
+                                                 class_loader,
+                                                 dex_file);
+    if (method != nullptr) return method;
+
+    return ArtCompileMethod(compiler,
+                            code_item,
+                            access_flags,
+                            invoke_type,
+                            class_def_idx,
+                            method_idx,
+                            class_loader,
+                            dex_file);
+  }
+
+  CompiledMethod* JniCompile(CompilerDriver& driver,
+                             uint32_t access_flags,
+                             uint32_t method_idx,
+                             const DexFile& dex_file) const {
+    return ArtLLVMJniCompileMethod(driver, access_flags, method_idx, dex_file);
+  }
+
+  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
+    return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
+  }
+
+  bool WriteElf(art::File* file,
+                OatWriter* oat_writer,
+                const std::vector<const art::DexFile*>& dex_files,
+                const std::string& android_root,
+                bool is_host, const CompilerDriver& driver) const
+      OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return art::ElfWriterMclinker::Create(
+        file, oat_writer, dex_files, android_root, is_host, driver);
+  }
+
+  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+    return PortableCodeGenerator(
+        cu, cu->mir_graph.get(), &cu->arena,
+        reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit));
+  }
+
+  void InitCompilationUnit(CompilationUnit& cu) const {
+      // Fused long branches not currently useful in bitcode.
+    cu.disable_opt |=
+        (1 << kBranchFusing) |
+        (1 << kSuppressExceptionEdges);
+  }
+
+  bool IsPortable() const OVERRIDE {
+    return true;
+  }
+
+  void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+    typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&);
+
+    SetBitcodeFileNameFn set_bitcode_file_name =
+      reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
+
+    set_bitcode_file_name(driver, filename);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LLVMCompiler);
+};
+#endif
+
+Compiler* Compiler::Create(Compiler::Kind kind) {
+  switch (kind) {
+    case kQuick:
+      return new QuickCompiler();
+      break;
+    case kOptimizing:
+      return new OptimizingCompiler();
+      break;
+    case kPortable:
+#ifdef ART_USE_PORTABLE_COMPILER
+      return new LLVMCompiler();
+#else
+      LOG(FATAL) << "Portable compiler not compiled";
+#endif
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+  }
+  return nullptr;
+}
+
+}  // namespace art
diff --git a/compiler/compiler_backend.h b/compiler/compiler.h
similarity index 79%
rename from compiler/compiler_backend.h
rename to compiler/compiler.h
index b473806..1d5fc24 100644
--- a/compiler/compiler_backend.h
+++ b/compiler/compiler.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_COMPILER_BACKEND_H_
-#define ART_COMPILER_COMPILER_BACKEND_H_
+#ifndef ART_COMPILER_COMPILER_H_
+#define ART_COMPILER_COMPILER_H_
 
 #include "dex_file.h"
 #include "os.h"
@@ -33,18 +33,19 @@
   class ArtMethod;
 }
 
-class CompilerBackend {
+class Compiler {
  public:
   enum Kind {
     kQuick,
+    kOptimizing,
     kPortable
   };
 
-  explicit CompilerBackend(uint64_t warning)
+  explicit Compiler(uint64_t warning)
       : maximum_compilation_time_before_warning_(warning) {
   }
 
-  static CompilerBackend* Create(Kind kind);
+  static Compiler* Create(Kind kind);
 
   virtual void Init(CompilerDriver& driver) const = 0;
 
@@ -59,6 +60,15 @@
                                   jobject class_loader,
                                   const DexFile& dex_file) const = 0;
 
+  static CompiledMethod* TryCompileWithSeaIR(art::CompilerDriver& driver,
+                                             const art::DexFile::CodeItem* code_item,
+                                             uint32_t access_flags,
+                                             art::InvokeType invoke_type,
+                                             uint16_t class_def_idx,
+                                             uint32_t method_idx,
+                                             jobject class_loader,
+                                             const art::DexFile& dex_file);
+
   virtual CompiledMethod* JniCompile(CompilerDriver& driver,
                                      uint32_t access_flags,
                                      uint32_t method_idx,
@@ -91,7 +101,7 @@
 
   virtual void InitCompilationUnit(CompilationUnit& cu) const = 0;
 
-  virtual ~CompilerBackend() {}
+  virtual ~Compiler() {}
 
   /*
    * @brief Generate and return Dwarf CFI initialization, if supported by the
@@ -109,9 +119,9 @@
  private:
   const uint64_t maximum_compilation_time_before_warning_;
 
-  DISALLOW_COPY_AND_ASSIGN(CompilerBackend);
+  DISALLOW_COPY_AND_ASSIGN(Compiler);
 };
 
 }  // namespace art
 
-#endif  // ART_COMPILER_COMPILER_BACKEND_H_
+#endif  // ART_COMPILER_COMPILER_H_
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
deleted file mode 100644
index 0afa665..0000000
--- a/compiler/compiler_backend.cc
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * 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.
- */
-
-#include "compiler_backend.h"
-#include "elf_writer_quick.h"
-#include "dex/quick/mir_to_lir.h"
-#include "dex/mir_graph.h"
-#include "driver/compiler_driver.h"
-#include "mirror/art_method-inl.h"
-
-#ifdef ART_USE_PORTABLE_COMPILER
-#include "dex/portable/mir_to_gbc.h"
-#include "elf_writer_mclinker.h"
-#endif
-
-namespace art {
-
-#ifdef ART_SEA_IR_MODE
-extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler,
-                                                   const art::DexFile::CodeItem* code_item,
-                                                   uint32_t access_flags,
-                                                   art::InvokeType invoke_type,
-                                                   uint16_t class_def_idx,
-                                                   uint32_t method_idx,
-                                                   jobject class_loader,
-                                                   const art::DexFile& dex_file);
-#endif
-
-extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver);
-extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver);
-extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler,
-                                                      const art::DexFile::CodeItem* code_item,
-                                                      uint32_t access_flags,
-                                                      art::InvokeType invoke_type,
-                                                      uint16_t class_def_idx,
-                                                      uint32_t method_idx,
-                                                      jobject class_loader,
-                                                      const art::DexFile& dex_file);
-
-extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& compiler,
-                                                         uint32_t access_flags, uint32_t method_idx,
-                                                         const art::DexFile& dex_file);
-
-
-static CompiledMethod* TryCompileWithSeaIR(art::CompilerDriver& compiler,
-                                           const art::DexFile::CodeItem* code_item,
-                                           uint32_t access_flags,
-                                           art::InvokeType invoke_type,
-                                           uint16_t class_def_idx,
-                                           uint32_t method_idx,
-                                           jobject class_loader,
-                                           const art::DexFile& dex_file) {
-#ifdef ART_SEA_IR_MODE
-    bool use_sea = Runtime::Current()->IsSeaIRMode();
-    use_sea = use_sea &&
-        (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
-    if (use_sea) {
-      LOG(INFO) << "Using SEA IR to compile..." << std::endl;
-      return SeaIrCompileMethod(compiler,
-                                code_item,
-                                access_flags,
-                                invoke_type,
-                                class_def_idx,
-                                method_idx,
-                                class_loader,
-                                dex_file);
-  }
-#endif
-  return nullptr;
-}
-
-
-// Hack for CFI CIE initialization
-extern std::vector<uint8_t>* X86CFIInitialization();
-
-class QuickBackend : public CompilerBackend {
- public:
-  QuickBackend() : CompilerBackend(100) {}
-
-  void Init(CompilerDriver& driver) const {
-    ArtInitQuickCompilerContext(driver);
-  }
-
-  void UnInit(CompilerDriver& driver) const {
-    ArtUnInitQuickCompilerContext(driver);
-  }
-
-  CompiledMethod* Compile(CompilerDriver& compiler,
-                          const DexFile::CodeItem* code_item,
-                          uint32_t access_flags,
-                          InvokeType invoke_type,
-                          uint16_t class_def_idx,
-                          uint32_t method_idx,
-                          jobject class_loader,
-                          const DexFile& dex_file) const {
-    CompiledMethod* method = TryCompileWithSeaIR(compiler,
-                                                 code_item,
-                                                 access_flags,
-                                                 invoke_type,
-                                                 class_def_idx,
-                                                 method_idx,
-                                                 class_loader,
-                                                 dex_file);
-    if (method != nullptr) return method;
-
-    return ArtQuickCompileMethod(compiler,
-                                 code_item,
-                                 access_flags,
-                                 invoke_type,
-                                 class_def_idx,
-                                 method_idx,
-                                 class_loader,
-                                 dex_file);
-  }
-
-  CompiledMethod* JniCompile(CompilerDriver& driver,
-                             uint32_t access_flags,
-                             uint32_t method_idx,
-                             const DexFile& dex_file) const {
-    return ArtQuickJniCompileMethod(driver, access_flags, method_idx, dex_file);
-  }
-
-  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
-    return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
-  }
-
-  bool WriteElf(art::File* file,
-                OatWriter* oat_writer,
-                const std::vector<const art::DexFile*>& dex_files,
-                const std::string& android_root,
-                bool is_host, const CompilerDriver& driver) const
-    OVERRIDE
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
-  }
-
-  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
-    Mir2Lir* mir_to_lir = nullptr;
-    switch (cu->instruction_set) {
-      case kThumb2:
-        mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
-        break;
-      case kMips:
-        mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
-        break;
-      case kX86:
-        mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
-        break;
-      default:
-        LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
-    }
-
-    /* The number of compiler temporaries depends on backend so set it up now if possible */
-    if (mir_to_lir) {
-      size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
-      bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
-      CHECK(set_max);
-    }
-    return mir_to_lir;
-  }
-
-  void InitCompilationUnit(CompilationUnit& cu) const {}
-
-  /*
-   * @brief Generate and return Dwarf CFI initialization, if supported by the
-   * backend.
-   * @param driver CompilerDriver for this compile.
-   * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
-   * information.
-   * @note This is used for backtrace information in generated code.
-   */
-  std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver) const
-      OVERRIDE {
-    if (driver.GetInstructionSet() == kX86) {
-      return X86CFIInitialization();
-    }
-    return nullptr;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(QuickBackend);
-};
-
-#ifdef ART_USE_PORTABLE_COMPILER
-
-extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
-
-extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
-
-extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
-                                                 const art::DexFile::CodeItem* code_item,
-                                                 uint32_t access_flags,
-                                                 art::InvokeType invoke_type,
-                                                 uint16_t class_def_idx,
-                                                 uint32_t method_idx,
-                                                 jobject class_loader,
-                                                 const art::DexFile& dex_file);
-
-extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
-                                                        uint32_t access_flags, uint32_t method_idx,
-                                                        const art::DexFile& dex_file);
-
-extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
-                                               std::string const& filename);
-
-
-class LLVMBackend : public CompilerBackend {
- public:
-  LLVMBackend() : CompilerBackend(1000) {}
-
-  void Init(CompilerDriver& driver) const {
-    ArtInitCompilerContext(driver);
-  }
-
-  void UnInit(CompilerDriver& driver) const {
-    ArtUnInitCompilerContext(driver);
-  }
-
-  CompiledMethod* Compile(CompilerDriver& compiler,
-                          const DexFile::CodeItem* code_item,
-                          uint32_t access_flags,
-                          InvokeType invoke_type,
-                          uint16_t class_def_idx,
-                          uint32_t method_idx,
-                          jobject class_loader,
-                          const DexFile& dex_file) const {
-    CompiledMethod* method = TryCompileWithSeaIR(compiler,
-                                                 code_item,
-                                                 access_flags,
-                                                 invoke_type,
-                                                 class_def_idx,
-                                                 method_idx,
-                                                 class_loader,
-                                                 dex_file);
-    if (method != nullptr) return method;
-
-    return ArtCompileMethod(compiler,
-                            code_item,
-                            access_flags,
-                            invoke_type,
-                            class_def_idx,
-                            method_idx,
-                            class_loader,
-                            dex_file);
-  }
-
-  CompiledMethod* JniCompile(CompilerDriver& driver,
-                             uint32_t access_flags,
-                             uint32_t method_idx,
-                             const DexFile& dex_file) const {
-    return ArtLLVMJniCompileMethod(driver, access_flags, method_idx, dex_file);
-  }
-
-  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
-    return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
-  }
-
-  bool WriteElf(art::File* file,
-                OatWriter* oat_writer,
-                const std::vector<const art::DexFile*>& dex_files,
-                const std::string& android_root,
-                bool is_host, const CompilerDriver& driver) const
-      OVERRIDE
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return art::ElfWriterMclinker::Create(
-        file, oat_writer, dex_files, android_root, is_host, driver);
-  }
-
-  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
-    return PortableCodeGenerator(
-        cu, cu->mir_graph.get(), &cu->arena,
-        reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit));
-  }
-
-  void InitCompilationUnit(CompilationUnit& cu) const {
-      // Fused long branches not currently useful in bitcode.
-    cu.disable_opt |=
-        (1 << kBranchFusing) |
-        (1 << kSuppressExceptionEdges);
-  }
-
-  bool IsPortable() const OVERRIDE {
-    return true;
-  }
-
-  void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
-    typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&);
-
-    SetBitcodeFileNameFn set_bitcode_file_name =
-      reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
-
-    set_bitcode_file_name(driver, filename);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LLVMBackend);
-};
-#endif
-
-CompilerBackend* CompilerBackend::Create(CompilerBackend::Kind kind) {
-  switch (kind) {
-    case kQuick:
-      return new QuickBackend();
-      break;
-    case kPortable:
-#ifdef ART_USE_PORTABLE_COMPILER
-      return new LLVMBackend();
-#else
-      LOG(FATAL) << "Portable compiler not compiled";
-#endif
-      break;
-    default:
-      LOG(FATAL) << "UNREACHABLE";
-  }
-  return nullptr;
-}
-
-}  // namespace art
diff --git a/compiler/compilers.cc b/compiler/compilers.cc
new file mode 100644
index 0000000..9bb1719
--- /dev/null
+++ b/compiler/compilers.cc
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#include "compilers.h"
+#include "dex/mir_graph.h"
+#include "dex/quick/mir_to_lir.h"
+#include "elf_writer_quick.h"
+#include "mirror/art_method-inl.h"
+
+namespace art {
+
+extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver);
+extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& driver,
+                                                      const art::DexFile::CodeItem* code_item,
+                                                      uint32_t access_flags,
+                                                      art::InvokeType invoke_type,
+                                                      uint16_t class_def_idx,
+                                                      uint32_t method_idx,
+                                                      jobject class_loader,
+                                                      const art::DexFile& dex_file);
+
+extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& driver,
+                                                         uint32_t access_flags, uint32_t method_idx,
+                                                         const art::DexFile& dex_file);
+
+// Hack for CFI CIE initialization
+extern std::vector<uint8_t>* X86CFIInitialization();
+
+void QuickCompiler::Init(CompilerDriver& driver) const {
+  ArtInitQuickCompilerContext(driver);
+}
+
+void QuickCompiler::UnInit(CompilerDriver& driver) const {
+  ArtUnInitQuickCompilerContext(driver);
+}
+
+CompiledMethod* QuickCompiler::Compile(CompilerDriver& driver,
+                                      const DexFile::CodeItem* code_item,
+                                      uint32_t access_flags,
+                                      InvokeType invoke_type,
+                                      uint16_t class_def_idx,
+                                      uint32_t method_idx,
+                                      jobject class_loader,
+                                      const DexFile& dex_file) const {
+  CompiledMethod* method = TryCompileWithSeaIR(driver,
+                                               code_item,
+                                               access_flags,
+                                               invoke_type,
+                                               class_def_idx,
+                                               method_idx,
+                                               class_loader,
+                                               dex_file);
+  if (method != nullptr) return method;
+
+  return ArtQuickCompileMethod(driver,
+                               code_item,
+                               access_flags,
+                               invoke_type,
+                               class_def_idx,
+                               method_idx,
+                               class_loader,
+                               dex_file);
+}
+
+CompiledMethod* QuickCompiler::JniCompile(CompilerDriver& driver,
+                                          uint32_t access_flags,
+                                          uint32_t method_idx,
+                                          const DexFile& dex_file) const {
+  return ArtQuickJniCompileMethod(driver, access_flags, method_idx, dex_file);
+}
+
+uintptr_t QuickCompiler::GetEntryPointOf(mirror::ArtMethod* method) const {
+  return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
+}
+
+bool QuickCompiler::WriteElf(art::File* file,
+                            OatWriter* oat_writer,
+                            const std::vector<const art::DexFile*>& dex_files,
+                            const std::string& android_root,
+                            bool is_host, const CompilerDriver& driver) const
+  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
+}
+
+Backend* QuickCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+  Mir2Lir* mir_to_lir = nullptr;
+  switch (cu->instruction_set) {
+    case kThumb2:
+      mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+      break;
+    case kMips:
+      mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+      break;
+    case kX86:
+      mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
+  }
+
+  /* The number of compiler temporaries depends on backend so set it up now if possible */
+  if (mir_to_lir) {
+    size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
+    bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
+    CHECK(set_max);
+  }
+  return mir_to_lir;
+}
+
+std::vector<uint8_t>* QuickCompiler::GetCallFrameInformationInitialization(
+    const CompilerDriver& driver) const {
+  if (driver.GetInstructionSet() == kX86) {
+    return X86CFIInitialization();
+  }
+  return nullptr;
+}
+
+CompiledMethod* OptimizingCompiler::Compile(CompilerDriver& driver,
+                                            const DexFile::CodeItem* code_item,
+                                            uint32_t access_flags,
+                                            InvokeType invoke_type,
+                                            uint16_t class_def_idx,
+                                            uint32_t method_idx,
+                                            jobject class_loader,
+                                            const DexFile& dex_file) const {
+  CompiledMethod* method = TryCompile(
+      driver, code_item, access_flags, invoke_type, class_def_idx, method_idx,
+      class_loader, dex_file);
+  if (method != nullptr) return method;
+
+  return QuickCompiler::Compile(
+      driver, code_item, access_flags, invoke_type, class_def_idx, method_idx,
+      class_loader, dex_file);
+}
+
+}  // namespace art
diff --git a/compiler/compilers.h b/compiler/compilers.h
new file mode 100644
index 0000000..892a6bd
--- /dev/null
+++ b/compiler/compilers.h
@@ -0,0 +1,103 @@
+/*
+ * 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_COMPILERS_H_
+#define ART_COMPILER_COMPILERS_H_
+
+#include "compiler.h"
+
+namespace art {
+
+class QuickCompiler : public Compiler {
+ public:
+  QuickCompiler() : Compiler(100) {}
+
+  void Init(CompilerDriver& driver) const OVERRIDE;
+
+  void UnInit(CompilerDriver& driver) const OVERRIDE;
+
+  CompiledMethod* Compile(CompilerDriver& driver,
+                          const DexFile::CodeItem* code_item,
+                          uint32_t access_flags,
+                          InvokeType invoke_type,
+                          uint16_t class_def_idx,
+                          uint32_t method_idx,
+                          jobject class_loader,
+                          const DexFile& dex_file) const OVERRIDE;
+
+  CompiledMethod* JniCompile(CompilerDriver& driver,
+                             uint32_t access_flags,
+                             uint32_t method_idx,
+                             const DexFile& dex_file) const OVERRIDE;
+
+  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const OVERRIDE;
+
+  bool WriteElf(art::File* file,
+                OatWriter* oat_writer,
+                const std::vector<const art::DexFile*>& dex_files,
+                const std::string& android_root,
+                bool is_host, const CompilerDriver& driver) const
+    OVERRIDE
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE;
+
+  void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE {}
+
+  /*
+   * @brief Generate and return Dwarf CFI initialization, if supported by the
+   * backend.
+   * @param driver CompilerDriver for this compile.
+   * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+   * information.
+   * @note This is used for backtrace information in generated code.
+   */
+  std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver) const
+      OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(QuickCompiler);
+};
+
+class OptimizingCompiler : public QuickCompiler {
+ public:
+  OptimizingCompiler() { }
+
+  CompiledMethod* Compile(CompilerDriver& driver,
+                          const DexFile::CodeItem* code_item,
+                          uint32_t access_flags,
+                          InvokeType invoke_type,
+                          uint16_t class_def_idx,
+                          uint32_t method_idx,
+                          jobject class_loader,
+                          const DexFile& dex_file) const OVERRIDE;
+
+  CompiledMethod* TryCompile(CompilerDriver& driver,
+                             const DexFile::CodeItem* code_item,
+                             uint32_t access_flags,
+                             InvokeType invoke_type,
+                             uint16_t class_def_idx,
+                             uint32_t method_idx,
+                             jobject class_loader,
+                             const DexFile& dex_file) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_COMPILERS_H_
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index c71f047..70159ca 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -62,7 +62,7 @@
   uint32_t disable_opt;                // opt_control_vector flags.
   uint32_t enable_debug;               // debugControlVector flags.
   bool verbose;
-  const CompilerBackend* compiler_backend;
+  const Compiler* compiler;
   InstructionSet instruction_set;
   bool target64;
 
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 3bd71d1..83fbca5 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "compiler_backend.h"
+#include "compiler.h"
 #include "compiler_internals.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
@@ -23,7 +23,6 @@
 #include "mirror/object.h"
 #include "pass_driver.h"
 #include "runtime.h"
-#include "backend.h"
 #include "base/logging.h"
 #include "base/timing_logger.h"
 #include "driver/compiler_options.h"
@@ -90,7 +89,7 @@
     disable_opt(0),
     enable_debug(0),
     verbose(false),
-    compiler_backend(NULL),
+    compiler(NULL),
     instruction_set(kNone),
     num_dalvik_registers(0),
     insns(NULL),
@@ -131,7 +130,7 @@
 }
 
 static CompiledMethod* CompileMethod(CompilerDriver& driver,
-                                     CompilerBackend* compiler_backend,
+                                     Compiler* compiler,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
                                      uint16_t class_def_idx, uint32_t method_idx,
@@ -157,7 +156,7 @@
   cu.class_linker = class_linker;
   cu.instruction_set = driver.GetInstructionSet();
   cu.target64 = cu.instruction_set == kX86_64;
-  cu.compiler_backend = compiler_backend;
+  cu.compiler = compiler;
   // TODO: x86_64 is not yet implemented.
   DCHECK((cu.instruction_set == kThumb2) ||
          (cu.instruction_set == kX86) ||
@@ -184,7 +183,7 @@
    * MIR and backend flags?  Need command-line setting as well.
    */
 
-  compiler_backend->InitCompilationUnit(cu);
+  compiler->InitCompilationUnit(cu);
 
   if (cu.instruction_set == kMips) {
     // Disable some optimizations for mips for now
@@ -209,7 +208,7 @@
    * The reason we do this is that optimizations on the MIR graph may need to get information
    * that is only available if a CG exists.
    */
-  cu.cg.reset(compiler_backend->GetCodeGenerator(&cu, llvm_compilation_unit));
+  cu.cg.reset(compiler->GetCodeGenerator(&cu, llvm_compilation_unit));
 
   /* Gathering opcode stats? */
   if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
@@ -286,8 +285,8 @@
   return result;
 }
 
-CompiledMethod* CompileOneMethod(CompilerDriver& compiler,
-                                 CompilerBackend* backend,
+CompiledMethod* CompileOneMethod(CompilerDriver& driver,
+                                 Compiler* compiler,
                                  const DexFile::CodeItem* code_item,
                                  uint32_t access_flags,
                                  InvokeType invoke_type,
@@ -296,21 +295,21 @@
                                  jobject class_loader,
                                  const DexFile& dex_file,
                                  void* compilation_unit) {
-  return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
+  return CompileMethod(driver, compiler, code_item, access_flags, invoke_type, class_def_idx,
                        method_idx, class_loader, dex_file, compilation_unit);
 }
 
 }  // namespace art
 
 extern "C" art::CompiledMethod*
-    ArtQuickCompileMethod(art::CompilerDriver& compiler,
+    ArtQuickCompileMethod(art::CompilerDriver& driver,
                           const art::DexFile::CodeItem* code_item,
                           uint32_t access_flags, art::InvokeType invoke_type,
                           uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
                           const art::DexFile& dex_file) {
   // TODO: check method fingerprint here to determine appropriate backend type.  Until then, use build default
-  art::CompilerBackend* backend = compiler.GetCompilerBackend();
-  return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type,
+  art::Compiler* compiler = driver.GetCompiler();
+  return art::CompileOneMethod(driver, compiler, code_item, access_flags, invoke_type,
                                class_def_idx, method_idx, class_loader, dex_file,
                                NULL /* use thread llvm_info */);
 }
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 03fc091..cb737ab 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -405,7 +405,7 @@
       // Is this the select pattern?
       // TODO: flesh out support for Mips.  NOTE: llvm's select op doesn't quite work here.
       // TUNING: expand to support IF_xx compare & branches
-      if (!cu_->compiler_backend->IsPortable() &&
+      if (!cu_->compiler->IsPortable() &&
           (cu_->instruction_set == kThumb2 || cu_->instruction_set == kX86) &&
           IsInstructionIfCcZ(mir->dalvikInsn.opcode)) {
         BasicBlock* ft = GetBasicBlock(bb->fall_through);
diff --git a/compiler/dex/pass_driver.cc b/compiler/dex/pass_driver.cc
index 291012f..72d3ea6 100644
--- a/compiler/dex/pass_driver.cc
+++ b/compiler/dex/pass_driver.cc
@@ -82,31 +82,48 @@
   pass_list_.push_back(new_pass);
 }
 
-void PassDriver::CreatePasses() {
-  /*
-   * Create the pass list. These passes are immutable and are shared across the threads.
-   *
-   * Advantage is that there will be no race conditions here.
-   * Disadvantage is the passes can't change their internal states depending on CompilationUnit:
-   *   - This is not yet an issue: no current pass would require it.
-   */
-  static const Pass* const passes[] = {
-      GetPassInstance<CacheFieldLoweringInfo>(),
-      GetPassInstance<CacheMethodLoweringInfo>(),
-      GetPassInstance<CodeLayout>(),
-      GetPassInstance<SSATransformation>(),
-      GetPassInstance<ConstantPropagation>(),
-      GetPassInstance<InitRegLocations>(),
-      GetPassInstance<MethodUseCount>(),
-      GetPassInstance<NullCheckEliminationAndTypeInferenceInit>(),
-      GetPassInstance<NullCheckEliminationAndTypeInference>(),
-      GetPassInstance<BBCombine>(),
-      GetPassInstance<BBOptimizations>(),
-  };
+/*
+ * Create the pass list. These passes are immutable and are shared across the threads.
+ *
+ * Advantage is that there will be no race conditions here.
+ * Disadvantage is the passes can't change their internal states depending on CompilationUnit:
+ *   - This is not yet an issue: no current pass would require it.
+ */
+static const Pass* const gPasses[] = {
+  GetPassInstance<CacheFieldLoweringInfo>(),
+  GetPassInstance<CacheMethodLoweringInfo>(),
+  GetPassInstance<CodeLayout>(),
+  GetPassInstance<SSATransformation>(),
+  GetPassInstance<ConstantPropagation>(),
+  GetPassInstance<InitRegLocations>(),
+  GetPassInstance<MethodUseCount>(),
+  GetPassInstance<NullCheckEliminationAndTypeInferenceInit>(),
+  GetPassInstance<NullCheckEliminationAndTypeInference>(),
+  GetPassInstance<BBCombine>(),
+  GetPassInstance<BBOptimizations>(),
+};
 
+// The default pass list is used by CreatePasses to initialize pass_list_.
+static std::vector<const Pass*> gDefaultPassList(gPasses, gPasses + arraysize(gPasses));
+
+void PassDriver::CreateDefaultPassList(const std::string& disable_passes) {
+  // Insert each pass from gPasses into gDefaultPassList.
+  gDefaultPassList.clear();
+  gDefaultPassList.reserve(arraysize(gPasses));
+  for (const Pass* pass : gPasses) {
+    // Check if we should disable this pass.
+    if (disable_passes.find(pass->GetName()) != std::string::npos) {
+      LOG(INFO) << "Skipping " << pass->GetName();
+    } else {
+      gDefaultPassList.push_back(pass);
+    }
+  }
+}
+
+void PassDriver::CreatePasses() {
   // Insert each pass into the list via the InsertPass method.
-  pass_list_.reserve(arraysize(passes));
-  for (const Pass* pass : passes) {
+  pass_list_.reserve(gDefaultPassList.size());
+  for (const Pass* pass : gDefaultPassList) {
     InsertPass(pass);
   }
 }
@@ -221,10 +238,10 @@
   }
 }
 
-void PassDriver::PrintPassNames() const {
+void PassDriver::PrintPassNames() {
   LOG(INFO) << "Loop Passes are:";
 
-  for (const Pass* cur_pass : pass_list_) {
+  for (const Pass* cur_pass : gPasses) {
     LOG(INFO) << "\t-" << cur_pass->GetName();
   }
 }
diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h
index c734d3e..2b7196e 100644
--- a/compiler/dex/pass_driver.h
+++ b/compiler/dex/pass_driver.h
@@ -73,7 +73,8 @@
    */
   void DispatchPass(CompilationUnit* c_unit, const Pass* pass);
 
-  void PrintPassNames() const;
+  static void PrintPassNames();
+  static void CreateDefaultPassList(const std::string& disable_passes);
 
   const Pass* GetPass(const char* name) const;
 
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 7423393..e50ba24 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#include "dex_file_method_inliner.h"
+
 #include <algorithm>
+
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "base/mutex-inl.h"
@@ -26,24 +29,8 @@
 #include "verifier/method_verifier.h"
 #include "verifier/method_verifier-inl.h"
 
-#include "dex_file_method_inliner.h"
-
 namespace art {
 
-namespace {  // anonymous namespace
-
-constexpr uint8_t kIGetIPutOpSizes[] = {
-    kWord,          // IGET, IPUT
-    kLong,          // IGET_WIDE, IPUT_WIDE
-    kWord,          // IGET_OBJECT, IPUT_OBJECT
-    kSignedByte,    // IGET_BOOLEAN, IPUT_BOOLEAN
-    kSignedByte,    // IGET_BYTE, IPUT_BYTE
-    kUnsignedHalf,  // IGET_CHAR, IPUT_CHAR
-    kSignedHalf,    // IGET_SHORT, IPUT_SHORT
-};
-
-}  // anonymous namespace
-
 const uint32_t DexFileMethodInliner::kIndexUnresolved;
 const char* const DexFileMethodInliner::kClassCacheNames[] = {
     "Z",                       // kClassCacheBoolean
@@ -271,56 +258,10 @@
 
 bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
   InlineMethod method;
-  bool success = AnalyseMethodCode(verifier, &method);
+  bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method);
   return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
 }
 
-bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier,
-                                             InlineMethod* method) {
-  // We currently support only plain return or 2-instruction methods.
-
-  const DexFile::CodeItem* code_item = verifier->CodeItem();
-  DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
-  const Instruction* instruction = Instruction::At(code_item->insns_);
-  Instruction::Code opcode = instruction->Opcode();
-
-  switch (opcode) {
-    case Instruction::RETURN_VOID:
-      method->opcode = kInlineOpNop;
-      method->flags = kInlineSpecial;
-      method->d.data = 0u;
-      return true;
-    case Instruction::RETURN:
-    case Instruction::RETURN_OBJECT:
-    case Instruction::RETURN_WIDE:
-      return AnalyseReturnMethod(code_item, method);
-    case Instruction::CONST:
-    case Instruction::CONST_4:
-    case Instruction::CONST_16:
-    case Instruction::CONST_HIGH16:
-      // TODO: Support wide constants (RETURN_WIDE).
-      return AnalyseConstMethod(code_item, method);
-    case Instruction::IGET:
-    case Instruction::IGET_OBJECT:
-    case Instruction::IGET_BOOLEAN:
-    case Instruction::IGET_BYTE:
-    case Instruction::IGET_CHAR:
-    case Instruction::IGET_SHORT:
-    case Instruction::IGET_WIDE:
-      return AnalyseIGetMethod(verifier, method);
-    case Instruction::IPUT:
-    case Instruction::IPUT_OBJECT:
-    case Instruction::IPUT_BOOLEAN:
-    case Instruction::IPUT_BYTE:
-    case Instruction::IPUT_CHAR:
-    case Instruction::IPUT_SHORT:
-    case Instruction::IPUT_WIDE:
-      return AnalyseIPutMethod(verifier, method);
-    default:
-      return false;
-  }
-}
-
 bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
   ReaderMutexLock mu(Thread::Current(), lock_);
   auto it = inline_methods_.find(method_index);
@@ -543,160 +484,4 @@
   }
 }
 
-bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
-                                               InlineMethod* result) {
-  const Instruction* return_instruction = Instruction::At(code_item->insns_);
-  Instruction::Code return_opcode = return_instruction->Opcode();
-  uint16_t size = (return_opcode == Instruction::RETURN_WIDE) ? kLong : kWord;
-  uint16_t is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
-  uint32_t reg = return_instruction->VRegA_11x();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
-  DCHECK_GE(reg, arg_start);
-  DCHECK_LT(size == kLong ? reg + 1 : reg, code_item->registers_size_);
-
-  result->opcode = kInlineOpReturnArg;
-  result->flags = kInlineSpecial;
-  InlineReturnArgData* data = &result->d.return_data;
-  data->arg = reg - arg_start;
-  data->op_size = size;
-  data->is_object = is_object;
-  data->reserved = 0u;
-  data->reserved2 = 0u;
-  return true;
-}
-
-bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item,
-                                              InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
-  const Instruction* return_instruction = instruction->Next();
-  Instruction::Code return_opcode = return_instruction->Opcode();
-  if (return_opcode != Instruction::RETURN &&
-      return_opcode != Instruction::RETURN_OBJECT) {
-    return false;
-  }
-
-  uint32_t return_reg = return_instruction->VRegA_11x();
-  DCHECK_LT(return_reg, code_item->registers_size_);
-
-  uint32_t vA, vB, dummy;
-  uint64_t dummy_wide;
-  instruction->Decode(vA, vB, dummy_wide, dummy, nullptr);
-  if (instruction->Opcode() == Instruction::CONST_HIGH16) {
-    vB <<= 16;
-  }
-  DCHECK_LT(vA, code_item->registers_size_);
-  if (vA != return_reg) {
-    return false;  // Not returning the value set by const?
-  }
-  if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
-    return false;  // Returning non-null reference constant?
-  }
-  result->opcode = kInlineOpNonWideConst;
-  result->flags = kInlineSpecial;
-  result->d.data = static_cast<uint64_t>(vB);
-  return true;
-}
-
-bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
-                                             InlineMethod* result) {
-  const DexFile::CodeItem* code_item = verifier->CodeItem();
-  const Instruction* instruction = Instruction::At(code_item->insns_);
-  Instruction::Code opcode = instruction->Opcode();
-  DCHECK_LT(static_cast<size_t>(opcode - Instruction::IGET), arraysize(kIGetIPutOpSizes));
-  uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IGET];
-
-  const Instruction* return_instruction = instruction->Next();
-  Instruction::Code return_opcode = return_instruction->Opcode();
-  if (!(return_opcode == Instruction::RETURN && size != kLong) &&
-      !(return_opcode == Instruction::RETURN_WIDE && size == kLong) &&
-      !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT)) {
-    return false;
-  }
-
-  uint32_t return_reg = return_instruction->VRegA_11x();
-  DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
-            code_item->registers_size_);
-
-  uint32_t dst_reg = instruction->VRegA_22c();
-  uint32_t object_reg = instruction->VRegB_22c();
-  uint32_t field_idx = instruction->VRegC_22c();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
-  DCHECK_GE(object_reg, arg_start);
-  DCHECK_LT(object_reg, code_item->registers_size_);
-  DCHECK_LT(size == kLong ? dst_reg + 1 : dst_reg, code_item->registers_size_);
-  if (dst_reg != return_reg) {
-    return false;  // Not returning the value retrieved by IGET?
-  }
-
-  if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
-    // TODO: Support inlining IGET on other register than "this".
-    return false;
-  }
-
-  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier,
-                                                  &result->d.ifield_data)) {
-    return false;
-  }
-
-  result->opcode = kInlineOpIGet;
-  result->flags = kInlineSpecial;
-  InlineIGetIPutData* data = &result->d.ifield_data;
-  data->op_size = size;
-  data->is_object = (opcode == Instruction::IGET_OBJECT) ? 1u : 0u;
-  data->object_arg = object_reg - arg_start;  // Allow IGET on any register, not just "this".
-  data->src_arg = 0;
-  data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
-  data->reserved = 0;
-  return true;
-}
-
-bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
-                                             InlineMethod* result) {
-  const DexFile::CodeItem* code_item = verifier->CodeItem();
-  const Instruction* instruction = Instruction::At(code_item->insns_);
-  Instruction::Code opcode = instruction->Opcode();
-  DCHECK_LT(static_cast<size_t>(opcode - Instruction::IPUT), arraysize(kIGetIPutOpSizes));
-  uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IPUT];
-
-  const Instruction* return_instruction = instruction->Next();
-  if (return_instruction->Opcode() != Instruction::RETURN_VOID) {
-    // TODO: Support returning an argument.
-    // This is needed by builder classes and generated accessor setters.
-    //    builder.setX(value): iput value, this, fieldX; return-object this;
-    //    object.access$nnn(value): iput value, this, fieldX; return value;
-    // Use InlineIGetIPutData::reserved to hold the information.
-    return false;
-  }
-
-  uint32_t src_reg = instruction->VRegA_22c();
-  uint32_t object_reg = instruction->VRegB_22c();
-  uint32_t field_idx = instruction->VRegC_22c();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
-  DCHECK_GE(object_reg, arg_start);
-  DCHECK_LT(object_reg, code_item->registers_size_);
-  DCHECK_GE(src_reg, arg_start);
-  DCHECK_LT(size == kLong ? src_reg + 1 : src_reg, code_item->registers_size_);
-
-  if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
-    // TODO: Support inlining IPUT on other register than "this".
-    return false;
-  }
-
-  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier,
-                                                  &result->d.ifield_data)) {
-    return false;
-  }
-
-  result->opcode = kInlineOpIPut;
-  result->flags = kInlineSpecial;
-  InlineIGetIPutData* data = &result->d.ifield_data;
-  data->op_size = size;
-  data->is_object = (opcode == Instruction::IPUT_OBJECT) ? 1u : 0u;
-  data->object_arg = object_reg - arg_start;  // Allow IPUT on any register, not just "this".
-  data->src_arg = src_reg - arg_start;
-  data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
-  data->reserved = 0;
-  return true;
-}
-
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 4aff01c..a6d4cab 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -23,6 +23,7 @@
 #include "safe_map.h"
 #include "dex/compiler_enums.h"
 #include "dex_file.h"
+#include "quick/inline_method_analyser.h"
 
 namespace art {
 
@@ -33,102 +34,6 @@
 struct CallInfo;
 class Mir2Lir;
 
-enum InlineMethodOpcode : uint16_t {
-  kIntrinsicDoubleCvt,
-  kIntrinsicFloatCvt,
-  kIntrinsicReverseBytes,
-  kIntrinsicAbsInt,
-  kIntrinsicAbsLong,
-  kIntrinsicAbsFloat,
-  kIntrinsicAbsDouble,
-  kIntrinsicMinMaxInt,
-  kIntrinsicSqrt,
-  kIntrinsicCharAt,
-  kIntrinsicCompareTo,
-  kIntrinsicIsEmptyOrLength,
-  kIntrinsicIndexOf,
-  kIntrinsicCurrentThread,
-  kIntrinsicPeek,
-  kIntrinsicPoke,
-  kIntrinsicCas,
-  kIntrinsicUnsafeGet,
-  kIntrinsicUnsafePut,
-
-  kInlineOpNop,
-  kInlineOpReturnArg,
-  kInlineOpNonWideConst,
-  kInlineOpIGet,
-  kInlineOpIPut,
-};
-std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
-
-enum InlineMethodFlags : uint16_t {
-  kNoInlineMethodFlags = 0x0000,
-  kInlineIntrinsic     = 0x0001,
-  kInlineSpecial       = 0x0002,
-};
-
-// IntrinsicFlags are stored in InlineMethod::d::raw_data
-enum IntrinsicFlags {
-  kIntrinsicFlagNone = 0,
-
-  // kIntrinsicMinMaxInt
-  kIntrinsicFlagMax = kIntrinsicFlagNone,
-  kIntrinsicFlagMin = 1,
-
-  // kIntrinsicIsEmptyOrLength
-  kIntrinsicFlagLength  = kIntrinsicFlagNone,
-  kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
-
-  // kIntrinsicIndexOf
-  kIntrinsicFlagBase0 = kIntrinsicFlagMin,
-
-  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
-  kIntrinsicFlagIsLong     = kIntrinsicFlagMin,
-  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
-  kIntrinsicFlagIsVolatile = 2,
-  // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
-  kIntrinsicFlagIsObject   = 4,
-  // kIntrinsicUnsafePut
-  kIntrinsicFlagIsOrdered  = 8,
-};
-
-// Check that OpSize fits into 3 bits (at least the values the inliner uses).
-COMPILE_ASSERT(kWord < 8 && kLong < 8 && kSingle < 8 && kDouble < 8 && kUnsignedHalf < 8 &&
-               kSignedHalf < 8 && kUnsignedByte < 8 && kSignedByte < 8, op_size_field_too_narrow);
-
-struct InlineIGetIPutData {
-  uint16_t op_size : 3;  // OpSize
-  uint16_t is_object : 1;
-  uint16_t object_arg : 4;
-  uint16_t src_arg : 4;  // iput only
-  uint16_t method_is_static : 1;
-  uint16_t reserved : 3;
-  uint16_t field_idx;
-  uint32_t is_volatile : 1;
-  uint32_t field_offset : 31;
-};
-COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
-
-struct InlineReturnArgData {
-  uint16_t arg;
-  uint16_t op_size : 3;  // OpSize
-  uint16_t is_object : 1;
-  uint16_t reserved : 12;
-  uint32_t reserved2;
-};
-COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
-
-struct InlineMethod {
-  InlineMethodOpcode opcode;
-  InlineMethodFlags flags;
-  union {
-    uint64_t data;
-    InlineIGetIPutData ifield_data;
-    InlineReturnArgData return_data;
-  } d;
-};
-
 /**
  * Handles inlining of methods from a particular DexFile.
  *
@@ -157,17 +62,6 @@
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
 
     /**
-     * Analyse method code to determine if the method is a candidate for inlining.
-     * If it is, record the inlining data.
-     *
-     * @param verifier the method verifier holding data about the method to analyse.
-     * @param method placeholder for the inline method data.
-     * @return true if the method is a candidate for inlining, false otherwise.
-     */
-    bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
-
-    /**
      * Check whether a particular method index corresponds to an intrinsic function.
      */
     bool IsIntrinsic(uint32_t method_index) LOCKS_EXCLUDED(lock_);
@@ -392,13 +286,6 @@
 
     bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
 
-    static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
-    static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
-    static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-    static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
     ReaderWriterMutex lock_;
     /*
      * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 40ed5ef..31f5c28 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -123,8 +123,8 @@
     return false;
   }
 
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
+  bool wide = (data.op_variant == InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE));
+  // The inliner doesn't distinguish kDouble or kFloat, use shorty.
   bool double_or_float = cu_->shorty[0] == 'F' || cu_->shorty[0] == 'D';
 
   // Point of no return - no aborts after this
@@ -151,8 +151,7 @@
     return false;
   }
 
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
+  bool wide = (data.op_variant == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE));
 
   // Point of no return - no aborts after this
   GenPrintLabel(mir);
@@ -173,7 +172,7 @@
   if (data.is_volatile) {
     GenMemBarrier(kLoadLoad);
   }
-  if (data.is_object) {
+  if (data.op_variant == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT)) {
     MarkGCCard(reg_src, reg_obj);
   }
   return true;
@@ -181,8 +180,8 @@
 
 bool Mir2Lir::GenSpecialIdentity(MIR* mir, const InlineMethod& special) {
   const InlineReturnArgData& data = special.d.return_data;
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
+  bool wide = (data.is_wide != 0u);
+  // The inliner doesn't distinguish kDouble or kFloat, use shorty.
   bool double_or_float = cu_->shorty[0] == 'F' || cu_->shorty[0] == 'D';
 
   // Point of no return - no aborts after this
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 083fccb..3596fff 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -1028,7 +1028,7 @@
       } else {
         // Compare to memory to avoid a register load.  Handle pushed EDI.
         int displacement = SRegOffset(rl_start.s_reg_low) + sizeof(uint32_t);
-        OpRegMem(kOpCmp, rDX, rX86_SP, displacement);
+        OpRegMem(kOpCmp, rCX, rX86_SP, displacement);
         length_compare = NewLIR2(kX86Jcc8, 0, kX86CondLe);
         OpRegMem(kOpSub, rCX, rX86_SP, displacement);
       }
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 7c4a6f7..5ee31f7 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -26,7 +26,7 @@
 #include "base/stl_util.h"
 #include "base/timing_logger.h"
 #include "class_linker.h"
-#include "compiler_backend.h"
+#include "compiler.h"
 #include "compiler_driver-inl.h"
 #include "dex_compilation_unit.h"
 #include "dex_file-inl.h"
@@ -324,7 +324,7 @@
 CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
                                VerificationResults* verification_results,
                                DexFileToMethodInlinerMap* method_inliner_map,
-                               CompilerBackend::Kind compiler_backend_kind,
+                               Compiler::Kind compiler_kind,
                                InstructionSet instruction_set,
                                InstructionSetFeatures instruction_set_features,
                                bool image, DescriptorSet* image_classes, size_t thread_count,
@@ -333,7 +333,7 @@
     : profile_ok_(false), compiler_options_(compiler_options),
       verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
-      compiler_backend_(CompilerBackend::Create(compiler_backend_kind)),
+      compiler_(Compiler::Create(compiler_kind)),
       instruction_set_(instruction_set),
       instruction_set_features_(instruction_set_features),
       freezing_constructor_lock_("freezing constructor lock"),
@@ -371,7 +371,7 @@
 
   dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
 
-  compiler_backend_->Init(*this);
+  compiler_->Init(*this);
 
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
@@ -380,7 +380,7 @@
 
   // Are we generating CFI information?
   if (compiler_options->GetGenerateGDBInformation()) {
-    cfi_info_.reset(compiler_backend_->GetCallFrameInformationInitialization(*this));
+    cfi_info_.reset(compiler_->GetCallFrameInformationInitialization(*this));
   }
 }
 
@@ -430,7 +430,7 @@
     STLDeleteElements(&classes_to_patch_);
   }
   CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
-  compiler_backend_->UnInit(*this);
+  compiler_->UnInit(*this);
 }
 
 CompilerTls* CompilerDriver::GetTls() {
@@ -961,29 +961,6 @@
   stats_->ProcessedInvoke(invoke_type, flags);
 }
 
-bool CompilerDriver::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
-                                                verifier::MethodVerifier* verifier,
-                                                InlineIGetIPutData* result) {
-  mirror::DexCache* dex_cache = verifier->GetDexCache();
-  uint32_t method_idx = verifier->GetMethodReference().dex_method_index;
-  mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx);
-  mirror::ArtField* field = dex_cache->GetResolvedField(field_idx);
-  if (method == nullptr || field == nullptr || field->IsStatic()) {
-    return false;
-  }
-  mirror::Class* method_class = method->GetDeclaringClass();
-  mirror::Class* field_class = field->GetDeclaringClass();
-  if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
-      (is_put && field->IsFinal() && method_class != field_class)) {
-    return false;
-  }
-  DCHECK_GE(field->GetOffset().Int32Value(), 0);
-  result->field_idx = field_idx;
-  result->field_offset = field->GetOffset().Int32Value();
-  result->is_volatile = field->IsVolatile();
-  return true;
-}
-
 bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
                                               bool is_put, MemberOffset* field_offset,
                                               bool* is_volatile) {
@@ -1077,7 +1054,7 @@
   *direct_method = 0;
   bool use_dex_cache = false;
   const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
-  if (compiler_backend_->IsPortable()) {
+  if (compiler_->IsPortable()) {
     if (sharp_type != kStatic && sharp_type != kDirect) {
       return;
     }
@@ -1153,13 +1130,13 @@
         CHECK(!method->IsAbstract());
         *type = sharp_type;
         *direct_method = reinterpret_cast<uintptr_t>(method);
-        *direct_code = compiler_backend_->GetEntryPointOf(method);
+        *direct_code = compiler_->GetEntryPointOf(method);
         target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
         target_method->dex_method_index = method->GetDexMethodIndex();
       } else if (!must_use_direct_pointers) {
         // Set the code and rely on the dex cache for the method.
         *type = sharp_type;
-        *direct_code = compiler_backend_->GetEntryPointOf(method);
+        *direct_code = compiler_->GetEntryPointOf(method);
       } else {
         // Direct pointers were required but none were available.
         VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
@@ -1887,7 +1864,7 @@
 #if defined(__x86_64__)
     // leaving this empty will trigger the generic JNI version
 #else
-    compiled_method = compiler_backend_->JniCompile(*this, access_flags, method_idx, dex_file);
+    compiled_method = compiler_->JniCompile(*this, access_flags, method_idx, dex_file);
     CHECK(compiled_method != NULL);
 #endif
   } else if ((access_flags & kAccAbstract) != 0) {
@@ -1896,7 +1873,7 @@
     bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
     if (compile) {
       // NOTE: if compiler declines to compile this method, it will return NULL.
-      compiled_method = compiler_backend_->Compile(
+      compiled_method = compiler_->Compile(
           *this, code_item, access_flags, invoke_type, class_def_idx,
           method_idx, class_loader, dex_file);
     } else if (dex_to_dex_compilation_level != kDontDexToDexCompile) {
@@ -1908,7 +1885,7 @@
     }
   }
   uint64_t duration_ns = NanoTime() - start_ns;
-  if (duration_ns > MsToNs(compiler_backend_->GetMaximumCompilationTimeBeforeWarning())) {
+  if (duration_ns > MsToNs(compiler_->GetMaximumCompilationTimeBeforeWarning())) {
     LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file)
                  << " took " << PrettyDuration(duration_ns);
   }
@@ -1995,7 +1972,7 @@
                               OatWriter* oat_writer,
                               art::File* file)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return compiler_backend_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
+  return compiler_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
 }
 void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
                                                 std::string* target_triple,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 26210c9..71c431d 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -26,7 +26,7 @@
 #include "class_reference.h"
 #include "compiled_class.h"
 #include "compiled_method.h"
-#include "compiler_backend.h"
+#include "compiler.h"
 #include "dex_file.h"
 #include "instruction_set.h"
 #include "invoke_type.h"
@@ -99,7 +99,7 @@
   explicit CompilerDriver(const CompilerOptions* compiler_options,
                           VerificationResults* verification_results,
                           DexFileToMethodInlinerMap* method_inliner_map,
-                          CompilerBackend::Kind compiler_backend_kind,
+                          Compiler::Kind compiler_kind,
                           InstructionSet instruction_set,
                           InstructionSetFeatures instruction_set_features,
                           bool image, DescriptorSet* image_classes,
@@ -137,8 +137,8 @@
     return *compiler_options_;
   }
 
-  CompilerBackend* GetCompilerBackend() const {
-    return compiler_backend_.get();
+  Compiler* GetCompiler() const {
+    return compiler_.get();
   }
 
   bool ProfilePresent() const {
@@ -287,13 +287,6 @@
   void ProcessedStaticField(bool resolved, bool local);
   void ProcessedInvoke(InvokeType invoke_type, int flags);
 
-  // Can we fast path instance field access in a verified accessor?
-  // If yes, computes field's offset and volatility and whether the method is static or not.
-  static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
-                                         verifier::MethodVerifier* verifier,
-                                         InlineIGetIPutData* result)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // Can we fast path instance field access? Computes field's offset and volatility.
   bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
                                 MemberOffset* field_offset, bool* is_volatile)
@@ -708,7 +701,7 @@
   VerificationResults* const verification_results_;
   DexFileToMethodInlinerMap* const method_inliner_map_;
 
-  UniquePtr<CompilerBackend> compiler_backend_;
+  UniquePtr<Compiler> compiler_;
 
   const InstructionSet instruction_set_;
   const InstructionSetFeatures instruction_set_features_;
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index 4ce714a..2812700 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -39,7 +39,7 @@
 
 namespace art {
 void CompileOneMethod(CompilerDriver& driver,
-                      CompilerBackend* compilerBackend,
+                      Compiler* compiler,
                       const DexFile::CodeItem* code_item,
                       uint32_t access_flags, InvokeType invoke_type,
                       uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
@@ -142,7 +142,7 @@
   cunit->SetCompilerDriver(compiler_driver_);
   // TODO: consolidate ArtCompileMethods
   CompileOneMethod(*compiler_driver_,
-                   compiler_driver_->GetCompilerBackend(),
+                   compiler_driver_->GetCompiler(),
                    dex_compilation_unit->GetCodeItem(),
                    dex_compilation_unit->GetAccessFlags(),
                    invoke_type,
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 93c3502..9cfef12 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -15,7 +15,7 @@
  */
 
 #include "common_compiler_test.h"
-#include "compiler/compiler_backend.h"
+#include "compiler/compiler.h"
 #include "compiler/oat_writer.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -84,9 +84,9 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   // TODO: make selectable.
-  CompilerBackend::Kind compiler_backend = kUsePortableCompiler
-      ? CompilerBackend::kPortable
-      : CompilerBackend::kQuick;
+  Compiler::Kind compiler_kind = kUsePortableCompiler
+      ? Compiler::kPortable
+      : Compiler::kQuick;
   InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
 
   InstructionSetFeatures insn_features;
@@ -99,7 +99,7 @@
   compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                             verification_results_.get(),
                                             method_inliner_map_.get(),
-                                            compiler_backend, insn_set,
+                                            compiler_kind, insn_set,
                                             insn_features, false, NULL, 2, true, true,
                                             timer_.get()));
   jobject class_loader = NULL;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 190c925..8c6a8cb 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -28,19 +28,25 @@
   for (int i = 0; i < count; i++) {
     HLocal* local = new (arena_) HLocal(i);
     entry_block_->AddInstruction(local);
-    locals_.Put(0, local);
+    locals_.Put(i, local);
   }
 }
 
 static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
-  if (code_item.tries_size_ > 0) return false;
-  if (code_item.outs_size_ > 0) return false;
-  if (code_item.ins_size_ > 0) return false;
+  if (code_item.tries_size_ > 0) {
+    return false;
+  } else if (code_item.outs_size_ > 0) {
+    return false;
+  } else if (code_item.ins_size_ > 0) {
+    return false;
+  }
   return true;
 }
 
 HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
-  if (!CanHandleCodeItem(code_item)) return nullptr;
+  if (!CanHandleCodeItem(code_item)) {
+    return nullptr;
+  }
 
   const uint16_t* code_ptr = code_item.insns_;
   const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
@@ -78,7 +84,9 @@
 
 void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
   HBasicBlock* block = FindBlockStartingAt(index);
-  if (block == nullptr) return;
+  if (block == nullptr) {
+    return;
+  }
 
   if (current_block_ != nullptr) {
     // Branching instructions clear current_block, so we know
@@ -131,7 +139,9 @@
 }
 
 bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
-  if (current_block_ == nullptr) return true;  // Dead code
+  if (current_block_ == nullptr) {
+    return true;  // Dead code
+  }
 
   switch (instruction.Opcode()) {
     case Instruction::CONST_4: {
@@ -140,11 +150,14 @@
       UpdateLocal(register_index, constant);
       break;
     }
-    case Instruction::RETURN_VOID:
+
+    case Instruction::RETURN_VOID: {
       current_block_->AddInstruction(new (arena_) HReturnVoid());
       current_block_->AddSuccessor(exit_block_);
       current_block_ = nullptr;
       break;
+    }
+
     case Instruction::IF_EQ: {
       HInstruction* first = LoadLocal(instruction.VRegA());
       HInstruction* second = LoadLocal(instruction.VRegB());
@@ -159,6 +172,7 @@
       current_block_ = nullptr;
       break;
     }
+
     case Instruction::GOTO:
     case Instruction::GOTO_16:
     case Instruction::GOTO_32: {
@@ -169,8 +183,18 @@
       current_block_ = nullptr;
       break;
     }
+
+    case Instruction::RETURN: {
+      HInstruction* value = LoadLocal(instruction.VRegA());
+      current_block_->AddInstruction(new (arena_) HReturn(value));
+      current_block_->AddSuccessor(exit_block_);
+      current_block_ = nullptr;
+      break;
+    }
+
     case Instruction::NOP:
       break;
+
     default:
       return false;
   }
@@ -178,15 +202,27 @@
 }
 
 HIntConstant* HGraphBuilder::GetConstant0() {
-  if (constant0_ != nullptr) return constant0_;
-  HIntConstant* constant = new(arena_) HIntConstant(0);
-  entry_block_->AddInstruction(constant);
-  return constant;
+  if (constant0_ != nullptr) {
+    return constant0_;
+  }
+  constant0_ = new(arena_) HIntConstant(0);
+  entry_block_->AddInstruction(constant0_);
+  return constant0_;
+}
+
+HIntConstant* HGraphBuilder::GetConstant1() {
+  if (constant1_ != nullptr) {
+    return constant1_;
+  }
+  constant1_ = new(arena_) HIntConstant(1);
+  entry_block_->AddInstruction(constant1_);
+  return constant1_;
 }
 
 HIntConstant* HGraphBuilder::GetConstant(int constant) {
   switch (constant) {
     case 0: return GetConstant0();
+    case 1: return GetConstant1();
     default: {
       HIntConstant* instruction = new (arena_) HIntConstant(constant);
       entry_block_->AddInstruction(instruction);
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 399dd63..fff83a1 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -41,7 +41,8 @@
         exit_block_(nullptr),
         current_block_(nullptr),
         graph_(nullptr),
-        constant0_(nullptr) { }
+        constant0_(nullptr),
+        constant1_(nullptr) { }
 
   HGraph* BuildGraph(const DexFile::CodeItem& code);
 
@@ -58,6 +59,7 @@
   HBasicBlock* FindBlockStartingAt(int32_t index) const;
 
   HIntConstant* GetConstant0();
+  HIntConstant* GetConstant1();
   HIntConstant* GetConstant(int constant);
   void InitializeLocals(int count);
   HLocal* GetLocalAt(int register_index) const;
@@ -79,6 +81,7 @@
   HGraph* graph_;
 
   HIntConstant* constant0_;
+  HIntConstant* constant1_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 01fc23b..56342aa 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -26,9 +26,11 @@
 namespace art {
 
 void CodeGenerator::Compile(CodeAllocator* allocator) {
-  GenerateFrameEntry();
   const GrowableArray<HBasicBlock*>* blocks = graph()->blocks();
-  for (size_t i = 0; i < blocks->Size(); i++) {
+  DCHECK(blocks->Get(0) == graph()->entry_block());
+  DCHECK(GoesToNextBlock(graph()->entry_block(), blocks->Get(1)));
+  CompileEntryBlock();
+  for (size_t i = 1; i < blocks->Size(); i++) {
     CompileBlock(blocks->Get(i));
   }
   size_t code_size = assembler_->CodeSize();
@@ -37,17 +39,54 @@
   assembler_->FinalizeInstructions(code);
 }
 
+void CodeGenerator::CompileEntryBlock() {
+  HGraphVisitor* location_builder = GetLocationBuilder();
+  // The entry block contains all locals for this method. By visiting the entry block,
+  // we're computing the required frame size.
+  for (HInstructionIterator it(graph()->entry_block()); !it.Done(); it.Advance()) {
+    HInstruction* current = it.Current();
+    // Instructions in the entry block should not generate code.
+    if (kIsDebugBuild) {
+      current->Accept(location_builder);
+      DCHECK(current->locations() == nullptr);
+    }
+    current->Accept(this);
+  }
+  GenerateFrameEntry();
+}
+
 void CodeGenerator::CompileBlock(HBasicBlock* block) {
   Bind(GetLabelOf(block));
+  HGraphVisitor* location_builder = GetLocationBuilder();
   for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
-    it.Current()->Accept(this);
+    // For each instruction, we emulate a stack-based machine, where the inputs are popped from
+    // the runtime stack, and the result is pushed on the stack. We currently can do this because
+    // we do not perform any code motion, and the Dex format does not reference individual
+    // instructions but uses registers instead (our equivalent of HLocal).
+    HInstruction* current = it.Current();
+    current->Accept(location_builder);
+    InitLocations(current);
+    current->Accept(this);
+    if (current->locations() != nullptr && current->locations()->Out().IsValid()) {
+      Push(current, current->locations()->Out());
+    }
   }
 }
 
-bool CodeGenerator::GoesToNextBlock(HGoto* goto_instruction) const {
-  HBasicBlock* successor = goto_instruction->GetSuccessor();
+void CodeGenerator::InitLocations(HInstruction* instruction) {
+  if (instruction->locations() == nullptr) return;
+  for (int i = 0; i < instruction->InputCount(); i++) {
+    Location location = instruction->locations()->InAt(i);
+    if (location.IsValid()) {
+      // Move the input to the desired location.
+      Move(instruction->InputAt(i), location);
+    }
+  }
+}
+
+bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const {
   // We currently iterate over the block in insertion order.
-  return goto_instruction->block()->block_id() + 1 == successor->block_id();
+  return current->block_id() + 1 == next->block_id();
 }
 
 Label* CodeGenerator::GetLabelOf(HBasicBlock* block) const {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 2a5ae7d..c406378 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 
+#include "globals.h"
 #include "instruction_set.h"
 #include "memory_region.h"
 #include "nodes.h"
@@ -35,12 +36,82 @@
   DISALLOW_COPY_AND_ASSIGN(CodeAllocator);
 };
 
+/**
+ * A Location is an abstraction over the potential location
+ * of an instruction. It could be in register or stack.
+ */
+class Location : public ValueObject {
+ public:
+  template<typename T>
+  T reg() const { return static_cast<T>(reg_); }
+
+  Location() : reg_(kInvalid) { }
+  explicit Location(uword reg) : reg_(reg) { }
+
+  static Location RegisterLocation(uword reg) {
+    return Location(reg);
+  }
+
+  bool IsValid() const { return reg_ != kInvalid; }
+
+  Location(const Location& other) : reg_(other.reg_) { }
+
+  Location& operator=(const Location& other) {
+    reg_ = other.reg_;
+    return *this;
+  }
+
+ private:
+  // The target register for that location.
+  // TODO: Support stack location.
+  uword reg_;
+  static const uword kInvalid = -1;
+};
+
+/**
+ * The code generator computes LocationSummary for each instruction so that
+ * the instruction itself knows what code to generate: where to find the inputs
+ * and where to place the result.
+ *
+ * The intent is to have the code for generating the instruction independent of
+ * register allocation. A register allocator just has to provide a LocationSummary.
+ */
+class LocationSummary : public ArenaObject {
+ public:
+  explicit LocationSummary(HInstruction* instruction)
+      : inputs(instruction->block()->graph()->arena(), instruction->InputCount()) {
+    inputs.SetSize(instruction->InputCount());
+    for (int i = 0; i < instruction->InputCount(); i++) {
+      inputs.Put(i, Location());
+    }
+  }
+
+  void SetInAt(uint32_t at, Location location) {
+    inputs.Put(at, location);
+  }
+
+  Location InAt(uint32_t at) const {
+    return inputs.Get(at);
+  }
+
+  void SetOut(Location location) {
+    output = Location(location);
+  }
+
+  Location Out() const { return output; }
+
+ private:
+  GrowableArray<Location> inputs;
+  Location output;
+
+  DISALLOW_COPY_AND_ASSIGN(LocationSummary);
+};
+
 class CodeGenerator : public HGraphVisitor {
  public:
   // Compiles the graph to executable instructions. Returns whether the compilation
   // succeeded.
-  static bool CompileGraph(
-      HGraph* graph, InstructionSet instruction_set, CodeAllocator* allocator);
+  static bool CompileGraph(HGraph* graph, InstructionSet instruction_set, CodeAllocator* allocator);
 
   Assembler* assembler() const { return assembler_; }
 
@@ -54,20 +125,31 @@
 
  protected:
   CodeGenerator(Assembler* assembler, HGraph* graph)
-      : HGraphVisitor(graph), assembler_(assembler), block_labels_(graph->arena(), 0) {
+      : HGraphVisitor(graph),
+        frame_size_(0),
+        assembler_(assembler),
+        block_labels_(graph->arena(), 0) {
     block_labels_.SetSize(graph->blocks()->Size());
   }
 
   Label* GetLabelOf(HBasicBlock* block) const;
-  bool GoesToNextBlock(HGoto* got) const;
+  bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
 
- private:
+  // Frame size required for this method.
+  uint32_t frame_size_;
+
   virtual void GenerateFrameEntry() = 0;
   virtual void GenerateFrameExit() = 0;
   virtual void Bind(Label* label) = 0;
+  virtual void Move(HInstruction* instruction, Location location) = 0;
+  virtual void Push(HInstruction* instruction, Location location) = 0;
+  virtual HGraphVisitor* GetLocationBuilder() = 0;
 
+ private:
+  void InitLocations(HInstruction* instruction);
   void Compile(CodeAllocator* allocator);
   void CompileBlock(HBasicBlock* block);
+  void CompileEntryBlock();
 
   Assembler* const assembler_;
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 356e909..62bf7ba 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -24,28 +24,52 @@
 namespace arm {
 
 void CodeGeneratorARM::GenerateFrameEntry() {
-  RegList registers = (1 << LR) | (1 << FP);
-  __ PushList(registers);
+  __ PushList((1 << FP) | (1 << LR));
+  __ mov(FP, ShifterOperand(SP));
+  if (frame_size_ != 0) {
+    __ AddConstant(SP, -frame_size_);
+  }
 }
 
 void CodeGeneratorARM::GenerateFrameExit() {
-  RegList registers = (1 << PC) | (1 << FP);
-  __ PopList(registers);
+  __ mov(SP, ShifterOperand(FP));
+  __ PopList((1 << FP) | (1 << PC));
 }
 
 void CodeGeneratorARM::Bind(Label* label) {
   __ Bind(label);
 }
 
+void CodeGeneratorARM::Push(HInstruction* instruction, Location location) {
+  __ Push(location.reg<Register>());
+}
+
+void CodeGeneratorARM::Move(HInstruction* instruction, Location location) {
+  HIntConstant* constant = instruction->AsIntConstant();
+  if (constant != nullptr) {
+    __ LoadImmediate(location.reg<Register>(), constant->value());
+  } else {
+    __ Pop(location.reg<Register>());
+  }
+}
+
+void LocationsBuilderARM::VisitGoto(HGoto* got) {
+  got->set_locations(nullptr);
+}
+
 void CodeGeneratorARM::VisitGoto(HGoto* got) {
   HBasicBlock* successor = got->GetSuccessor();
   if (graph()->exit_block() == successor) {
     GenerateFrameExit();
-  } else if (!GoesToNextBlock(got)) {
+  } else if (!GoesToNextBlock(got->block(), successor)) {
     __ b(GetLabelOf(successor));
   }
 }
 
+void LocationsBuilderARM::VisitExit(HExit* exit) {
+  exit->set_locations(nullptr);
+}
+
 void CodeGeneratorARM::VisitExit(HExit* exit) {
   if (kIsDebugBuild) {
     __ Comment("Unreachable");
@@ -53,33 +77,101 @@
   }
 }
 
+void LocationsBuilderARM::VisitIf(HIf* if_instr) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(if_instr);
+  locations->SetInAt(0, Location(R0));
+  if_instr->set_locations(locations);
+}
+
 void CodeGeneratorARM::VisitIf(HIf* if_instr) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  // TODO: Generate the input as a condition, instead of materializing in a register.
+  __ cmp(if_instr->locations()->InAt(0).reg<Register>(), ShifterOperand(0));
+  __ b(GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
+  if (!GoesToNextBlock(if_instr->block(), if_instr->IfTrueSuccessor())) {
+    __ b(GetLabelOf(if_instr->IfTrueSuccessor()));
+  }
+}
+
+void LocationsBuilderARM::VisitEqual(HEqual* equal) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(equal);
+  locations->SetInAt(0, Location(R0));
+  locations->SetInAt(1, Location(R1));
+  locations->SetOut(Location(R0));
+  equal->set_locations(locations);
 }
 
 void CodeGeneratorARM::VisitEqual(HEqual* equal) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  LocationSummary* locations = equal->locations();
+  __ teq(locations->InAt(0).reg<Register>(),
+         ShifterOperand(locations->InAt(1).reg<Register>()));
+  __ mov(locations->Out().reg<Register>(), ShifterOperand(1), EQ);
+  __ mov(locations->Out().reg<Register>(), ShifterOperand(0), NE);
+}
+
+void LocationsBuilderARM::VisitLocal(HLocal* local) {
+  local->set_locations(nullptr);
 }
 
 void CodeGeneratorARM::VisitLocal(HLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  DCHECK_EQ(local->block(), graph()->entry_block());
+  frame_size_ += kWordSize;
 }
 
-void CodeGeneratorARM::VisitLoadLocal(HLoadLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(load);
+  locations->SetOut(Location(R0));
+  load->set_locations(locations);
 }
 
-void CodeGeneratorARM::VisitStoreLocal(HStoreLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+static int32_t GetStackSlot(HLocal* local) {
+  // We are currently using FP to access locals, so the offset must be negative.
+  return (local->reg_number() + 1) * -kWordSize;
+}
+
+void CodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
+  LocationSummary* locations = load->locations();
+  __ LoadFromOffset(kLoadWord, locations->Out().reg<Register>(),
+                    FP, GetStackSlot(load->GetLocal()));
+}
+
+void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(store);
+  locations->SetInAt(1, Location(R0));
+  store->set_locations(locations);
+}
+
+void CodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
+  LocationSummary* locations = store->locations();
+  __ StoreToOffset(kStoreWord, locations->InAt(1).reg<Register>(),
+                   FP, GetStackSlot(store->GetLocal()));
+}
+
+void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
+  constant->set_locations(nullptr);
 }
 
 void CodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
+  ret->set_locations(nullptr);
 }
 
 void CodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
   GenerateFrameExit();
 }
 
+void LocationsBuilderARM::VisitReturn(HReturn* ret) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(ret);
+  locations->SetInAt(0, Location(R0));
+  ret->set_locations(locations);
+}
+
+void CodeGeneratorARM::VisitReturn(HReturn* ret) {
+  DCHECK_EQ(ret->locations()->InAt(0).reg<Register>(), R0);
+  GenerateFrameExit();
+}
+
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 27a83b8..33d8e62 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -27,10 +27,25 @@
 
 namespace arm {
 
+class LocationsBuilderARM : public HGraphVisitor {
+ public:
+  explicit LocationsBuilderARM(HGraph* graph) : HGraphVisitor(graph) { }
+
+#define DECLARE_VISIT_INSTRUCTION(name)     \
+  virtual void Visit##name(H##name* instr);
+
+  FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM);
+};
+
 class CodeGeneratorARM : public CodeGenerator {
  public:
   CodeGeneratorARM(Assembler* assembler, HGraph* graph)
-      : CodeGenerator(assembler, graph) { }
+      : CodeGenerator(assembler, graph), location_builder_(graph) { }
 
   // Visit functions for instruction classes.
 #define DECLARE_VISIT_INSTRUCTION(name)     \
@@ -40,10 +55,19 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+ protected:
+  virtual void GenerateFrameEntry() OVERRIDE;
+  virtual void GenerateFrameExit() OVERRIDE;
+  virtual void Bind(Label* label) OVERRIDE;
+  virtual void Move(HInstruction* instruction, Location location) OVERRIDE;
+  virtual void Push(HInstruction* instruction, Location location) OVERRIDE;
+
+  virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+    return &location_builder_;
+  }
+
  private:
-  virtual void GenerateFrameEntry();
-  virtual void GenerateFrameExit();
-  virtual void Bind(Label* label);
+  LocationsBuilderARM location_builder_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
 };
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index ab34599..81ada4d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -26,6 +26,10 @@
 void CodeGeneratorX86::GenerateFrameEntry() {
   __ pushl(EBP);
   __ movl(EBP, ESP);
+
+  if (frame_size_ != 0) {
+    __ subl(ESP, Immediate(frame_size_));
+  }
 }
 
 void CodeGeneratorX86::GenerateFrameExit() {
@@ -37,15 +41,36 @@
   __ Bind(label);
 }
 
+void CodeGeneratorX86::Push(HInstruction* instruction, Location location) {
+  __ pushl(location.reg<Register>());
+}
+
+void CodeGeneratorX86::Move(HInstruction* instruction, Location location) {
+  HIntConstant* constant = instruction->AsIntConstant();
+  if (constant != nullptr) {
+    __ movl(location.reg<Register>(), Immediate(constant->value()));
+  } else {
+    __ popl(location.reg<Register>());
+  }
+}
+
+void LocationsBuilderX86::VisitGoto(HGoto* got) {
+  got->set_locations(nullptr);
+}
+
 void CodeGeneratorX86::VisitGoto(HGoto* got) {
   HBasicBlock* successor = got->GetSuccessor();
   if (graph()->exit_block() == successor) {
     GenerateFrameExit();
-  } else if (!GoesToNextBlock(got)) {
+  } else if (!GoesToNextBlock(got->block(), successor)) {
     __ jmp(GetLabelOf(successor));
   }
 }
 
+void LocationsBuilderX86::VisitExit(HExit* exit) {
+  exit->set_locations(nullptr);
+}
+
 void CodeGeneratorX86::VisitExit(HExit* exit) {
   if (kIsDebugBuild) {
     __ Comment("Unreachable");
@@ -53,28 +78,81 @@
   }
 }
 
+void LocationsBuilderX86::VisitIf(HIf* if_instr) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(if_instr);
+  locations->SetInAt(0, Location(EAX));
+  if_instr->set_locations(locations);
+}
+
 void CodeGeneratorX86::VisitIf(HIf* if_instr) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  // TODO: Generate the input as a condition, instead of materializing in a register.
+  __ cmpl(if_instr->locations()->InAt(0).reg<Register>(), Immediate(0));
+  __ j(kEqual, GetLabelOf(if_instr->IfFalseSuccessor()));
+  if (!GoesToNextBlock(if_instr->block(), if_instr->IfTrueSuccessor())) {
+    __ jmp(GetLabelOf(if_instr->IfTrueSuccessor()));
+  }
+}
+
+void LocationsBuilderX86::VisitLocal(HLocal* local) {
+  local->set_locations(nullptr);
 }
 
 void CodeGeneratorX86::VisitLocal(HLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  DCHECK_EQ(local->block(), graph()->entry_block());
+  frame_size_ += kWordSize;
 }
 
-void CodeGeneratorX86::VisitLoadLocal(HLoadLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(local);
+  locations->SetOut(Location(EAX));
+  local->set_locations(locations);
 }
 
-void CodeGeneratorX86::VisitStoreLocal(HStoreLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+static int32_t GetStackSlot(HLocal* local) {
+  // We are currently using EBP to access locals, so the offset must be negative.
+  return (local->reg_number() + 1) * -kWordSize;
+}
+
+void CodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
+  __ movl(load->locations()->Out().reg<Register>(),
+          Address(EBP, GetStackSlot(load->GetLocal())));
+}
+
+void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* local) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(local);
+  locations->SetInAt(1, Location(EAX));
+  local->set_locations(locations);
+}
+
+void CodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
+  __ movl(Address(EBP, GetStackSlot(store->GetLocal())),
+          store->locations()->InAt(1).reg<Register>());
+}
+
+void LocationsBuilderX86::VisitEqual(HEqual* equal) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(equal);
+  locations->SetInAt(0, Location(EAX));
+  locations->SetInAt(1, Location(ECX));
+  locations->SetOut(Location(EAX));
+  equal->set_locations(locations);
 }
 
 void CodeGeneratorX86::VisitEqual(HEqual* equal) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  __ cmpl(equal->locations()->InAt(0).reg<Register>(),
+          equal->locations()->InAt(1).reg<Register>());
+  __ setb(kEqual, equal->locations()->Out().reg<Register>());
+}
+
+void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
+  constant->set_locations(nullptr);
 }
 
 void CodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  // Will be generated at use site.
+}
+
+void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
+  ret->set_locations(nullptr);
 }
 
 void CodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
@@ -82,5 +160,17 @@
   __ ret();
 }
 
+void LocationsBuilderX86::VisitReturn(HReturn* ret) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(ret);
+  locations->SetInAt(0, Location(EAX));
+  ret->set_locations(locations);
+}
+
+void CodeGeneratorX86::VisitReturn(HReturn* ret) {
+  DCHECK_EQ(ret->locations()->InAt(0).reg<Register>(), EAX);
+  GenerateFrameExit();
+  __ ret();
+}
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 7dae2ab..dd146b8 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -27,12 +27,10 @@
 
 namespace x86 {
 
-class CodeGeneratorX86 : public CodeGenerator {
+class LocationsBuilderX86 : public HGraphVisitor {
  public:
-  CodeGeneratorX86(Assembler* assembler, HGraph* graph)
-      : CodeGenerator(assembler, graph) { }
+  explicit LocationsBuilderX86(HGraph* graph) : HGraphVisitor(graph) { }
 
-  // Visit functions for instruction classes.
 #define DECLARE_VISIT_INSTRUCTION(name)     \
   virtual void Visit##name(H##name* instr);
 
@@ -41,9 +39,34 @@
 #undef DECLARE_VISIT_INSTRUCTION
 
  private:
-  virtual void GenerateFrameEntry();
-  virtual void GenerateFrameExit();
-  virtual void Bind(Label* label);
+  DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86);
+};
+
+class CodeGeneratorX86 : public CodeGenerator {
+ public:
+  CodeGeneratorX86(Assembler* assembler, HGraph* graph)
+      : CodeGenerator(assembler, graph), location_builder_(graph) { }
+
+#define DECLARE_VISIT_INSTRUCTION(name)     \
+  virtual void Visit##name(H##name* instr);
+
+  FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+#undef DECLARE_VISIT_INSTRUCTION
+
+ protected:
+  virtual void GenerateFrameEntry() OVERRIDE;
+  virtual void GenerateFrameExit() OVERRIDE;
+  virtual void Bind(Label* label) OVERRIDE;
+  virtual void Move(HInstruction* instruction, Location location) OVERRIDE;
+  virtual void Push(HInstruction* instruction, Location location) OVERRIDE;
+
+  virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+    return &location_builder_;
+  }
+
+ private:
+  LocationsBuilderX86 location_builder_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
 };
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 6d4588d..5020dd0 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -45,7 +45,7 @@
   DISALLOW_COPY_AND_ASSIGN(ExecutableMemoryAllocator);
 };
 
-static void TestCode(const uint16_t* data) {
+static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) {
   ArenaPool pool;
   ArenaAllocator arena(&pool);
   HGraphBuilder builder(&arena);
@@ -54,13 +54,19 @@
   ASSERT_NE(graph, nullptr);
   ExecutableMemoryAllocator allocator;
   CHECK(CodeGenerator::CompileGraph(graph, kX86, &allocator));
-  typedef void (*fptr)();
+  typedef int32_t (*fptr)();
 #if defined(__i386__)
-  reinterpret_cast<fptr>(allocator.memory())();
+  int32_t result = reinterpret_cast<fptr>(allocator.memory())();
+  if (has_result) {
+    CHECK_EQ(result, expected);
+  }
 #endif
   CHECK(CodeGenerator::CompileGraph(graph, kArm, &allocator));
 #if defined(__arm__)
-  reinterpret_cast<fptr>(allocator.memory())();
+  int32_t result = reinterpret_cast<fptr>(allocator.memory())();
+  if (has_result) {
+    CHECK_EQ(result, expected);
+  }
 #endif
 }
 
@@ -69,7 +75,7 @@
   TestCode(data);
 }
 
-TEST(PrettyPrinterTest, CFG1) {
+TEST(CodegenTest, CFG1) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,
     Instruction::RETURN_VOID);
@@ -77,7 +83,7 @@
   TestCode(data);
 }
 
-TEST(PrettyPrinterTest, CFG2) {
+TEST(CodegenTest, CFG2) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,
     Instruction::GOTO | 0x100,
@@ -86,7 +92,7 @@
   TestCode(data);
 }
 
-TEST(PrettyPrinterTest, CFG3) {
+TEST(CodegenTest, CFG3) {
   const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x200,
     Instruction::RETURN_VOID,
@@ -109,7 +115,7 @@
   TestCode(data3);
 }
 
-TEST(PrettyPrinterTest, CFG4) {
+TEST(CodegenTest, CFG4) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::RETURN_VOID,
     Instruction::GOTO | 0x100,
@@ -118,4 +124,70 @@
   TestCode(data);
 }
 
+TEST(CodegenTest, CFG5) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0x100,
+    Instruction::RETURN_VOID);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, IntConstant) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::RETURN_VOID);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, Return1) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::RETURN | 0);
+
+  TestCode(data, true, 0);
+}
+
+TEST(CodegenTest, Return2) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::CONST_4 | 0 | 1 << 8,
+    Instruction::RETURN | 1 << 8);
+
+  TestCode(data, true, 0);
+}
+
+TEST(CodegenTest, Return3) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::CONST_4 | 1 << 8 | 1 << 12,
+    Instruction::RETURN | 1 << 8);
+
+  TestCode(data, true, 1);
+}
+
+TEST(CodegenTest, ReturnIf1) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::CONST_4 | 1 << 8 | 1 << 12,
+    Instruction::IF_EQ, 3,
+    Instruction::RETURN | 0 << 8,
+    Instruction::RETURN | 1 << 8);
+
+  TestCode(data, true, 1);
+}
+
+TEST(CodegenTest, ReturnIf2) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::CONST_4 | 1 << 8 | 1 << 12,
+    Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
+    Instruction::RETURN | 0 << 8,
+    Instruction::RETURN | 1 << 8);
+
+  TestCode(data, true, 0);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 16dfb94..a6f3f5a 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -121,6 +121,7 @@
 }
 
 void HBasicBlock::AddInstruction(HInstruction* instruction) {
+  DCHECK(instruction->block() == nullptr);
   instruction->set_block(this);
   instruction->set_id(graph()->GetNextInstructionId());
   if (first_instruction_ == nullptr) {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index bb08bd0..9418599 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -27,6 +27,7 @@
 class HInstruction;
 class HIntConstant;
 class HGraphVisitor;
+class LocationSummary;
 
 static const int kDefaultNumberOfBlocks = 8;
 static const int kDefaultNumberOfSuccessors = 2;
@@ -186,12 +187,18 @@
   M(IntConstant)                                           \
   M(LoadLocal)                                             \
   M(Local)                                                 \
+  M(Return)                                                \
   M(ReturnVoid)                                            \
   M(StoreLocal)                                            \
 
+#define FORWARD_DECLARATION(type) class H##type;
+FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
+#undef FORWARD_DECLARATION
+
 #define DECLARE_INSTRUCTION(type)                          \
   virtual void Accept(HGraphVisitor* visitor);             \
   virtual const char* DebugName() const { return #type; }  \
+  virtual H##type* As##type() { return this; }             \
 
 class HUseListNode : public ArenaObject {
  public:
@@ -210,7 +217,14 @@
 
 class HInstruction : public ArenaObject {
  public:
-  HInstruction() : previous_(nullptr), next_(nullptr), block_(nullptr), id_(-1), uses_(nullptr) { }
+  HInstruction()
+      : previous_(nullptr),
+        next_(nullptr),
+        block_(nullptr),
+        id_(-1),
+        uses_(nullptr),
+        locations_(nullptr) { }
+
   virtual ~HInstruction() { }
 
   HInstruction* next() const { return next_; }
@@ -236,6 +250,15 @@
   int id() const { return id_; }
   void set_id(int id) { id_ = id; }
 
+  LocationSummary* locations() const { return locations_; }
+  void set_locations(LocationSummary* locations) { locations_ = locations; }
+
+#define INSTRUCTION_TYPE_CHECK(type)                                           \
+  virtual H##type* As##type() { return nullptr; }
+
+  FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
+#undef INSTRUCTION_TYPE_CHECK
+
  private:
   HInstruction* previous_;
   HInstruction* next_;
@@ -248,6 +271,9 @@
 
   HUseListNode* uses_;
 
+  // Set by the code generator.
+  LocationSummary* locations_;
+
   friend class HBasicBlock;
 
   DISALLOW_COPY_AND_ASSIGN(HInstruction);
@@ -386,6 +412,20 @@
   DISALLOW_COPY_AND_ASSIGN(HReturnVoid);
 };
 
+// Represents dex's RETURN opcodes. A HReturn is a control flow
+// instruction that branches to the exit block.
+class HReturn : public HTemplateInstruction<1> {
+ public:
+  explicit HReturn(HInstruction* value) {
+    SetRawInputAt(0, value);
+  }
+
+  DECLARE_INSTRUCTION(Return)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HReturn);
+};
+
 // The exit instruction is the only instruction of the exit block.
 // Instructions aborting the method (HTrow and HReturn) must branch to the
 // exit block.
@@ -422,6 +462,14 @@
     SetRawInputAt(0, input);
   }
 
+  HBasicBlock* IfTrueSuccessor() const {
+    return block()->successors()->Get(0);
+  }
+
+  HBasicBlock* IfFalseSuccessor() const {
+    return block()->successors()->Get(1);
+  }
+
   DECLARE_INSTRUCTION(If)
 
  private:
@@ -449,9 +497,11 @@
 
   DECLARE_INSTRUCTION(Local)
 
+  uint16_t reg_number() const { return reg_number_; }
+
  private:
-  // The register number in Dex.
-  uint16_t reg_number_;
+  // The Dex register number.
+  const uint16_t reg_number_;
 
   DISALLOW_COPY_AND_ASSIGN(HLocal);
 };
@@ -463,6 +513,8 @@
     SetRawInputAt(0, local);
   }
 
+  HLocal* GetLocal() const { return reinterpret_cast<HLocal*>(InputAt(0)); }
+
   DECLARE_INSTRUCTION(LoadLocal)
 
  private:
@@ -478,6 +530,8 @@
     SetRawInputAt(1, value);
   }
 
+  HLocal* GetLocal() const { return reinterpret_cast<HLocal*>(InputAt(0)); }
+
   DECLARE_INSTRUCTION(StoreLocal)
 
  private:
@@ -490,6 +544,8 @@
  public:
   explicit HIntConstant(int32_t value) : value_(value) { }
 
+  int32_t value() const { return value_; }
+
   DECLARE_INSTRUCTION(IntConstant)
 
  private:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
new file mode 100644
index 0000000..73323a4
--- /dev/null
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#include "compilers.h"
+
+namespace art {
+
+CompiledMethod* OptimizingCompiler::TryCompile(CompilerDriver& driver,
+                                               const DexFile::CodeItem* code_item,
+                                               uint32_t access_flags,
+                                               InvokeType invoke_type,
+                                               uint16_t class_def_idx,
+                                               uint32_t method_idx,
+                                               jobject class_loader,
+                                               const DexFile& dex_file) const {
+  return nullptr;
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index bf13a41..67c4850 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -26,4 +26,7 @@
 #define ONE_REGISTER_CODE_ITEM(...)                                        \
     { 1, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
 
+#define TWO_REGISTERS_CODE_ITEM(...)                                       \
+    { 2, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
+
 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 327d3fb..908d995 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -30,9 +30,10 @@
 #include "base/timing_logger.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
-#include "compiler_backend.h"
+#include "compiler.h"
 #include "compiler_callbacks.h"
 #include "dex_file-inl.h"
+#include "dex/pass_driver.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_callbacks_impl.h"
 #include "driver/compiler_driver.h"
@@ -147,7 +148,7 @@
   UsageError("      Example: --instruction-set-features=div");
   UsageError("      Default: default");
   UsageError("");
-  UsageError("  --compiler-backend=(Quick|QuickGBC|Portable): select compiler backend");
+  UsageError("  --compiler-backend=(Quick|Optimizing|Portable): select compiler backend");
   UsageError("      set.");
   UsageError("      Example: --compiler-backend=Portable");
   UsageError("      Default: Quick");
@@ -203,6 +204,11 @@
     UsageError("");
     UsageError("  --profile-file=<filename>: specify profiler output file to use for compilation.");
   UsageError("");
+  UsageError("  --print-pass-names: print a list of pass names");
+  UsageError("");
+  UsageError("  --disable-passes=<pass-names>:  disable one or more passes separated by comma.");
+  UsageError("      Example: --disable-passes=UseCount,BBOptimizations");
+  UsageError("");
   std::cerr << "See log for usage error information\n";
   exit(EXIT_FAILURE);
 }
@@ -212,7 +218,7 @@
   static bool Create(Dex2Oat** p_dex2oat,
                      const Runtime::Options& runtime_options,
                      const CompilerOptions& compiler_options,
-                     CompilerBackend::Kind compiler_backend,
+                     Compiler::Kind compiler_kind,
                      InstructionSet instruction_set,
                      InstructionSetFeatures instruction_set_features,
                      VerificationResults* verification_results,
@@ -222,7 +228,7 @@
     CHECK(verification_results != nullptr);
     CHECK(method_inliner_map != nullptr);
     UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
-                                           compiler_backend,
+                                           compiler_kind,
                                            instruction_set,
                                            instruction_set_features,
                                            verification_results,
@@ -335,7 +341,7 @@
     UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
                                                         verification_results_,
                                                         method_inliner_map_,
-                                                        compiler_backend_,
+                                                        compiler_kind_,
                                                         instruction_set_,
                                                         instruction_set_features_,
                                                         image,
@@ -346,7 +352,7 @@
                                                         &compiler_phases_timings,
                                                         profile_file));
 
-    driver->GetCompilerBackend()->SetBitcodeFileName(*driver.get(), bitcode_filename);
+    driver->GetCompiler()->SetBitcodeFileName(*driver.get(), bitcode_filename);
 
     driver->CompileAll(class_loader, dex_files, &timings);
 
@@ -410,14 +416,14 @@
 
  private:
   explicit Dex2Oat(const CompilerOptions* compiler_options,
-                   CompilerBackend::Kind compiler_backend,
+                   Compiler::Kind compiler_kind,
                    InstructionSet instruction_set,
                    InstructionSetFeatures instruction_set_features,
                    VerificationResults* verification_results,
                    DexFileToMethodInlinerMap* method_inliner_map,
                    size_t thread_count)
       : compiler_options_(compiler_options),
-        compiler_backend_(compiler_backend),
+        compiler_kind_(compiler_kind),
         instruction_set_(instruction_set),
         instruction_set_features_(instruction_set_features),
         verification_results_(verification_results),
@@ -482,7 +488,7 @@
   }
 
   const CompilerOptions* const compiler_options_;
-  const CompilerBackend::Kind compiler_backend_;
+  const Compiler::Kind compiler_kind_;
 
   const InstructionSet instruction_set_;
   const InstructionSetFeatures instruction_set_features_;
@@ -722,9 +728,9 @@
   std::string android_root;
   std::vector<const char*> runtime_args;
   int thread_count = sysconf(_SC_NPROCESSORS_CONF);
-  CompilerBackend::Kind compiler_backend = kUsePortableCompiler
-      ? CompilerBackend::kPortable
-      : CompilerBackend::kQuick;
+  Compiler::Kind compiler_kind = kUsePortableCompiler
+      ? Compiler::kPortable
+      : Compiler::kQuick;
   const char* compiler_filter_string = NULL;
   int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
   int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
@@ -844,9 +850,11 @@
     } else if (option.starts_with("--compiler-backend=")) {
       StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
       if (backend_str == "Quick") {
-        compiler_backend = CompilerBackend::kQuick;
+        compiler_kind = Compiler::kQuick;
+      } else if (backend_str == "Optimizing") {
+        compiler_kind = Compiler::kOptimizing;
       } else if (backend_str == "Portable") {
-        compiler_backend = CompilerBackend::kPortable;
+        compiler_kind = Compiler::kPortable;
       }
     } else if (option.starts_with("--compiler-filter=")) {
       compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
@@ -912,6 +920,11 @@
     } else if (option == "--no-profile-file") {
       LOG(INFO) << "dex2oat: no profile file supplied (explictly)";
       // No profile
+    } else if (option == "--print-pass-names") {
+      PassDriver::PrintPassNames();
+    } else if (option.starts_with("--disable-passes=")) {
+      std::string disable_passes = option.substr(strlen("--disable-passes=")).data();
+      PassDriver::CreateDefaultPassList(disable_passes);
     } else {
       Usage("Unknown argument %s", option.data());
     }
@@ -1101,7 +1114,7 @@
   if (!Dex2Oat::Create(&p_dex2oat,
                        runtime_options,
                        compiler_options,
-                       compiler_backend,
+                       compiler_kind,
                        instruction_set,
                        instruction_set_features,
                        &verification_results,
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 98bec85..10b3f1e 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -125,6 +125,7 @@
 	os_linux.cc \
 	parsed_options.cc \
 	primitive.cc \
+	quick/inline_method_analyser.cc \
 	reference_table.cc \
 	reflection.cc \
 	runtime.cc \
@@ -291,6 +292,7 @@
 	lock_word.h \
 	mirror/class.h \
 	oat.h \
+	quick/inline_method_analyser.h \
 	thread.h \
 	thread_state.h \
 	verifier/method_verifier.h
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
new file mode 100644
index 0000000..4388d31
--- /dev/null
+++ b/runtime/quick/inline_method_analyser.cc
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+#include "inline_method_analyser.h"
+#include "dex_instruction.h"
+#include "dex_instruction-inl.h"
+#include "mirror/art_field.h"
+#include "mirror/art_field-inl.h"
+#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
+#include "mirror/class.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
+#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
+
+/*
+ * NOTE: This code is part of the quick compiler. It lives in the runtime
+ * only to allow the debugger to check whether a method has been inlined.
+ */
+
+namespace art {
+
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET),
+               check_iget_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE),
+               check_iget_wide_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT),
+               check_iget_object_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BOOLEAN),
+               check_iget_boolean_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BYTE),
+               check_iget_byte_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_CHAR),
+               check_iget_char_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_SHORT),
+               check_iget_short_type);
+
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT),
+               check_iput_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_WIDE),
+               check_iput_wide_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_OBJECT),
+               check_iput_object_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BOOLEAN),
+               check_iput_boolean_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BYTE),
+               check_iput_byte_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_CHAR),
+               check_iput_char_type);
+COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_SHORT),
+               check_iput_short_type);
+
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT), check_iget_iput_variant);
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE), check_iget_iput_wide_variant);
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT), check_iget_iput_object_variant);
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN), check_iget_iput_boolean_variant);
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE), check_iget_iput_byte_variant);
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR), check_iget_iput_char_variant);
+COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), check_iget_iput_short_variant);
+
+bool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier,
+                                             InlineMethod* method) {
+  // We currently support only plain return or 2-instruction methods.
+
+  const DexFile::CodeItem* code_item = verifier->CodeItem();
+  DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
+  const Instruction* instruction = Instruction::At(code_item->insns_);
+  Instruction::Code opcode = instruction->Opcode();
+
+  switch (opcode) {
+    case Instruction::RETURN_VOID:
+      method->opcode = kInlineOpNop;
+      method->flags = kInlineSpecial;
+      method->d.data = 0u;
+      return true;
+    case Instruction::RETURN:
+    case Instruction::RETURN_OBJECT:
+    case Instruction::RETURN_WIDE:
+      return AnalyseReturnMethod(code_item, method);
+    case Instruction::CONST:
+    case Instruction::CONST_4:
+    case Instruction::CONST_16:
+    case Instruction::CONST_HIGH16:
+      // TODO: Support wide constants (RETURN_WIDE).
+      return AnalyseConstMethod(code_item, method);
+    case Instruction::IGET:
+    case Instruction::IGET_OBJECT:
+    case Instruction::IGET_BOOLEAN:
+    case Instruction::IGET_BYTE:
+    case Instruction::IGET_CHAR:
+    case Instruction::IGET_SHORT:
+    case Instruction::IGET_WIDE:
+      return AnalyseIGetMethod(verifier, method);
+    case Instruction::IPUT:
+    case Instruction::IPUT_OBJECT:
+    case Instruction::IPUT_BOOLEAN:
+    case Instruction::IPUT_BYTE:
+    case Instruction::IPUT_CHAR:
+    case Instruction::IPUT_SHORT:
+    case Instruction::IPUT_WIDE:
+      return AnalyseIPutMethod(verifier, method);
+    default:
+      return false;
+  }
+}
+
+bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
+                                               InlineMethod* result) {
+  const Instruction* return_instruction = Instruction::At(code_item->insns_);
+  Instruction::Code return_opcode = return_instruction->Opcode();
+  uint32_t reg = return_instruction->VRegA_11x();
+  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  DCHECK_GE(reg, arg_start);
+  DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg,
+      code_item->registers_size_);
+
+  result->opcode = kInlineOpReturnArg;
+  result->flags = kInlineSpecial;
+  InlineReturnArgData* data = &result->d.return_data;
+  data->arg = reg - arg_start;
+  data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u;
+  data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
+  data->reserved = 0u;
+  data->reserved2 = 0u;
+  return true;
+}
+
+bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item,
+                                              InlineMethod* result) {
+  const Instruction* instruction = Instruction::At(code_item->insns_);
+  const Instruction* return_instruction = instruction->Next();
+  Instruction::Code return_opcode = return_instruction->Opcode();
+  if (return_opcode != Instruction::RETURN &&
+      return_opcode != Instruction::RETURN_OBJECT) {
+    return false;
+  }
+
+  uint32_t return_reg = return_instruction->VRegA_11x();
+  DCHECK_LT(return_reg, code_item->registers_size_);
+
+  uint32_t vA, vB, dummy;
+  uint64_t dummy_wide;
+  instruction->Decode(vA, vB, dummy_wide, dummy, nullptr);
+  if (instruction->Opcode() == Instruction::CONST_HIGH16) {
+    vB <<= 16;
+  }
+  DCHECK_LT(vA, code_item->registers_size_);
+  if (vA != return_reg) {
+    return false;  // Not returning the value set by const?
+  }
+  if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
+    return false;  // Returning non-null reference constant?
+  }
+  result->opcode = kInlineOpNonWideConst;
+  result->flags = kInlineSpecial;
+  result->d.data = static_cast<uint64_t>(vB);
+  return true;
+}
+
+bool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
+                                             InlineMethod* result) {
+  const DexFile::CodeItem* code_item = verifier->CodeItem();
+  const Instruction* instruction = Instruction::At(code_item->insns_);
+  Instruction::Code opcode = instruction->Opcode();
+  DCHECK(IsInstructionIGet(opcode));
+
+  const Instruction* return_instruction = instruction->Next();
+  Instruction::Code return_opcode = return_instruction->Opcode();
+  if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) &&
+      !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) &&
+      !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE &&
+          opcode != Instruction::IGET_OBJECT)) {
+    return false;
+  }
+
+  uint32_t return_reg = return_instruction->VRegA_11x();
+  DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
+            code_item->registers_size_);
+
+  uint32_t dst_reg = instruction->VRegA_22c();
+  uint32_t object_reg = instruction->VRegB_22c();
+  uint32_t field_idx = instruction->VRegC_22c();
+  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  DCHECK_GE(object_reg, arg_start);
+  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_);
+  if (dst_reg != return_reg) {
+    return false;  // Not returning the value retrieved by IGET?
+  }
+
+  if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
+    // TODO: Support inlining IGET on other register than "this".
+    return false;
+  }
+
+  if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, &result->d.ifield_data)) {
+    return false;
+  }
+
+  result->opcode = kInlineOpIGet;
+  result->flags = kInlineSpecial;
+  InlineIGetIPutData* data = &result->d.ifield_data;
+  data->op_variant = IGetVariant(opcode);
+  data->object_arg = object_reg - arg_start;  // Allow IGET on any register, not just "this".
+  data->src_arg = 0;
+  data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
+  data->reserved = 0;
+  return true;
+}
+
+bool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
+                                             InlineMethod* result) {
+  const DexFile::CodeItem* code_item = verifier->CodeItem();
+  const Instruction* instruction = Instruction::At(code_item->insns_);
+  Instruction::Code opcode = instruction->Opcode();
+  DCHECK(IsInstructionIPut(opcode));
+
+  const Instruction* return_instruction = instruction->Next();
+  Instruction::Code return_opcode = return_instruction->Opcode();
+  if (return_opcode != Instruction::RETURN_VOID) {
+    // TODO: Support returning an argument.
+    // This is needed by builder classes and generated accessor setters.
+    //    builder.setX(value): iput value, this, fieldX; return-object this;
+    //    object.access$nnn(value): iput value, this, fieldX; return value;
+    // Use InlineIGetIPutData::reserved to hold the information.
+    return false;
+  }
+
+  uint32_t src_reg = instruction->VRegA_22c();
+  uint32_t object_reg = instruction->VRegB_22c();
+  uint32_t field_idx = instruction->VRegC_22c();
+  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  DCHECK_GE(object_reg, arg_start);
+  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_GE(src_reg, arg_start);
+  DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_);
+
+  if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
+    // TODO: Support inlining IPUT on other register than "this".
+    return false;
+  }
+
+  if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, &result->d.ifield_data)) {
+    return false;
+  }
+
+  result->opcode = kInlineOpIPut;
+  result->flags = kInlineSpecial;
+  InlineIGetIPutData* data = &result->d.ifield_data;
+  data->op_variant = IPutVariant(opcode);
+  data->object_arg = object_reg - arg_start;  // Allow IPUT on any register, not just "this".
+  data->src_arg = src_reg - arg_start;
+  data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
+  data->reserved = 0;
+  return true;
+}
+
+bool InlineMethodAnalyser::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
+                                                      verifier::MethodVerifier* verifier,
+                                                      InlineIGetIPutData* result) {
+  mirror::DexCache* dex_cache = verifier->GetDexCache();
+  uint32_t method_idx = verifier->GetMethodReference().dex_method_index;
+  mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx);
+  mirror::ArtField* field = dex_cache->GetResolvedField(field_idx);
+  if (method == nullptr || field == nullptr || field->IsStatic()) {
+    return false;
+  }
+  mirror::Class* method_class = method->GetDeclaringClass();
+  mirror::Class* field_class = field->GetDeclaringClass();
+  if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
+      (is_put && field->IsFinal() && method_class != field_class)) {
+    return false;
+  }
+  DCHECK_GE(field->GetOffset().Int32Value(), 0);
+  result->field_idx = field_idx;
+  result->field_offset = field->GetOffset().Int32Value();
+  result->is_volatile = field->IsVolatile();
+  return true;
+}
+
+}  // namespace art
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
new file mode 100644
index 0000000..8e1a408
--- /dev/null
+++ b/runtime/quick/inline_method_analyser.h
@@ -0,0 +1,177 @@
+/*
+ * 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_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
+#define ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
+
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "dex_file.h"
+#include "dex_instruction.h"
+
+/*
+ * NOTE: This code is part of the quick compiler. It lives in the runtime
+ * only to allow the debugger to check whether a method has been inlined.
+ */
+
+namespace art {
+
+namespace verifier {
+class MethodVerifier;
+}  // namespace verifier
+
+enum InlineMethodOpcode : uint16_t {
+  kIntrinsicDoubleCvt,
+  kIntrinsicFloatCvt,
+  kIntrinsicReverseBytes,
+  kIntrinsicAbsInt,
+  kIntrinsicAbsLong,
+  kIntrinsicAbsFloat,
+  kIntrinsicAbsDouble,
+  kIntrinsicMinMaxInt,
+  kIntrinsicSqrt,
+  kIntrinsicCharAt,
+  kIntrinsicCompareTo,
+  kIntrinsicIsEmptyOrLength,
+  kIntrinsicIndexOf,
+  kIntrinsicCurrentThread,
+  kIntrinsicPeek,
+  kIntrinsicPoke,
+  kIntrinsicCas,
+  kIntrinsicUnsafeGet,
+  kIntrinsicUnsafePut,
+
+  kInlineOpNop,
+  kInlineOpReturnArg,
+  kInlineOpNonWideConst,
+  kInlineOpIGet,
+  kInlineOpIPut,
+};
+std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
+
+enum InlineMethodFlags : uint16_t {
+  kNoInlineMethodFlags = 0x0000,
+  kInlineIntrinsic     = 0x0001,
+  kInlineSpecial       = 0x0002,
+};
+
+// IntrinsicFlags are stored in InlineMethod::d::raw_data
+enum IntrinsicFlags {
+  kIntrinsicFlagNone = 0,
+
+  // kIntrinsicMinMaxInt
+  kIntrinsicFlagMax = kIntrinsicFlagNone,
+  kIntrinsicFlagMin = 1,
+
+  // kIntrinsicIsEmptyOrLength
+  kIntrinsicFlagLength  = kIntrinsicFlagNone,
+  kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
+
+  // kIntrinsicIndexOf
+  kIntrinsicFlagBase0 = kIntrinsicFlagMin,
+
+  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
+  kIntrinsicFlagIsLong     = kIntrinsicFlagMin,
+  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
+  kIntrinsicFlagIsVolatile = 2,
+  // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
+  kIntrinsicFlagIsObject   = 4,
+  // kIntrinsicUnsafePut
+  kIntrinsicFlagIsOrdered  = 8,
+};
+
+struct InlineIGetIPutData {
+  // The op_variant below is opcode-Instruction::IGET for IGETs and
+  // opcode-Instruction::IPUT for IPUTs. This is because the runtime
+  // doesn't know the OpSize enumeration.
+  uint16_t op_variant : 3;
+  uint16_t object_arg : 4;
+  uint16_t src_arg : 4;  // iput only
+  uint16_t method_is_static : 1;
+  uint16_t reserved : 4;
+  uint16_t field_idx;
+  uint32_t is_volatile : 1;
+  uint32_t field_offset : 31;
+};
+COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
+
+struct InlineReturnArgData {
+  uint16_t arg;
+  uint16_t is_wide : 1;
+  uint16_t is_object : 1;
+  uint16_t reserved : 14;
+  uint32_t reserved2;
+};
+COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
+
+struct InlineMethod {
+  InlineMethodOpcode opcode;
+  InlineMethodFlags flags;
+  union {
+    uint64_t data;
+    InlineIGetIPutData ifield_data;
+    InlineReturnArgData return_data;
+  } d;
+};
+
+class InlineMethodAnalyser {
+ public:
+  /**
+   * Analyse method code to determine if the method is a candidate for inlining.
+   * If it is, record the inlining data.
+   *
+   * @param verifier the method verifier holding data about the method to analyse.
+   * @param method placeholder for the inline method data.
+   * @return true if the method is a candidate for inlining, false otherwise.
+   */
+  static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
+    return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
+  }
+
+  static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
+    return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
+  }
+
+  static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
+    return opcode - Instruction::IGET;
+  }
+
+  static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
+    return opcode - Instruction::IPUT;
+  }
+
+ private:
+  static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
+  static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
+  static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can we fast path instance field access in a verified accessor?
+  // If yes, computes field's offset and volatility and whether the method is static or not.
+  static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
+                                         verifier::MethodVerifier* verifier,
+                                         InlineIGetIPutData* result)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index f4d2dd1..86a03ab 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -96,8 +96,10 @@
     }
   }
 
+  static int start;
   public static void test_String_indexOf() {
     String str0 = "";
+    String str1 = "/";
     String str3 = "abc";
     String str10 = "abcdefghij";
     String str40 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabc";
@@ -122,6 +124,7 @@
     Assert.assertEquals(str0.indexOf('a',20), -1);
     Assert.assertEquals(str0.indexOf('a',0), -1);
     Assert.assertEquals(str0.indexOf('a',-1), -1);
+    Assert.assertEquals(str1.indexOf('/',++start), -1);
     Assert.assertEquals(str3.indexOf('a',0), 0);
     Assert.assertEquals(str3.indexOf('a',1), -1);
     Assert.assertEquals(str3.indexOf('a',1234), -1);
diff --git a/test/Android.mk b/test/Android.mk
index bae4680..da5b35f 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -44,8 +44,7 @@
 TEST_OAT_DIRECTORIES := \
 	Main \
 	HelloWorld \
-	\
-        InterfaceTest \
+	InterfaceTest \
 	JniTest \
 	NativeAllocations \
 	ParallelGC \
@@ -110,12 +109,12 @@
 test-art-target-oat-$(1): $(ART_TEST_OUT)/oat-test-dex-$(1).jar test-art-target-sync
 	adb shell touch $(ART_TEST_DIR)/test-art-target-oat-$(1)
 	adb shell rm $(ART_TEST_DIR)/test-art-target-oat-$(1)
-	adb shell sh -c "/system/bin/dalvikvm -XXlib:libartd.so -Ximage:$(ART_TEST_DIR)/core.art -classpath $(ART_TEST_DIR)/oat-test-dex-$(1).jar -Djava.library.path=$(ART_TEST_DIR) $(1) $(2) && touch $(ART_TEST_DIR)/test-art-target-oat-$(1)"
+	adb shell sh -c "/system/bin/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$(ART_TEST_DIR)/core.art -classpath $(ART_TEST_DIR)/oat-test-dex-$(1).jar -Djava.library.path=$(ART_TEST_DIR) $(1) $(2) && touch $(ART_TEST_DIR)/test-art-target-oat-$(1)"
 	$(hide) (adb pull $(ART_TEST_DIR)/test-art-target-oat-$(1) /tmp/ && echo test-art-target-oat-$(1) PASSED) || (echo test-art-target-oat-$(1) FAILED && exit 1)
 	$(hide) rm /tmp/test-art-target-oat-$(1)
 
 $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OAT)
-	$(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$(PWD)/$$< --oat-file=$(PWD)/$$@ --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
+	$(DEX2OAT) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$(PWD)/$$< --oat-file=$(PWD)/$$@ --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
 
 .PHONY: test-art-host-oat-default-$(1)
 test-art-host-oat-default-$(1): $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex test-art-host-dependencies
@@ -123,7 +122,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-default-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-default-$(1) PASSED || (echo test-art-host-oat-default-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-default-$(1)