Merge "Fix debugger crashes in presence of proxy objects."
diff --git a/build/Android.common.mk b/build/Android.common.mk
index f22eb37..219f1e2 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -37,6 +37,12 @@
 ART_BUILD_HOST_NDEBUG ?= $(WITH_HOST_DALVIK)
 ART_BUILD_HOST_DEBUG ?= $(WITH_HOST_DALVIK)
 
+ifeq ($(BUILD_HOST_64bit),)
+ART_HOST_ARCH := x86
+else
+ART_HOST_ARCH := x86_64
+endif
+
 ifeq ($(ART_BUILD_TARGET_NDEBUG),false)
 $(info Disabling ART_BUILD_TARGET_NDEBUG)
 endif
@@ -87,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/build/Android.oat.mk b/build/Android.oat.mk
index 6012421..def585b 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -40,19 +40,13 @@
 
 TARGET_INSTRUCTION_SET_FEATURES := $(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES)
 
-ifeq ($(BUILD_HOST_64bit),)
-host_arch := x86
-else
-host_arch := x86_64
-endif
-
 $(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
 	@echo "host dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
 	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix \
 		--dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) \
 		--oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(LIBART_IMG_HOST_BASE_ADDRESS) \
-		--instruction-set=$(host_arch) --host --android-root=$(HOST_OUT)
+		--instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
 
 $(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $@ ($?)"
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 def7b68..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"
@@ -219,8 +219,15 @@
       } else {
         const void* method_code = GetQuickGenericJniTrampoline();
         mirror::ArtMethod* callee_save_method = runtime_->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
+
+        // Compute Sirt size, as Sirt goes into frame
+        MethodHelper mh(method);
+        uint32_t sirt_refs = mh.GetNumberOfReferenceArgsWithoutReceiver() + 1;
+        uint32_t sirt_size = StackIndirectReferenceTable::SizeOf(sirt_refs);
+
         OatFile::OatMethod oat_method = CreateOatMethod(method_code,
-                                                        callee_save_method->GetFrameSizeInBytes(),
+                                                        callee_save_method->GetFrameSizeInBytes() +
+                                                            sirt_size,
                                                         callee_save_method->GetCoreSpillMask(),
                                                         callee_save_method->GetFpSpillMask(),
                                                         nullptr,
@@ -312,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..f58b38b
--- /dev/null
+++ b/compiler/compilers.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 {
+  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/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 34d3834..d095444 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -997,7 +997,6 @@
       fill_array_data_(arena, 4, kGrowableArrayFillArrayData),
       throw_launchpads_(arena, 2048, kGrowableArrayThrowLaunchPads),
       suspend_launchpads_(arena, 4, kGrowableArraySuspendLaunchPads),
-      intrinsic_launchpads_(arena, 2048, kGrowableArrayMisc),
       tempreg_info_(arena, 20, kGrowableArrayMisc),
       reginfo_map_(arena, 64, kGrowableArrayMisc),
       pointer_storage_(arena, 128, kGrowableArrayMisc),
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/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 00c51d4..1c5f6a0 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -581,24 +581,6 @@
   }
 }
 
-void Mir2Lir::HandleIntrinsicLaunchPads() {
-  int num_elems = intrinsic_launchpads_.Size();
-  for (int i = 0; i < num_elems; i++) {
-    ResetRegPool();
-    ResetDefTracking();
-    LIR* lab = intrinsic_launchpads_.Get(i);
-    CallInfo* info = reinterpret_cast<CallInfo*>(UnwrapPointer(lab->operands[0]));
-    current_dalvik_offset_ = info->offset;
-    AppendLIR(lab);
-    // NOTE: GenInvoke handles MarkSafepointPC
-    GenInvoke(info);
-    LIR* resume_lab = reinterpret_cast<LIR*>(UnwrapPointer(lab->operands[2]));
-    if (resume_lab != NULL) {
-      OpUnconditionalBranch(resume_lab);
-    }
-  }
-}
-
 void Mir2Lir::HandleThrowLaunchPads() {
   int num_elems = throw_launchpads_.Size();
   for (int i = 0; i < num_elems; i++) {
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 1907012..419d0a9 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -34,6 +34,32 @@
  * and "op" calls may be used here.
  */
 
+void Mir2Lir::AddIntrinsicLaunchpad(CallInfo* info, LIR* branch, LIR* resume) {
+  class IntrinsicLaunchpadPath : public Mir2Lir::LIRSlowPath {
+   public:
+    IntrinsicLaunchpadPath(Mir2Lir* m2l, CallInfo* info, LIR* branch, LIR* resume = nullptr)
+        : LIRSlowPath(m2l, info->offset, branch, resume), info_(info) {
+    }
+
+    void Compile() {
+      m2l_->ResetRegPool();
+      m2l_->ResetDefTracking();
+      LIR* label = GenerateTargetLabel();
+      label->opcode = kPseudoIntrinsicRetry;
+      // NOTE: GenInvokeNoInline() handles MarkSafepointPC.
+      m2l_->GenInvokeNoInline(info_);
+      if (cont_ != nullptr) {
+        m2l_->OpUnconditionalBranch(cont_);
+      }
+    }
+
+   private:
+    CallInfo* const info_;
+  };
+
+  AddSlowPath(new (arena_) IntrinsicLaunchpadPath(this, info, branch, resume));
+}
+
 /*
  * To save scheduling time, helper calls are broken into two parts: generation of
  * the helper target address, and the actuall call to the helper.  Because x86
@@ -984,7 +1010,7 @@
   int reg_max;
   GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), info->opt_flags);
   bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
-  LIR* launch_pad = NULL;
+  LIR* range_check_branch = nullptr;
   int reg_off = INVALID_REG;
   int reg_ptr = INVALID_REG;
   if (cu_->instruction_set != kX86) {
@@ -998,25 +1024,22 @@
     LoadWordDisp(rl_obj.reg.GetReg(), value_offset, reg_ptr);
     if (range_check) {
       // Set up a launch pad to allow retry in case of bounds violation */
-      launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
-      intrinsic_launchpads_.Insert(launch_pad);
       OpRegReg(kOpCmp, rl_idx.reg.GetReg(), reg_max);
       FreeTemp(reg_max);
-      OpCondBranch(kCondUge, launch_pad);
+      range_check_branch = OpCondBranch(kCondUge, nullptr);
     }
     OpRegImm(kOpAdd, reg_ptr, data_offset);
   } else {
     if (range_check) {
       // On x86, we can compare to memory directly
       // Set up a launch pad to allow retry in case of bounds violation */
-      launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
-      intrinsic_launchpads_.Insert(launch_pad);
       if (rl_idx.is_const) {
-        OpCmpMemImmBranch(kCondUlt, INVALID_REG, rl_obj.reg.GetReg(), count_offset,
-                          mir_graph_->ConstantValue(rl_idx.orig_sreg), launch_pad);
+        range_check_branch = OpCmpMemImmBranch(
+            kCondUlt, INVALID_REG, rl_obj.reg.GetReg(), count_offset,
+            mir_graph_->ConstantValue(rl_idx.orig_sreg), nullptr);
       } else {
         OpRegMem(kOpCmp, rl_idx.reg.GetReg(), rl_obj.reg.GetReg(), count_offset);
-        OpCondBranch(kCondUge, launch_pad);
+        range_check_branch = OpCondBranch(kCondUge, nullptr);
       }
     }
     reg_off = AllocTemp();
@@ -1045,10 +1068,10 @@
   FreeTemp(reg_ptr);
   StoreValue(rl_dest, rl_result);
   if (range_check) {
-    launch_pad->operands[2] = 0;  // no resumption
+    DCHECK(range_check_branch != nullptr);
+    info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've already null checked.
+    AddIntrinsicLaunchpad(info, range_check_branch);
   }
-  // Record that we've already inlined & null checked
-  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
   return true;
 }
 
@@ -1232,7 +1255,7 @@
 }
 
 /*
- * Fast string.index_of(I) & (II).  Tests for simple case of char <= 0xffff,
+ * Fast String.indexOf(I) & (II).  Tests for simple case of char <= 0xFFFF,
  * otherwise bails to standard library code.
  */
 bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
@@ -1240,14 +1263,19 @@
     // TODO - add Mips implementation
     return false;
   }
+  RegLocation rl_obj = info->args[0];
+  RegLocation rl_char = info->args[1];
+  if (rl_char.is_const && (mir_graph_->ConstantValue(rl_char) & ~0xFFFF) != 0) {
+    // Code point beyond 0xFFFF. Punt to the real String.indexOf().
+    return false;
+  }
+
   ClobberCallerSave();
   LockCallTemps();  // Using fixed registers
   int reg_ptr = TargetReg(kArg0);
   int reg_char = TargetReg(kArg1);
   int reg_start = TargetReg(kArg2);
 
-  RegLocation rl_obj = info->args[0];
-  RegLocation rl_char = info->args[1];
   LoadValueDirectFixed(rl_obj, reg_ptr);
   LoadValueDirectFixed(rl_char, reg_char);
   if (zero_based) {
@@ -1258,15 +1286,20 @@
   }
   int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf));
   GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
-  LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
-  intrinsic_launchpads_.Insert(launch_pad);
-  OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
+  LIR* high_code_point_branch =
+      rl_char.is_const ? nullptr : OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, nullptr);
   // NOTE: not a safepoint
   OpReg(kOpBlx, r_tgt);
-  LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
-  launch_pad->operands[2] = WrapPointer(resume_tgt);
-  // Record that we've already inlined & null checked
-  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  if (!rl_char.is_const) {
+    // Add the slow path for code points beyond 0xFFFF.
+    DCHECK(high_code_point_branch != nullptr);
+    LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
+    info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've null checked.
+    AddIntrinsicLaunchpad(info, high_code_point_branch, resume_tgt);
+  } else {
+    DCHECK_EQ(mir_graph_->ConstantValue(rl_char) & ~0xFFFF, 0);
+    DCHECK(high_code_point_branch == nullptr);
+  }
   RegLocation rl_return = GetReturn(false);
   RegLocation rl_dest = InlineTarget(info);
   StoreValue(rl_dest, rl_return);
@@ -1291,19 +1324,16 @@
   int r_tgt = (cu_->instruction_set != kX86) ?
       LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
   GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
+  info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've null checked.
   // TUNING: check if rl_cmp.s_reg_low is already null checked
-  LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
-  intrinsic_launchpads_.Insert(launch_pad);
-  OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
+  LIR* cmp_null_check_branch = OpCmpImmBranch(kCondEq, reg_cmp, 0, nullptr);
+  AddIntrinsicLaunchpad(info, cmp_null_check_branch);
   // NOTE: not a safepoint
   if (cu_->instruction_set != kX86) {
     OpReg(kOpBlx, r_tgt);
   } else {
     OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pStringCompareTo));
   }
-  launch_pad->operands[2] = 0;  // No return possible
-  // Record that we've already inlined & null checked
-  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
   RegLocation rl_return = GetReturn(false);
   RegLocation rl_dest = InlineTarget(info);
   StoreValue(rl_dest, rl_return);
@@ -1390,13 +1420,15 @@
 }
 
 void Mir2Lir::GenInvoke(CallInfo* info) {
-  if (!(info->opt_flags & MIR_INLINED)) {
-    DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
-    if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
-        ->GenIntrinsic(this, info)) {
-      return;
-    }
+  DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
+  if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
+      ->GenIntrinsic(this, info)) {
+    return;
   }
+  GenInvokeNoInline(info);
+}
+
+void Mir2Lir::GenInvokeNoInline(CallInfo* info) {
   int call_state = 0;
   LIR* null_ck;
   LIR** p_null_ck = NULL;
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 40ed5ef..f93a5e3 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
@@ -1089,8 +1088,6 @@
   HandleSuspendLaunchPads();
 
   HandleThrowLaunchPads();
-
-  HandleIntrinsicLaunchPads();
 }
 
 //
@@ -1098,10 +1095,10 @@
 //
 
 LIR* Mir2Lir::LIRSlowPath::GenerateTargetLabel() {
-  LIR* target = m2l_->RawLIR(current_dex_pc_, kPseudoTargetLabel);
-  m2l_->AppendLIR(target);
-  fromfast_->target = target;
   m2l_->SetCurrentDexPc(current_dex_pc_);
+  LIR* target = m2l_->NewLIR0(kPseudoTargetLabel);
+  fromfast_->target = target;
   return target;
 }
+
 }  // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 6955577..856318f 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -535,11 +535,11 @@
     RegisterInfo* GetRegInfo(int reg);
 
     // Shared by all targets - implemented in gen_common.cc.
+    void AddIntrinsicLaunchpad(CallInfo* info, LIR* branch, LIR* resume = nullptr);
     bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
                           RegLocation rl_src, RegLocation rl_dest, int lit);
     bool HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit);
     void HandleSuspendLaunchPads();
-    void HandleIntrinsicLaunchPads();
     void HandleThrowLaunchPads();
     void HandleSlowPaths();
     void GenBarrier();
@@ -637,6 +637,7 @@
                                                             RegLocation arg2,
                                                             bool safepoint_pc);
     void GenInvoke(CallInfo* info);
+    void GenInvokeNoInline(CallInfo* info);
     void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
     int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
                              NextCallInsn next_call_insn,
@@ -1196,7 +1197,6 @@
     GrowableArray<FillArrayData*> fill_array_data_;
     GrowableArray<LIR*> throw_launchpads_;
     GrowableArray<LIR*> suspend_launchpads_;
-    GrowableArray<LIR*> intrinsic_launchpads_;
     GrowableArray<RegisterInfo*> tempreg_info_;
     GrowableArray<RegisterInfo*> reginfo_map_;
     GrowableArray<void*> pointer_storage_;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 083fccb..5b6e119 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -965,21 +965,17 @@
   // Is the string non-NULL?
   LoadValueDirectFixed(rl_obj, rDX);
   GenNullCheck(rl_obj.s_reg_low, rDX, info->opt_flags);
-
-  // Record that we have inlined & null checked the object.
-  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've null checked.
 
   // Does the character fit in 16 bits?
-  LIR* launch_pad = nullptr;
+  LIR* launchpad_branch = nullptr;
   if (rl_char.is_const) {
     // We need the value in EAX.
     LoadConstantNoClobber(rAX, char_value);
   } else {
     // Character is not a constant; compare at runtime.
     LoadValueDirectFixed(rl_char, rAX);
-    launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
-    intrinsic_launchpads_.Insert(launch_pad);
-    OpCmpImmBranch(kCondGt, rAX, 0xFFFF, launch_pad);
+    launchpad_branch = OpCmpImmBranch(kCondGt, rAX, 0xFFFF, nullptr);
   }
 
   // From here down, we know that we are looking for a char that fits in 16 bits.
@@ -1028,7 +1024,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);
       }
@@ -1096,9 +1092,9 @@
   NewLIR1(kX86Pop32R, rDI);
 
   // Out of line code returns here.
-  if (launch_pad != nullptr) {
+  if (launchpad_branch != nullptr) {
     LIR *return_point = NewLIR0(kPseudoTargetLabel);
-    launch_pad->operands[2] = WrapPointer(return_point);
+    AddIntrinsicLaunchpad(info, launchpad_branch, return_point);
   }
 
   StoreValue(rl_dest, rl_return);
diff --git a/compiler/driver/compiler_callbacks_impl.h b/compiler/driver/compiler_callbacks_impl.h
index ed6a925..92adb20 100644
--- a/compiler/driver/compiler_callbacks_impl.h
+++ b/compiler/driver/compiler_callbacks_impl.h
@@ -36,15 +36,7 @@
     ~CompilerCallbacksImpl() { }
 
     bool MethodVerified(verifier::MethodVerifier* verifier)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
-      bool result = verification_results_->ProcessVerifiedMethod(verifier);
-      if (result) {
-        MethodReference ref = verifier->GetMethodReference();
-        method_inliner_map_->GetMethodInliner(ref.dex_file)
-            ->AnalyseMethodCode(verifier);
-      }
-      return result;
-    }
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
     void ClassRejected(ClassReference ref) OVERRIDE {
       verification_results_->AddRejectedClass(ref);
     }
@@ -54,6 +46,16 @@
     DexFileToMethodInlinerMap* const method_inliner_map_;
 };
 
+inline bool CompilerCallbacksImpl::MethodVerified(verifier::MethodVerifier* verifier) {
+  bool result = verification_results_->ProcessVerifiedMethod(verifier);
+  if (result) {
+    MethodReference ref = verifier->GetMethodReference();
+    method_inliner_map_->GetMethodInliner(ref.dex_file)
+        ->AnalyseMethodCode(verifier);
+  }
+  return result;
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 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/image_writer.cc b/compiler/image_writer.cc
index f4b507a..8885652 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -639,14 +639,17 @@
           (!orig->IsStatic() || orig->IsConstructor() || orig->GetDeclaringClass()->IsInitialized())) {
         // We have code for a non-static or initialized method, just use the code.
         copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(quick_code);
-      } else if (quick_code == nullptr && orig->IsNative() && !orig->IsStatic()) {
-        // Non-static native method missing compiled code, use generic JNI version.
+      } else if (quick_code == nullptr && orig->IsNative() &&
+          (!orig->IsStatic() || orig->GetDeclaringClass()->IsInitialized())) {
+        // Non-static or initialized native method missing compiled code, use generic JNI version.
         copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_generic_jni_trampoline_offset_));
       } else if (quick_code == nullptr && !orig->IsNative()) {
         // We don't have code at all for a non-native method, use the interpreter.
         copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_to_interpreter_bridge_offset_));
       } else {
-        // We have code for a static method, but need to go through the resolution stub for class initialization.
+        CHECK(!orig->GetDeclaringClass()->IsInitialized());
+        // We have code for a static method, but need to go through the resolution stub for class
+        // initialization.
         copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_));
       }
       const byte* portable_code = GetOatAddress(orig->GetPortableOatCodeOffset());
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/oat_writer.cc b/compiler/oat_writer.cc
index ffd7b41..c5219a6 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -364,7 +364,7 @@
   OatClass* oat_class = oat_classes_[oat_class_index];
   CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
-  if (compiled_method != NULL) {
+  if (compiled_method != nullptr) {
     const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode();
     const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
     if (portable_code != nullptr) {
@@ -495,6 +495,33 @@
 
 
   if (compiler_driver_->IsImage()) {
+    // Derive frame size and spill masks for native methods without code:
+    // These are generic JNI methods...
+    if (is_native && compiled_method == nullptr) {
+      // Compute Sirt size as putting _every_ reference into it, even null ones.
+      uint32_t s_len;
+      const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx), &s_len);
+      DCHECK(shorty != nullptr);
+      uint32_t refs = 1;    // Native method always has "this" or class.
+      for (uint32_t i = 1; i < s_len; ++i) {
+        if (shorty[i] == 'L') {
+          refs++;
+        }
+      }
+      size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSize(refs);
+
+      // Get the generic spill masks and base frame size.
+      mirror::ArtMethod* callee_save_method =
+          Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
+
+      frame_size_in_bytes = callee_save_method->GetFrameSizeInBytes() + sirt_size;
+      core_spill_mask = callee_save_method->GetCoreSpillMask();
+      fp_spill_mask = callee_save_method->GetFpSpillMask();
+      mapping_table_offset = 0;
+      vmap_table_offset = 0;
+      gc_map_offset = 0;
+    }
+
     ClassLinker* linker = Runtime::Current()->GetClassLinker();
     // Unchecked as we hold mutator_lock_ on entry.
     ScopedObjectAccessUnchecked soa(Thread::Current());
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 cc78816..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;
@@ -738,8 +744,12 @@
 
 #if defined(__arm__)
   InstructionSet instruction_set = kThumb2;
+#elif defined(__aarch64__)
+  InstructionSet instruction_set = kArm64;
 #elif defined(__i386__)
   InstructionSet instruction_set = kX86;
+#elif defined(__x86_64__)
+  InstructionSet instruction_set = kX86_64;
 #elif defined(__mips__)
   InstructionSet instruction_set = kMips;
 #else
@@ -840,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();
@@ -908,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());
     }
@@ -1097,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/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 81d5f4c..5fbf8cb 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -421,7 +421,7 @@
 .Lreturn_float_quick2:
     movss %xmm0, (%r8)           // Store the floating point result.
     ret
-END_FUNCTION art_quick_invoke_stub
+END_FUNCTION art_quick_invoke_static_stub
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
@@ -646,7 +646,43 @@
 UNIMPLEMENTED art_quick_get32_static
 UNIMPLEMENTED art_quick_get64_static
 UNIMPLEMENTED art_quick_get_obj_static
-UNIMPLEMENTED art_quick_proxy_invoke_handler
+
+DEFINE_FUNCTION art_quick_proxy_invoke_handler
+    // Save callee and GPR args, mixed together to agree with core spills bitmap of ref. and args
+    // callee save frame.
+    PUSH r15  // Callee save.
+    PUSH r14  // Callee save.
+    PUSH r13  // Callee save.
+    PUSH r12  // Callee save.
+    PUSH r9   // Quick arg 5.
+    PUSH r8   // Quick arg 4.
+    PUSH rsi  // Quick arg 1.
+    PUSH rbp  // Callee save.
+    PUSH rbx  // Callee save.
+    PUSH rdx  // Quick arg 2.
+    PUSH rcx  // Quick arg 3.
+    // Create space for FPR args and create 2 slots, 1 of padding and 1 for the ArtMethod*.
+    subq LITERAL(80), %rsp
+    CFI_ADJUST_CFA_OFFSET(80)
+    // Save FPRs.
+    movq %xmm0, 16(%rsp)
+    movq %xmm1, 24(%rsp)
+    movq %xmm2, 32(%rsp)
+    movq %xmm3, 40(%rsp)
+    movq %xmm4, 48(%rsp)
+    movq %xmm5, 56(%rsp)
+    movq %xmm6, 64(%rsp)
+    movq %xmm7, 72(%rsp)
+    // Store proxy method to bottom of stack.
+    movq %rdi, 0(%rsp)
+    movq %gs:THREAD_SELF_OFFSET, %rdx  // Pass Thread::Current().
+    movq %rsp, %rcx                    // Pass SP.
+    call PLT_SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+    movq %rax, %xmm0                   // Copy return value in case of float returns.
+    addq LITERAL(168), %rsp            // Pop arguments.
+    CFI_ADJUST_CFA_OFFSET(-168)
+    RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_proxy_invoke_handler
 
     /*
      * Called to resolve an imt conflict.
@@ -659,6 +695,7 @@
     movq %rsp, %rcx
     call PLT_SYMBOL(artQuickResolutionTrampoline) // (called, receiver, Thread*, SP)
     movq %rax, %r10               // Remember returned code pointer in R10.
+    movq (%rsp), %rdi             // Load called method into RDI.
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
     testq %r10, %r10              // If code pointer is NULL goto deliver pending exception.
     jz 1f
@@ -674,6 +711,13 @@
  * |                   |
  * | caller method...  |
  * #-------------------#    <--- SP on entry
+ *
+ *          |
+ *          V
+ *
+ * #-------------------#
+ * | caller method...  |
+ * #-------------------#
  * | Return            |
  * | R15               |    callee save
  * | R14               |    callee save
@@ -697,22 +741,7 @@
  * | Padding           |
  * | RDI/Method*       |  <- sp
  * #-------------------#
- * | local ref cookie  | // 4B
- * |   padding         | // 4B
- * #----------#--------#
- * |          |      | |
- * | Temp/    | SIRT | |    Scratch frame is 4k
- * | Scratch  |      v |
- * | Frame    #--------|
- * |                   |
- * |          #--------|
- * |          |      ^ |
- * |          | JNI  | |
- * |          | Stack| |
- * #----------#--------#    <--- SP on native call (needs alignment?)
- * |                   |
- * | Stack for Regs    |    The trampoline assembly will pop these values
- * |                   |    into registers for native call
+ * | Scratch Alloca    |    5K scratch space
  * #---------#---------#
  * |         | sp*     |
  * | Tramp.  #---------#
@@ -720,6 +749,35 @@
  * | Tramp.  #---------#
  * |         | method  |
  * #-------------------#    <--- SP on artQuickGenericJniTrampoline
+ *
+ *           |
+ *           v              artQuickGenericJniTrampoline
+ *
+ * #-------------------#
+ * | caller method...  |
+ * #-------------------#
+ * | Return            |
+ * | Callee-Save Data  |
+ * #-------------------#
+ * | SIRT              |
+ * #-------------------#
+ * | Method*           |    <--- (1)
+ * #-------------------#
+ * | local ref cookie  | // 4B
+ * | SIRT size         | // 4B   TODO: roll into call stack alignment?
+ * #-------------------#
+ * | JNI Call Stack    |
+ * #-------------------#    <--- SP on native call
+ * |                   |
+ * | Stack for Regs    |    The trampoline assembly will pop these values
+ * |                   |    into registers for native call
+ * #-------------------#
+ * | Native code ptr   |
+ * #-------------------#
+ * | Free scratch      |
+ * #-------------------#
+ * | Ptr to (1)        |    <--- RSP
+ * #-------------------#
  */
     /*
      * Called to do a generic JNI down-call
@@ -752,7 +810,8 @@
     // Store native ArtMethod* to bottom of stack.
     movq %rdi, 0(%rsp)
     movq %rsp, %rbp                 // save SP at callee-save frame
-    CFI_DEF_CFA_REGISTER(rbp)
+    movq %rsp, %rbx
+    CFI_DEF_CFA_REGISTER(rbx)
     //
     // reserve a lot of space
     //
@@ -778,12 +837,19 @@
     movq %gs:THREAD_SELF_OFFSET, %rdi
     movq %rbp, %rsi
     call PLT_SYMBOL(artQuickGenericJniTrampoline)  // (Thread*, sp)
-    test %rax, %rax                 // Check for error, negative value.
+
+    // At the bottom of the alloca we now have the name pointer to the method=bottom of callee-save
+    // get the adjusted frame pointer
+    popq %rbp
+
+    // Check for error, negative value.
+    test %rax, %rax
     js .Lentry_error
-    // release part of the alloca
+
+    // release part of the alloca, get the code pointer
     addq %rax, %rsp
-    // get the code pointer
     popq %rax
+
     // pop from the register-passing alloca region
     // what's the right layout?
     popq %rdi
@@ -816,7 +882,7 @@
     call PLT_SYMBOL(artQuickGenericJniEndTrampoline)
 
     // Tear down the alloca.
-    movq %rbp, %rsp
+    movq %rbx, %rsp
     CFI_DEF_CFA_REGISTER(rsp)
 
     // Pending exceptions possible.
@@ -854,12 +920,35 @@
     movq %rax, %xmm0
     ret
 .Lentry_error:
-    movq %rbp, %rsp
+    movq %rbx, %rsp
+    CFI_DEF_CFA_REGISTER(rsp)
 .Lexception_in_native:
-    CFI_REL_OFFSET(rsp,176)
     // TODO: the SIRT contains the this pointer which is used by the debugger for exception
     //       delivery.
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    movq %xmm0, 16(%rsp)         // doesn't make sense!!!
+    movq 24(%rsp), %xmm1            // neither does this!!!
+    movq 32(%rsp), %xmm2
+    movq 40(%rsp), %xmm3
+    movq 48(%rsp), %xmm4
+    movq 56(%rsp), %xmm5
+    movq 64(%rsp), %xmm6
+    movq 72(%rsp), %xmm7
+    // was 80 bytes
+    addq LITERAL(80), %rsp
+    CFI_ADJUST_CFA_OFFSET(-80)
+    // Save callee and GPR args, mixed together to agree with core spills bitmap.
+    POP rcx  // Arg.
+    POP rdx  // Arg.
+    POP rbx  // Callee save.
+    POP rbp  // Callee save.
+    POP rsi  // Arg.
+    POP r8   // Arg.
+    POP r9   // Arg.
+    POP r12  // Callee save.
+    POP r13  // Callee save.
+    POP r14  // Callee save.
+    POP r15  // Callee save.
+
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_generic_jni_trampoline
 
diff --git a/runtime/base/hex_dump_test.cc b/runtime/base/hex_dump_test.cc
index d950961..3d782b2 100644
--- a/runtime/base/hex_dump_test.cc
+++ b/runtime/base/hex_dump_test.cc
@@ -24,11 +24,18 @@
 
 namespace art {
 
+#if defined(__LP64__)
+#define ZEROPREFIX "00000000"
+#else
+#define ZEROPREFIX
+#endif
+
 TEST(HexDump, OneLine) {
   const char* test_text = "0123456789abcdef";
   std::ostringstream oss;
   oss << HexDump(test_text, strlen(test_text), false, "");
   EXPECT_STREQ(oss.str().c_str(),
+               ZEROPREFIX
                "00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66  0123456789abcdef");
 }
 
@@ -37,7 +44,9 @@
   std::ostringstream oss;
   oss << HexDump(test_text, strlen(test_text), false, "");
   EXPECT_STREQ(oss.str().c_str(),
+               ZEROPREFIX
                "00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66  0123456789abcdef\n"
+               ZEROPREFIX
                "00000010: 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46  0123456789ABCDEF");
 }
 
@@ -56,7 +65,7 @@
   std::ostringstream oss;
   oss << HexDump(test_text, strlen(test_text), false, "test prefix: ");
   EXPECT_STREQ(oss.str().c_str(),
-               "test prefix: 00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66  "
+               "test prefix: " ZEROPREFIX "00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66  "
                "0123456789abcdef");
 }
 
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index b193ff1..8175514 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -22,7 +22,7 @@
 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
 
 // C++11 final and override keywords that were introduced in GCC version 4.7.
-#if GCC_VERSION >= 40700
+#if defined(__clang__) || GCC_VERSION >= 40700
 #define OVERRIDE override
 #define FINAL final
 #else
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 6255c8c..b709da3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1597,7 +1597,10 @@
   }
   const void* result = GetOatMethodFor(method).GetQuickCode();
   if (result == nullptr) {
-    if (method->IsPortableCompiled()) {
+    if (method->IsNative()) {
+      // No code and native? Use generic trampoline.
+      result = GetQuickGenericJniTrampoline();
+    } else if (method->IsPortableCompiled()) {
       // No code? Do we expect portable code?
       result = GetQuickToPortableBridge();
     } else {
@@ -1707,12 +1710,12 @@
     bool have_portable_code = false;
     if (enter_interpreter) {
       // Use interpreter entry point.
-
-      // check whether the method is native, in which case it's generic JNI
-      portable_code = GetPortableToInterpreterBridge();
+      // Check whether the method is native, in which case it's generic JNI.
       if (quick_code == nullptr && portable_code == nullptr && method->IsNative()) {
         quick_code = GetQuickGenericJniTrampoline();
+        portable_code = GetPortableToQuickBridge();
       } else {
+        portable_code = GetPortableToInterpreterBridge();
         quick_code = GetQuickToInterpreterBridge();
       }
     } else {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 1276cd9..852cef4 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -222,7 +222,8 @@
   return false;
 }
 
-static bool IsSuspendedForDebugger(ScopedObjectAccessUnchecked& soa, Thread* thread) {
+static bool IsSuspendedForDebugger(ScopedObjectAccessUnchecked& soa, Thread* thread)
+    LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) {
   MutexLock mu(soa.Self(), *Locks::thread_suspend_count_lock_);
   // A thread may be suspended for GC; in this code, we really want to know whether
   // there's a debugger suspension active.
@@ -743,8 +744,7 @@
 
 JDWP::JdwpError Dbg::GetOwnedMonitors(JDWP::ObjectId thread_id,
                                       std::vector<JDWP::ObjectId>& monitors,
-                                      std::vector<uint32_t>& stack_depths)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+                                      std::vector<uint32_t>& stack_depths) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
   Thread* thread;
@@ -793,8 +793,8 @@
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id,
+                                         JDWP::ObjectId& contended_monitor) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
   Thread* thread;
@@ -1708,22 +1708,19 @@
   if (error == JDWP::ERR_THREAD_NOT_ALIVE) {
     // Zombie threads are in the null group.
     expandBufAddObjectId(pReply, JDWP::ObjectId(0));
-    return JDWP::ERR_NONE;
+    error = JDWP::ERR_NONE;
+  } else if (error == JDWP::ERR_NONE) {
+    mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+    CHECK(c != nullptr);
+    mirror::ArtField* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
+    CHECK(f != NULL);
+    mirror::Object* group = f->GetObject(thread_object);
+    CHECK(group != NULL);
+    JDWP::ObjectId thread_group_id = gRegistry->Add(group);
+    expandBufAddObjectId(pReply, thread_group_id);
   }
-  if (error != JDWP::ERR_NONE) {
-    return error;
-  }
-  mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
-  CHECK(c != nullptr);
-  mirror::ArtField* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
-  CHECK(f != NULL);
-  mirror::Object* group = f->GetObject(thread_object);
-  CHECK(group != NULL);
-  JDWP::ObjectId thread_group_id = gRegistry->Add(group);
   soa.Self()->EndAssertNoThreadSuspension(old_cause);
-
-  expandBufAddObjectId(pReply, thread_group_id);
-  return JDWP::ERR_NONE;
+  return error;
 }
 
 std::string Dbg::GetThreadGroupName(JDWP::ObjectId thread_group_id) {
@@ -1801,7 +1798,8 @@
   return JDWP::TS_ZOMBIE;
 }
 
-JDWP::JdwpError Dbg::GetThreadStatus(JDWP::ObjectId thread_id, JDWP::JdwpThreadStatus* pThreadStatus, JDWP::JdwpSuspendStatus* pSuspendStatus) {
+JDWP::JdwpError Dbg::GetThreadStatus(JDWP::ObjectId thread_id, JDWP::JdwpThreadStatus* pThreadStatus,
+                                     JDWP::JdwpSuspendStatus* pSuspendStatus) {
   ScopedObjectAccess soa(Thread::Current());
 
   *pSuspendStatus = JDWP::SUSPEND_STATUS_NOT_SUSPENDED;
@@ -2610,6 +2608,7 @@
 class ScopedThreadSuspension {
  public:
   ScopedThreadSuspension(Thread* self, JDWP::ObjectId thread_id)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
       thread_(NULL),
       error_(JDWP::ERR_NONE),
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 6c44bde..6610347 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -220,8 +220,11 @@
   static JDWP::JdwpError GetOwnedMonitors(JDWP::ObjectId thread_id,
                                           std::vector<JDWP::ObjectId>& monitors,
                                           std::vector<uint32_t>& stack_depths)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
+  static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id,
+                                             JDWP::ObjectId& contended_monitor)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   //
@@ -301,7 +304,8 @@
   static JDWP::JdwpError GetThreadName(JDWP::ObjectId thread_id, std::string& name)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  static JDWP::JdwpError GetThreadGroup(JDWP::ObjectId thread_id, JDWP::ExpandBuf* pReply);
+  static JDWP::JdwpError GetThreadGroup(JDWP::ObjectId thread_id, JDWP::ExpandBuf* pReply)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_);
   static std::string GetThreadGroupName(JDWP::ObjectId thread_group_id);
   static JDWP::ObjectId GetThreadGroupParent(JDWP::ObjectId thread_group_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -310,8 +314,14 @@
   static JDWP::ObjectId GetMainThreadGroupId();
 
   static JDWP::JdwpThreadStatus ToJdwpThreadStatus(ThreadState state);
-  static JDWP::JdwpError GetThreadStatus(JDWP::ObjectId thread_id, JDWP::JdwpThreadStatus* pThreadStatus, JDWP::JdwpSuspendStatus* pSuspendStatus);
-  static JDWP::JdwpError GetThreadDebugSuspendCount(JDWP::ObjectId thread_id, JDWP::ExpandBuf* pReply);
+  static JDWP::JdwpError GetThreadStatus(JDWP::ObjectId thread_id,
+                                         JDWP::JdwpThreadStatus* pThreadStatus,
+                                         JDWP::JdwpSuspendStatus* pSuspendStatus)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_);
+  static JDWP::JdwpError GetThreadDebugSuspendCount(JDWP::ObjectId thread_id,
+                                                    JDWP::ExpandBuf* pReply)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                     Locks::thread_suspend_count_lock_);
   // static void WaitForSuspend(JDWP::ObjectId thread_id);
 
   // Fills 'thread_ids' with the threads in the given thread group. If thread_group_id == 0,
@@ -321,9 +331,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void GetChildThreadGroups(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& child_thread_group_ids);
 
-  static JDWP::JdwpError GetThreadFrameCount(JDWP::ObjectId thread_id, size_t& result);
+  static JDWP::JdwpError GetThreadFrameCount(JDWP::ObjectId thread_id, size_t& result)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_);
   static JDWP::JdwpError GetThreadFrames(JDWP::ObjectId thread_id, size_t start_frame,
                                          size_t frame_count, JDWP::ExpandBuf* buf)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static JDWP::ObjectId GetThreadSelfId()
@@ -350,12 +362,15 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void GetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame_id, int slot,
                             JDWP::JdwpTag tag, uint8_t* buf, size_t expectedLen)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void SetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame_id, int slot,
                             JDWP::JdwpTag tag, uint64_t value, size_t width)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static JDWP::JdwpError Interrupt(JDWP::ObjectId thread_id);
+  static JDWP::JdwpError Interrupt(JDWP::ObjectId thread_id)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_);
 
   /*
    * Debugger notification
@@ -413,6 +428,7 @@
                                        JDWP::JdwpStepDepth depth)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void UnconfigureStep(JDWP::ObjectId thread_id)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static JDWP::JdwpError InvokeMethod(JDWP::ObjectId thread_id, JDWP::ObjectId object_id,
@@ -431,7 +447,8 @@
    */
   static void DdmSendThreadNotification(Thread* t, uint32_t type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void DdmSetThreadNotification(bool enable);
+  static void DdmSetThreadNotification(bool enable)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_);
   static bool DdmHandlePacket(JDWP::Request& request, uint8_t** pReplyBuf, int* pReplyLen);
   static void DdmConnected() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void DdmDisconnected() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -446,17 +463,21 @@
    * Recent allocation tracking support.
    */
   static void RecordAllocation(mirror::Class* type, size_t byte_count)
+      LOCKS_EXCLUDED(alloc_tracker_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void SetAllocTrackingEnabled(bool enabled);
+  static void SetAllocTrackingEnabled(bool enabled) LOCKS_EXCLUDED(alloc_tracker_lock_);
   static bool IsAllocTrackingEnabled() {
     return recent_allocation_records_ != nullptr;
   }
-  static jbyteArray GetRecentAllocations() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static jbyteArray GetRecentAllocations()
+      LOCKS_EXCLUDED(alloc_tracker_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static size_t HeadIndex() EXCLUSIVE_LOCKS_REQUIRED(alloc_tracker_lock_);
-  static void DumpRecentAllocations();
+  static void DumpRecentAllocations() LOCKS_EXCLUDED(alloc_tracker_lock_);
 
   // Updates the stored direct object pointers (called from SweepSystemWeaks).
   static void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
+      LOCKS_EXCLUDED(alloc_tracker_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   enum HpifWhen {
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index fe33806..4de46e3 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -978,7 +978,11 @@
       !check_section_name(all, 11, ".debug_str")) {
     return;
   }
-
+#ifdef __LP64__
+  if (true) {
+    return;  // No ELF debug support in 64bit.
+  }
+#endif
   // This is not needed if we have no .text segment.
   uint32_t text_start_addr = 0;
   for (uint32_t i = 0; i < segments_.size(); i++) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 08de95f..31a5728 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -434,38 +434,7 @@
                                uint32_t shorty_len, ShadowFrame* sf, size_t first_arg_reg) :
     QuickArgumentVisitor(sp, is_static, shorty, shorty_len), sf_(sf), cur_reg_(first_arg_reg) {}
 
-  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
-    Primitive::Type type = GetParamPrimitiveType();
-    switch (type) {
-      case Primitive::kPrimLong:  // Fall-through.
-      case Primitive::kPrimDouble:
-        if (IsSplitLongOrDouble()) {
-          sf_->SetVRegLong(cur_reg_, ReadSplitLongParam());
-        } else {
-          sf_->SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress()));
-        }
-        ++cur_reg_;
-        break;
-      case Primitive::kPrimNot: {
-          StackReference<mirror::Object>* stack_ref =
-              reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
-          sf_->SetVRegReference(cur_reg_, stack_ref->AsMirrorPtr());
-        }
-        break;
-      case Primitive::kPrimBoolean:  // Fall-through.
-      case Primitive::kPrimByte:     // Fall-through.
-      case Primitive::kPrimChar:     // Fall-through.
-      case Primitive::kPrimShort:    // Fall-through.
-      case Primitive::kPrimInt:      // Fall-through.
-      case Primitive::kPrimFloat:
-        sf_->SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress()));
-        break;
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "UNREACHABLE";
-        break;
-    }
-    ++cur_reg_;
-  }
+  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
 
  private:
   ShadowFrame* const sf_;
@@ -474,6 +443,39 @@
   DISALLOW_COPY_AND_ASSIGN(BuildQuickShadowFrameVisitor);
 };
 
+void BuildQuickShadowFrameVisitor::Visit()  {
+  Primitive::Type type = GetParamPrimitiveType();
+  switch (type) {
+    case Primitive::kPrimLong:  // Fall-through.
+    case Primitive::kPrimDouble:
+      if (IsSplitLongOrDouble()) {
+        sf_->SetVRegLong(cur_reg_, ReadSplitLongParam());
+      } else {
+        sf_->SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress()));
+      }
+      ++cur_reg_;
+      break;
+    case Primitive::kPrimNot: {
+        StackReference<mirror::Object>* stack_ref =
+            reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+        sf_->SetVRegReference(cur_reg_, stack_ref->AsMirrorPtr());
+      }
+      break;
+    case Primitive::kPrimBoolean:  // Fall-through.
+    case Primitive::kPrimByte:     // Fall-through.
+    case Primitive::kPrimChar:     // Fall-through.
+    case Primitive::kPrimShort:    // Fall-through.
+    case Primitive::kPrimInt:      // Fall-through.
+    case Primitive::kPrimFloat:
+      sf_->SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress()));
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "UNREACHABLE";
+      break;
+  }
+  ++cur_reg_;
+}
+
 extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Thread* self,
                                                 mirror::ArtMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -532,56 +534,61 @@
                             std::vector<jvalue>* args) :
     QuickArgumentVisitor(sp, is_static, shorty, shorty_len), soa_(soa), args_(args) {}
 
-  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
-    jvalue val;
-    Primitive::Type type = GetParamPrimitiveType();
-    switch (type) {
-      case Primitive::kPrimNot: {
-        StackReference<mirror::Object>* stack_ref =
-            reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
-        val.l = soa_->AddLocalReference<jobject>(stack_ref->AsMirrorPtr());
-        references_.push_back(std::make_pair(val.l, stack_ref));
-        break;
-      }
-      case Primitive::kPrimLong:  // Fall-through.
-      case Primitive::kPrimDouble:
-        if (IsSplitLongOrDouble()) {
-          val.j = ReadSplitLongParam();
-        } else {
-          val.j = *reinterpret_cast<jlong*>(GetParamAddress());
-        }
-        break;
-      case Primitive::kPrimBoolean:  // Fall-through.
-      case Primitive::kPrimByte:     // Fall-through.
-      case Primitive::kPrimChar:     // Fall-through.
-      case Primitive::kPrimShort:    // Fall-through.
-      case Primitive::kPrimInt:      // Fall-through.
-      case Primitive::kPrimFloat:
-        val.i = *reinterpret_cast<jint*>(GetParamAddress());
-        break;
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "UNREACHABLE";
-        val.j = 0;
-        break;
-    }
-    args_->push_back(val);
-  }
+  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
 
-  void FixupReferences() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Fixup any references which may have changed.
-    for (const auto& pair : references_) {
-      pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
-    }
-  }
+  void FixupReferences() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  ScopedObjectAccessUnchecked* soa_;
-  std::vector<jvalue>* args_;
+  ScopedObjectAccessUnchecked* const soa_;
+  std::vector<jvalue>* const args_;
   // References which we must update when exiting in case the GC moved the objects.
   std::vector<std::pair<jobject, StackReference<mirror::Object>*> > references_;
+
   DISALLOW_COPY_AND_ASSIGN(BuildQuickArgumentVisitor);
 };
 
+void BuildQuickArgumentVisitor::Visit() {
+  jvalue val;
+  Primitive::Type type = GetParamPrimitiveType();
+  switch (type) {
+    case Primitive::kPrimNot: {
+      StackReference<mirror::Object>* stack_ref =
+          reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+      val.l = soa_->AddLocalReference<jobject>(stack_ref->AsMirrorPtr());
+      references_.push_back(std::make_pair(val.l, stack_ref));
+      break;
+    }
+    case Primitive::kPrimLong:  // Fall-through.
+    case Primitive::kPrimDouble:
+      if (IsSplitLongOrDouble()) {
+        val.j = ReadSplitLongParam();
+      } else {
+        val.j = *reinterpret_cast<jlong*>(GetParamAddress());
+      }
+      break;
+    case Primitive::kPrimBoolean:  // Fall-through.
+    case Primitive::kPrimByte:     // Fall-through.
+    case Primitive::kPrimChar:     // Fall-through.
+    case Primitive::kPrimShort:    // Fall-through.
+    case Primitive::kPrimInt:      // Fall-through.
+    case Primitive::kPrimFloat:
+      val.i = *reinterpret_cast<jint*>(GetParamAddress());
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "UNREACHABLE";
+      val.j = 0;
+      break;
+  }
+  args_->push_back(val);
+}
+
+void BuildQuickArgumentVisitor::FixupReferences() {
+  // Fixup any references which may have changed.
+  for (const auto& pair : references_) {
+    pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+  }
+}
+
 // Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
 // which is responsible for recording callee save registers. We explicitly place into jobjects the
 // incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
@@ -644,30 +651,35 @@
                                uint32_t shorty_len, ScopedObjectAccessUnchecked* soa) :
     QuickArgumentVisitor(sp, is_static, shorty, shorty_len), soa_(soa) {}
 
-  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
-    if (IsParamAReference()) {
-      StackReference<mirror::Object>* stack_ref =
-          reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
-      jobject reference =
-          soa_->AddLocalReference<jobject>(stack_ref->AsMirrorPtr());
-      references_.push_back(std::make_pair(reference, stack_ref));
-    }
-  }
+  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
 
-  void FixupReferences() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Fixup any references which may have changed.
-    for (const auto& pair : references_) {
-      pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
-    }
-  }
+  void FixupReferences() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  ScopedObjectAccessUnchecked* soa_;
+  ScopedObjectAccessUnchecked* const soa_;
   // References which we must update when exiting in case the GC moved the objects.
   std::vector<std::pair<jobject, StackReference<mirror::Object>*> > references_;
   DISALLOW_COPY_AND_ASSIGN(RememberForGcArgumentVisitor);
 };
 
+void RememberForGcArgumentVisitor::Visit() {
+  if (IsParamAReference()) {
+    StackReference<mirror::Object>* stack_ref =
+        reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+    jobject reference =
+        soa_->AddLocalReference<jobject>(stack_ref->AsMirrorPtr());
+    references_.push_back(std::make_pair(reference, stack_ref));
+  }
+}
+
+void RememberForGcArgumentVisitor::FixupReferences() {
+  // Fixup any references which may have changed.
+  for (const auto& pair : references_) {
+    pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+  }
+}
+
+
 // Lazily resolve a method for quick. Called by stub code.
 extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
                                                     mirror::Object* receiver,
@@ -856,9 +868,10 @@
  *
  * void PushStack(uintptr_t): Push a value to the stack.
  *
- * uintptr_t PushSirt(mirror::Object* ref): Add a reference to the Sirt. Is guaranteed != nullptr.
+ * uintptr_t PushSirt(mirror::Object* ref): Add a reference to the Sirt. This _will_ have nullptr,
+ *                                          as this might be important for null initialization.
  *                                          Must return the jobject, that is, the reference to the
- *                                          entry in the Sirt.
+ *                                          entry in the Sirt (nullptr if necessary).
  *
  */
 template <class T> class BuildGenericJniFrameStateMachine {
@@ -948,12 +961,7 @@
   }
 
   void AdvanceSirt(mirror::Object* ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    uintptr_t sirtRef;
-    if (ptr != nullptr) {
-      sirtRef = PushSirt(ptr);
-    } else {
-      sirtRef = reinterpret_cast<uintptr_t>(nullptr);
-    }
+    uintptr_t sirtRef = PushSirt(ptr);
     if (HaveSirtGpr()) {
       gpr_index_--;
       PushGpr(sirtRef);
@@ -1155,49 +1163,49 @@
  public:
   ComputeGenericJniFrameSize() : num_sirt_references_(0), num_stack_entries_(0) {}
 
-  // (negative) offset from SP to top of Sirt.
-  uint32_t GetSirtOffset() {
-    return 8;
-  }
-
-  uint32_t GetFirstSirtEntryOffset() {
-    return GetSirtOffset() + sizeof(StackReference<mirror::Object>);
-  }
-
-  uint32_t GetNumSirtReferences() {
-    return num_sirt_references_;
-  }
-
   uint32_t GetStackSize() {
     return num_stack_entries_ * sizeof(uintptr_t);
   }
 
-  void ComputeLayout(bool is_static, const char* shorty, uint32_t shorty_len, void* sp,
-                     StackReference<mirror::Object>** start_sirt, StackIndirectReferenceTable** table,
-                     uint32_t* sirt_entries, uintptr_t** start_stack, uintptr_t** start_gpr,
-                     uint32_t** start_fpr, void** code_return, size_t* overall_size)
+  // WARNING: After this, *sp won't be pointing to the method anymore!
+  void ComputeLayout(mirror::ArtMethod*** m, bool is_static, const char* shorty, uint32_t shorty_len,
+                     void* sp, StackIndirectReferenceTable** table, uint32_t* sirt_entries,
+                     uintptr_t** start_stack, uintptr_t** start_gpr, uint32_t** start_fpr,
+                     void** code_return, size_t* overall_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ComputeAll(is_static, shorty, shorty_len);
 
+    mirror::ArtMethod* method = **m;
+
     uint8_t* sp8 = reinterpret_cast<uint8_t*>(sp);
-    *start_sirt = reinterpret_cast<StackReference<mirror::Object>*>(sp8-GetFirstSirtEntryOffset());
 
-    // Add padding entries if necessary for alignment.
-    if (sizeof(uintptr_t) < sizeof(uint64_t)) {
-      uint32_t size = sizeof(uintptr_t) * num_sirt_references_;
-      uint32_t rem = size % 8;
-      if (rem != 0) {
-        DCHECK_EQ(rem, 4U);
-        num_sirt_references_++;
-      }
-    }
+    // First, fix up the layout of the callee-save frame.
+    // We have to squeeze in the Sirt, and relocate the method pointer.
+
+    // "Free" the slot for the method.
+    sp8 += kPointerSize;
+
+    // Add the Sirt.
     *sirt_entries = num_sirt_references_;
-    size_t sirt_size = StackIndirectReferenceTable::SizeOf(num_sirt_references_);
-    sp8 -= GetSirtOffset() + sirt_size;
+    size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSize(num_sirt_references_);
+    sp8 -= sirt_size;
     *table = reinterpret_cast<StackIndirectReferenceTable*>(sp8);
+    (*table)->SetNumberOfReferences(num_sirt_references_);
 
+    // Add a slot for the method pointer, and fill it. Fix the pointer-pointer given to us.
+    sp8 -= kPointerSize;
+    uint8_t* method_pointer = sp8;
+    *(reinterpret_cast<mirror::ArtMethod**>(method_pointer)) = method;
+    *m = reinterpret_cast<mirror::ArtMethod**>(method_pointer);
+
+    // Reference cookie and padding
+    sp8 -= 8;
+    // Store Sirt size
+    *reinterpret_cast<uint32_t*>(sp8) = static_cast<uint32_t>(sirt_size & 0xFFFFFFFF);
+
+    // Next comes the native call stack.
     sp8 -= GetStackSize();
-    // Now align the call stack under the Sirt. This aligns by 16.
+    // Now align the call stack below. This aligns by 16, as AArch64 seems to require.
     uintptr_t mask = ~0x0F;
     sp8 = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(sp8) & mask);
     *start_stack = reinterpret_cast<uintptr_t*>(sp8);
@@ -1212,10 +1220,14 @@
     *start_gpr = reinterpret_cast<uintptr_t*>(sp8);
 
     // reserve space for the code pointer
-    sp8 -= sizeof(void*);
+    sp8 -= kPointerSize;
     *code_return = reinterpret_cast<void*>(sp8);
 
     *overall_size = reinterpret_cast<uint8_t*>(sp) - sp8;
+
+    // The new SP is stored at the end of the alloca, so it can be immediately popped
+    sp8 = reinterpret_cast<uint8_t*>(sp) - 5 * KB;
+    *(reinterpret_cast<uint8_t**>(sp8)) = method_pointer;
   }
 
   void ComputeSirtOffset() { }  // nothing to do, static right now
@@ -1291,85 +1303,30 @@
 // of transitioning into native code.
 class BuildGenericJniFrameVisitor FINAL : public QuickArgumentVisitor {
  public:
-  BuildGenericJniFrameVisitor(mirror::ArtMethod** sp, bool is_static, const char* shorty,
+  BuildGenericJniFrameVisitor(mirror::ArtMethod*** sp, bool is_static, const char* shorty,
                               uint32_t shorty_len, Thread* self) :
-      QuickArgumentVisitor(sp, is_static, shorty, shorty_len), sm_(this) {
+      QuickArgumentVisitor(*sp, is_static, shorty, shorty_len), sm_(this) {
     ComputeGenericJniFrameSize fsc;
-    fsc.ComputeLayout(is_static, shorty, shorty_len, sp, &cur_sirt_entry_, &sirt_,
-                      &sirt_expected_refs_, &cur_stack_arg_, &cur_gpr_reg_, &cur_fpr_reg_,
-                      &code_return_, &alloca_used_size_);
+    fsc.ComputeLayout(sp, is_static, shorty, shorty_len, *sp, &sirt_, &sirt_expected_refs_,
+                      &cur_stack_arg_, &cur_gpr_reg_, &cur_fpr_reg_, &code_return_,
+                      &alloca_used_size_);
     sirt_number_of_references_ = 0;
-    top_of_sirt_ = cur_sirt_entry_;
+    cur_sirt_entry_ = reinterpret_cast<StackReference<mirror::Object>*>(GetFirstSirtEntry());
 
     // jni environment is always first argument
     sm_.AdvancePointer(self->GetJniEnv());
 
     if (is_static) {
-      sm_.AdvanceSirt((*sp)->GetDeclaringClass());
+      sm_.AdvanceSirt((**sp)->GetDeclaringClass());
     }
   }
 
-  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
-    Primitive::Type type = GetParamPrimitiveType();
-    switch (type) {
-      case Primitive::kPrimLong: {
-        jlong long_arg;
-        if (IsSplitLongOrDouble()) {
-          long_arg = ReadSplitLongParam();
-        } else {
-          long_arg = *reinterpret_cast<jlong*>(GetParamAddress());
-        }
-        sm_.AdvanceLong(long_arg);
-        break;
-      }
-      case Primitive::kPrimDouble: {
-        uint64_t double_arg;
-        if (IsSplitLongOrDouble()) {
-          // Read into union so that we don't case to a double.
-          double_arg = ReadSplitLongParam();
-        } else {
-          double_arg = *reinterpret_cast<uint64_t*>(GetParamAddress());
-        }
-        sm_.AdvanceDouble(double_arg);
-        break;
-      }
-      case Primitive::kPrimNot: {
-        StackReference<mirror::Object>* stack_ref =
-            reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
-        sm_.AdvanceSirt(stack_ref->AsMirrorPtr());
-        break;
-      }
-      case Primitive::kPrimFloat:
-        sm_.AdvanceFloat(*reinterpret_cast<float*>(GetParamAddress()));
-        break;
-      case Primitive::kPrimBoolean:  // Fall-through.
-      case Primitive::kPrimByte:     // Fall-through.
-      case Primitive::kPrimChar:     // Fall-through.
-      case Primitive::kPrimShort:    // Fall-through.
-      case Primitive::kPrimInt:      // Fall-through.
-        sm_.AdvanceInt(*reinterpret_cast<jint*>(GetParamAddress()));
-        break;
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "UNREACHABLE";
-        break;
-    }
-  }
+  void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
 
-  void FinalizeSirt(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Initialize padding entries.
-    while (sirt_number_of_references_ < sirt_expected_refs_) {
-      *cur_sirt_entry_ = StackReference<mirror::Object>();
-      cur_sirt_entry_--;
-      sirt_number_of_references_++;
-    }
-    sirt_->SetNumberOfReferences(sirt_expected_refs_);
-    DCHECK_NE(sirt_expected_refs_, 0U);
-    // Install Sirt.
-    self->PushSirt(sirt_);
-  }
+  void FinalizeSirt(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  jobject GetFirstSirtEntry() {
-    return reinterpret_cast<jobject>(top_of_sirt_);
+  jobject GetFirstSirtEntry() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return reinterpret_cast<jobject>(sirt_->GetStackReference(0));
   }
 
   void PushGpr(uintptr_t val) {
@@ -1394,9 +1351,15 @@
   }
 
   uintptr_t PushSirt(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    *cur_sirt_entry_ = StackReference<mirror::Object>::FromMirrorPtr(ref);
-    uintptr_t tmp = reinterpret_cast<uintptr_t>(cur_sirt_entry_);
-    cur_sirt_entry_--;
+    uintptr_t tmp;
+    if (ref == nullptr) {
+      *cur_sirt_entry_ = StackReference<mirror::Object>();
+      tmp = reinterpret_cast<uintptr_t>(nullptr);
+    } else {
+      *cur_sirt_entry_ = StackReference<mirror::Object>::FromMirrorPtr(ref);
+      tmp = reinterpret_cast<uintptr_t>(cur_sirt_entry_);
+    }
+    cur_sirt_entry_++;
     sirt_number_of_references_++;
     return tmp;
   }
@@ -1418,7 +1381,7 @@
   uintptr_t* cur_gpr_reg_;
   uint32_t* cur_fpr_reg_;
   uintptr_t* cur_stack_arg_;
-  StackReference<mirror::Object>* top_of_sirt_;
+  // StackReference<mirror::Object>* top_of_sirt_;
   void* code_return_;
   size_t alloca_used_size_;
 
@@ -1427,25 +1390,86 @@
   DISALLOW_COPY_AND_ASSIGN(BuildGenericJniFrameVisitor);
 };
 
+void BuildGenericJniFrameVisitor::Visit() {
+  Primitive::Type type = GetParamPrimitiveType();
+  switch (type) {
+    case Primitive::kPrimLong: {
+      jlong long_arg;
+      if (IsSplitLongOrDouble()) {
+        long_arg = ReadSplitLongParam();
+      } else {
+        long_arg = *reinterpret_cast<jlong*>(GetParamAddress());
+      }
+      sm_.AdvanceLong(long_arg);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      uint64_t double_arg;
+      if (IsSplitLongOrDouble()) {
+        // Read into union so that we don't case to a double.
+        double_arg = ReadSplitLongParam();
+      } else {
+        double_arg = *reinterpret_cast<uint64_t*>(GetParamAddress());
+      }
+      sm_.AdvanceDouble(double_arg);
+      break;
+    }
+    case Primitive::kPrimNot: {
+      StackReference<mirror::Object>* stack_ref =
+          reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+      sm_.AdvanceSirt(stack_ref->AsMirrorPtr());
+      break;
+    }
+    case Primitive::kPrimFloat:
+      sm_.AdvanceFloat(*reinterpret_cast<float*>(GetParamAddress()));
+      break;
+    case Primitive::kPrimBoolean:  // Fall-through.
+    case Primitive::kPrimByte:     // Fall-through.
+    case Primitive::kPrimChar:     // Fall-through.
+    case Primitive::kPrimShort:    // Fall-through.
+    case Primitive::kPrimInt:      // Fall-through.
+      sm_.AdvanceInt(*reinterpret_cast<jint*>(GetParamAddress()));
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "UNREACHABLE";
+      break;
+  }
+}
+
+void BuildGenericJniFrameVisitor::FinalizeSirt(Thread* self) {
+  // Initialize padding entries.
+  while (sirt_number_of_references_ < sirt_expected_refs_) {
+    *cur_sirt_entry_ = StackReference<mirror::Object>();
+    cur_sirt_entry_++;
+    sirt_number_of_references_++;
+  }
+  sirt_->SetNumberOfReferences(sirt_expected_refs_);
+  DCHECK_NE(sirt_expected_refs_, 0U);
+  // Install Sirt.
+  self->PushSirt(sirt_);
+}
+
 /*
  * Initializes an alloca region assumed to be directly below sp for a native call:
  * Create a Sirt and call stack and fill a mini stack with values to be pushed to registers.
  * The final element on the stack is a pointer to the native code.
  *
+ * On entry, the stack has a standard callee-save frame above sp, and an alloca below it.
+ * We need to fix this, as the Sirt needs to go into the callee-save frame.
+ *
  * The return of this function denotes:
  * 1) How many bytes of the alloca can be released, if the value is non-negative.
  * 2) An error, if the value is negative.
  */
 extern "C" ssize_t artQuickGenericJniTrampoline(Thread* self, mirror::ArtMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  uint32_t* sp32 = reinterpret_cast<uint32_t*>(sp);
   mirror::ArtMethod* called = *sp;
-  DCHECK(called->IsNative());
+  DCHECK(called->IsNative()) << PrettyMethod(called, true);
 
   // run the visitor
   MethodHelper mh(called);
 
-  BuildGenericJniFrameVisitor visitor(sp, called->IsStatic(), mh.GetShorty(), mh.GetShortyLength(),
+  BuildGenericJniFrameVisitor visitor(&sp, called->IsStatic(), mh.GetShorty(), mh.GetShortyLength(),
                                       self);
   visitor.VisitArguments();
   visitor.FinalizeSirt(self);
@@ -1462,11 +1486,14 @@
     if (self->IsExceptionPending()) {
       self->PopSirt();
       // A negative value denotes an error.
+      // TODO: Do we still need to fix the stack pointer? I think so. Then it's necessary to push
+      //       that value!
       return -1;
     }
   } else {
     cookie = JniMethodStart(self);
   }
+  uint32_t* sp32 = reinterpret_cast<uint32_t*>(sp);
   *(sp32 - 1) = cookie;
 
   // retrieve native code
@@ -1480,8 +1507,8 @@
   size_t window_size = visitor.GetAllocaUsedSize();
   *code_pointer = reinterpret_cast<uintptr_t>(nativeCode);
 
-  // 5K reserved, window_size used.
-  return (5 * KB) - window_size;
+  // 5K reserved, window_size + frame pointer used.
+  return (5 * KB) - window_size - kPointerSize;
 }
 
 /*
@@ -1501,10 +1528,10 @@
   if (return_shorty_char == 'L') {
     // the only special ending call
     if (called->IsSynchronized()) {
-      ComputeGenericJniFrameSize fsc;
-      fsc.ComputeSirtOffset();
-      uint32_t offset = fsc.GetFirstSirtEntryOffset();
-      jobject tmp = reinterpret_cast<jobject>(reinterpret_cast<uint8_t*>(sp) - offset);
+      StackIndirectReferenceTable* table =
+          reinterpret_cast<StackIndirectReferenceTable*>(
+              reinterpret_cast<uint8_t*>(sp) + kPointerSize);
+      jobject tmp = reinterpret_cast<jobject>(table->GetStackReference(0));
 
       return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceSynchronized(result.l, cookie, tmp,
                                                                               self));
@@ -1513,10 +1540,10 @@
     }
   } else {
     if (called->IsSynchronized()) {
-      ComputeGenericJniFrameSize fsc;
-      fsc.ComputeSirtOffset();
-      uint32_t offset = fsc.GetFirstSirtEntryOffset();
-      jobject tmp = reinterpret_cast<jobject>(reinterpret_cast<uint8_t*>(sp) - offset);
+      StackIndirectReferenceTable* table =
+          reinterpret_cast<StackIndirectReferenceTable*>(
+              reinterpret_cast<uint8_t*>(sp) + kPointerSize);
+      jobject tmp = reinterpret_cast<jobject>(table->GetStackReference(0));
 
       JniMethodEndSynchronized(cookie, tmp, self);
     } else {
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 5e3f504..4a75152 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -76,7 +76,7 @@
 
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
-    method_f_->SetFrameSizeInBytes(kStackAlignment);
+    method_f_->SetFrameSizeInBytes(4 * kPointerSize);
     method_f_->SetEntryPointFromQuickCompiledCode(&fake_code_[sizeof(code_size)]);
     method_f_->SetMappingTable(&fake_mapping_data_.GetData()[0]);
     method_f_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]);
@@ -84,7 +84,7 @@
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
-    method_g_->SetFrameSizeInBytes(kStackAlignment);
+    method_g_->SetFrameSizeInBytes(4 * kPointerSize);
     method_g_->SetEntryPointFromQuickCompiledCode(&fake_code_[sizeof(code_size)]);
     method_g_->SetMappingTable(&fake_mapping_data_.GetData()[0]);
     method_g_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]);
@@ -151,7 +151,7 @@
 
   std::vector<uintptr_t> fake_stack;
   ASSERT_EQ(kStackAlignment, 16U);
-  ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
+  // ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
 
   if (!kUsePortableCompiler) {
     // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index e13bd71..ace9f9e 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -48,8 +48,8 @@
       bulk_free_lock_("rosalloc bulk free lock", kRosAllocBulkFreeLock),
       page_release_mode_(page_release_mode),
       page_release_size_threshold_(page_release_size_threshold) {
-  DCHECK(RoundUp(capacity, kPageSize) == capacity);
-  DCHECK(RoundUp(max_capacity, kPageSize) == max_capacity);
+  DCHECK_EQ(RoundUp(capacity, kPageSize), capacity);
+  DCHECK_EQ(RoundUp(max_capacity, kPageSize), max_capacity);
   CHECK_LE(capacity, max_capacity);
   CHECK(IsAligned<kPageSize>(page_release_size_threshold_));
   if (!initialized_) {
@@ -151,7 +151,7 @@
     if (it != free_page_runs_.rend() && (last_free_page_run = *it)->End(this) == base_ + footprint_) {
       // There is a free page run at the end.
       DCHECK(last_free_page_run->IsFree());
-      DCHECK(page_map_[ToPageMapIndex(last_free_page_run)] == kPageMapEmpty);
+      DCHECK_EQ(page_map_[ToPageMapIndex(last_free_page_run)], kPageMapEmpty);
       last_free_page_run_size = last_free_page_run->ByteSize(this);
     } else {
       // There is no free page run at the end.
@@ -176,7 +176,7 @@
         DCHECK_EQ(last_free_page_run_size, last_free_page_run->ByteSize(this));
         last_free_page_run->SetByteSize(this, last_free_page_run_size + increment);
         DCHECK_EQ(last_free_page_run->ByteSize(this) % kPageSize, static_cast<size_t>(0));
-        DCHECK(last_free_page_run->End(this) == base_ + new_footprint);
+        DCHECK_EQ(last_free_page_run->End(this), base_ + new_footprint);
       } else {
         // Otherwise, insert a new free page run at the end.
         FreePageRun* new_free_page_run = reinterpret_cast<FreePageRun*>(base_ + footprint_);
@@ -186,7 +186,7 @@
         new_free_page_run->SetByteSize(this, increment);
         DCHECK_EQ(new_free_page_run->ByteSize(this) % kPageSize, static_cast<size_t>(0));
         free_page_runs_.insert(new_free_page_run);
-        DCHECK(*free_page_runs_.rbegin() == new_free_page_run);
+        DCHECK_EQ(*free_page_runs_.rbegin(), new_free_page_run);
         if (kTraceRosAlloc) {
           LOG(INFO) << "RosAlloc::AlloPages() : Grew the heap by inserting run 0x"
                     << std::hex << reinterpret_cast<intptr_t>(new_free_page_run)
@@ -240,7 +240,7 @@
     // Update the page map.
     size_t page_map_idx = ToPageMapIndex(res);
     for (size_t i = 0; i < num_pages; i++) {
-      DCHECK(page_map_[page_map_idx + i] == kPageMapEmpty);
+      DCHECK_EQ(page_map_[page_map_idx + i], kPageMapEmpty);
     }
     switch (page_map_type) {
     case kPageMapRun:
@@ -282,7 +282,7 @@
 void RosAlloc::FreePages(Thread* self, void* ptr) {
   lock_.AssertHeld(self);
   size_t pm_idx = ToPageMapIndex(ptr);
-  DCHECK(pm_idx < page_map_size_);
+  DCHECK_LT(pm_idx, page_map_size_);
   byte pm_type = page_map_[pm_idx];
   DCHECK(pm_type == kPageMapRun || pm_type == kPageMapLargeObject);
   byte pm_part_type;
@@ -425,7 +425,7 @@
 }
 
 void* RosAlloc::AllocLargeObject(Thread* self, size_t size, size_t* bytes_allocated) {
-  DCHECK(size > kLargeSizeThreshold);
+  DCHECK_GT(size, kLargeSizeThreshold);
   size_t num_pages = RoundUp(size, kPageSize) / kPageSize;
   void* r;
   {
@@ -461,13 +461,14 @@
 }
 
 void RosAlloc::FreeInternal(Thread* self, void* ptr) {
-  DCHECK(base_ <= ptr && ptr < base_ + footprint_);
+  DCHECK_LE(base_, ptr);
+  DCHECK_LT(ptr, base_ + footprint_);
   size_t pm_idx = RoundDownToPageMapIndex(ptr);
   bool free_from_run = false;
   Run* run = NULL;
   {
     MutexLock mu(self, lock_);
-    DCHECK(pm_idx < page_map_size_);
+    DCHECK_LT(pm_idx, page_map_size_);
     byte page_map_entry = page_map_[pm_idx];
     if (kTraceRosAlloc) {
       LOG(INFO) << "RosAlloc::FreeInternal() : " << std::hex << ptr << ", pm_idx=" << std::dec << pm_idx
@@ -491,11 +492,11 @@
         // Find the beginning of the run.
         while (page_map_[pi] != kPageMapRun) {
           pi--;
-          DCHECK(pi < capacity_ / kPageSize);
+          DCHECK_LT(pi, capacity_ / kPageSize);
         }
-        DCHECK(page_map_[pi] == kPageMapRun);
+        DCHECK_EQ(page_map_[pi], kPageMapRun);
         run = reinterpret_cast<Run*>(base_ + pi * kPageSize);
-        DCHECK(run->magic_num_ == kMagicNum);
+        DCHECK_EQ(run->magic_num_, kMagicNum);
         break;
       }
       default:
@@ -551,13 +552,13 @@
 }
 
 void* RosAlloc::AllocFromRun(Thread* self, size_t size, size_t* bytes_allocated) {
-  DCHECK(size <= kLargeSizeThreshold);
+  DCHECK_LE(size, kLargeSizeThreshold);
   size_t bracket_size;
   size_t idx = SizeToIndexAndBracketSize(size, &bracket_size);
   DCHECK_EQ(idx, SizeToIndex(size));
   DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
   DCHECK_EQ(bracket_size, bracketSizes[idx]);
-  DCHECK(size <= bracket_size);
+  DCHECK_LE(size, bracket_size);
   DCHECK(size > 512 || bracket_size - size < 16);
 
   void* slot_addr;
@@ -693,8 +694,9 @@
 }
 
 void RosAlloc::FreeFromRun(Thread* self, void* ptr, Run* run) {
-  DCHECK(run->magic_num_ == kMagicNum);
-  DCHECK(run < ptr && ptr < run->End());
+  DCHECK_EQ(run->magic_num_, kMagicNum);
+  DCHECK_LT(run, ptr);
+  DCHECK_LT(ptr, run->End());
   size_t idx = run->size_bracket_idx_;
   MutexLock mu(self, *size_bracket_locks_[idx]);
   bool run_was_full = false;
@@ -858,11 +860,11 @@
       - (reinterpret_cast<byte*>(this) + headerSizes[idx]);
   DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0));
   size_t slot_idx = offset_from_slot_base / bracketSizes[idx];
-  DCHECK(slot_idx < numOfSlots[idx]);
+  DCHECK_LT(slot_idx, numOfSlots[idx]);
   size_t vec_idx = slot_idx / 32;
   if (kIsDebugBuild) {
     size_t num_vec = RoundUp(numOfSlots[idx], 32) / 32;
-    DCHECK(vec_idx < num_vec);
+    DCHECK_LT(vec_idx, num_vec);
   }
   size_t vec_off = slot_idx % 32;
   uint32_t* vec = &alloc_bit_map_[vec_idx];
@@ -960,11 +962,11 @@
       - (reinterpret_cast<byte*>(this) + headerSizes[idx]);
   DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0));
   size_t slot_idx = offset_from_slot_base / bracketSizes[idx];
-  DCHECK(slot_idx < numOfSlots[idx]);
+  DCHECK_LT(slot_idx, numOfSlots[idx]);
   size_t vec_idx = slot_idx / 32;
   if (kIsDebugBuild) {
     size_t num_vec = RoundUp(numOfSlots[idx], 32) / 32;
-    DCHECK(vec_idx < num_vec);
+    DCHECK_LT(vec_idx, num_vec);
   }
   size_t vec_off = slot_idx % 32;
   uint32_t* vec = &free_bit_map_base[vec_idx];
@@ -997,11 +999,13 @@
   size_t num_vec = RoundUp(num_slots, 32) / 32;
   size_t slots = 0;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
-    DCHECK(num_slots >= slots);
+    DCHECK_GE(num_slots, slots);
     uint32_t vec = alloc_bit_map_[v];
     uint32_t mask = (num_slots - slots >= 32) ? static_cast<uint32_t>(-1)
         : (1 << (num_slots - slots)) - 1;
-    DCHECK(num_slots - slots >= 32 ? mask == static_cast<uint32_t>(-1) : true);
+    if ((num_slots - slots) >= 32) {
+      DCHECK_EQ(mask, static_cast<uint32_t>(-1));
+    }
     if (vec != mask) {
       return false;
     }
@@ -1052,7 +1056,7 @@
   size_t num_vec = RoundUp(num_slots, 32) / 32;
   size_t slots = 0;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
-    DCHECK(num_slots >= slots);
+    DCHECK_GE(num_slots, slots);
     uint32_t vec = alloc_bit_map_[v];
     size_t end = std::min(num_slots - slots, static_cast<size_t>(32));
     for (size_t i = 0; i < end; ++i) {
@@ -1094,7 +1098,8 @@
   for (size_t i = 0; i < num_ptrs; i++) {
     void* ptr = ptrs[i];
     ptrs[i] = NULL;
-    DCHECK(base_ <= ptr && ptr < base_ + footprint_);
+    DCHECK_LE(base_, ptr);
+    DCHECK_LT(ptr, base_ + footprint_);
     size_t pm_idx = RoundDownToPageMapIndex(ptr);
     Run* run = NULL;
     if (kReadPageMapEntryWithoutLockInBulkFree) {
@@ -1107,18 +1112,18 @@
       }
       if (LIKELY(page_map_entry == kPageMapRun)) {
         run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
-        DCHECK(run->magic_num_ == kMagicNum);
+        DCHECK_EQ(run->magic_num_, kMagicNum);
       } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
         size_t pi = pm_idx;
         DCHECK(page_map_[pi] == kPageMapRun || page_map_[pi] == kPageMapRunPart);
         // Find the beginning of the run.
         while (page_map_[pi] != kPageMapRun) {
           pi--;
-          DCHECK(pi < capacity_ / kPageSize);
+          DCHECK_LT(pi, capacity_ / kPageSize);
         }
-        DCHECK(page_map_[pi] == kPageMapRun);
+        DCHECK_EQ(page_map_[pi], kPageMapRun);
         run = reinterpret_cast<Run*>(base_ + pi * kPageSize);
-        DCHECK(run->magic_num_ == kMagicNum);
+        DCHECK_EQ(run->magic_num_, kMagicNum);
       } else if (page_map_entry == kPageMapLargeObject) {
         MutexLock mu(self, lock_);
         FreePages(self, ptr);
@@ -1142,7 +1147,7 @@
       bool free_from_run = false;
       {
         MutexLock mu(self, lock_);
-        DCHECK(pm_idx < page_map_size_);
+        DCHECK_LT(pm_idx, page_map_size_);
         byte page_map_entry = page_map_[pm_idx];
         if (kTraceRosAlloc) {
           LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
@@ -1152,7 +1157,7 @@
         if (LIKELY(page_map_entry == kPageMapRun)) {
           free_from_run = true;
           run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
-          DCHECK(run->magic_num_ == kMagicNum);
+          DCHECK_EQ(run->magic_num_, kMagicNum);
         } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
           free_from_run = true;
           size_t pi = pm_idx;
@@ -1160,11 +1165,11 @@
           // Find the beginning of the run.
           while (page_map_[pi] != kPageMapRun) {
             pi--;
-            DCHECK(pi < capacity_ / kPageSize);
+            DCHECK_LT(pi, capacity_ / kPageSize);
           }
-          DCHECK(page_map_[pi] == kPageMapRun);
+          DCHECK_EQ(page_map_[pi], kPageMapRun);
           run = reinterpret_cast<Run*>(base_ + pi * kPageSize);
-          DCHECK(run->magic_num_ == kMagicNum);
+          DCHECK_EQ(run->magic_num_, kMagicNum);
         } else if (page_map_entry == kPageMapLargeObject) {
           FreePages(self, ptr);
         } else {
@@ -1393,7 +1398,8 @@
 }
 
 size_t RosAlloc::UsableSize(void* ptr) {
-  DCHECK(base_ <= ptr && ptr < base_ + footprint_);
+  DCHECK_LE(base_, ptr);
+  DCHECK_LT(ptr, base_ + footprint_);
   size_t pm_idx = RoundDownToPageMapIndex(ptr);
   MutexLock mu(Thread::Current(), lock_);
   switch (page_map_[pm_idx]) {
@@ -1420,11 +1426,11 @@
     // Find the beginning of the run.
     while (page_map_[pm_idx] != kPageMapRun) {
       pm_idx--;
-      DCHECK(pm_idx < capacity_ / kPageSize);
+      DCHECK_LT(pm_idx, capacity_ / kPageSize);
     }
-    DCHECK(page_map_[pm_idx] == kPageMapRun);
+    DCHECK_EQ(page_map_[pm_idx], kPageMapRun);
     Run* run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
-    DCHECK(run->magic_num_ == kMagicNum);
+    DCHECK_EQ(run->magic_num_, kMagicNum);
     size_t idx = run->size_bracket_idx_;
     size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
         - (reinterpret_cast<byte*>(run) + headerSizes[idx]);
@@ -1446,7 +1452,7 @@
   if (it != free_page_runs_.rend() && (last_free_page_run = *it)->End(this) == base_ + footprint_) {
     // Remove the last free page run, if any.
     DCHECK(last_free_page_run->IsFree());
-    DCHECK(page_map_[ToPageMapIndex(last_free_page_run)] == kPageMapEmpty);
+    DCHECK_EQ(page_map_[ToPageMapIndex(last_free_page_run)], kPageMapEmpty);
     DCHECK_EQ(last_free_page_run->ByteSize(this) % kPageSize, static_cast<size_t>(0));
     DCHECK_EQ(last_free_page_run->End(this), base_ + footprint_);
     free_page_runs_.erase(last_free_page_run);
@@ -1547,7 +1553,7 @@
       case kPageMapRun: {
         // The start of a run.
         Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize);
-        DCHECK(run->magic_num_ == kMagicNum);
+        DCHECK_EQ(run->magic_num_, kMagicNum);
         run->InspectAllSlots(handler, arg);
         size_t num_pages = numOfPages[run->size_bracket_idx_];
         if (kIsDebugBuild) {
@@ -1656,7 +1662,7 @@
     } else if (i == kNumOfSizeBrackets - 2) {
       bracketSizes[i] = 1 * KB;
     } else {
-      DCHECK(i == kNumOfSizeBrackets - 1);
+      DCHECK_EQ(i, kNumOfSizeBrackets - 1);
       bracketSizes[i] = 2 * KB;
     }
     if (kTraceRosAlloc) {
@@ -1674,10 +1680,10 @@
     } else if (i < 32) {
       numOfPages[i] = 8;
     } else if (i == 32) {
-      DCHECK(i = kNumOfSizeBrackets - 2);
+      DCHECK_EQ(i, kNumOfSizeBrackets - 2);
       numOfPages[i] = 16;
     } else {
-      DCHECK(i = kNumOfSizeBrackets - 1);
+      DCHECK_EQ(i, kNumOfSizeBrackets - 1);
       numOfPages[i] = 32;
     }
     if (kTraceRosAlloc) {
@@ -1726,7 +1732,7 @@
     DCHECK(num_of_slots > 0 && header_size > 0 && bulk_free_bit_map_offset > 0);
     // Add the padding for the alignment remainder.
     header_size += run_size % bracket_size;
-    DCHECK(header_size + num_of_slots * bracket_size == run_size);
+    DCHECK_EQ(header_size + num_of_slots * bracket_size, run_size);
     numOfSlots[i] = num_of_slots;
     headerSizes[i] = header_size;
     bulkFreeBitMapOffsets[i] = bulk_free_bit_map_offset;
@@ -1773,7 +1779,7 @@
         case kPageMapEmpty: {
           // The start of a free page run.
           FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * kPageSize);
-          DCHECK(fpr->magic_num_ == kMagicNumFree) << "Bad magic number : " << fpr->magic_num_;
+          DCHECK_EQ(fpr->magic_num_, kMagicNumFree);
           CHECK(free_page_runs_.find(fpr) != free_page_runs_.end())
               << "An empty page must belong to the free page run set";
           size_t fpr_size = fpr->ByteSize(this);
@@ -1805,7 +1811,7 @@
           void* start = base_ + i * kPageSize;
           mirror::Object* obj = reinterpret_cast<mirror::Object*>(start);
           size_t obj_size = obj->SizeOf();
-          CHECK(obj_size > kLargeSizeThreshold)
+          CHECK_GT(obj_size, kLargeSizeThreshold)
               << "A rosalloc large object size must be > " << kLargeSizeThreshold;
           CHECK_EQ(num_pages, RoundUp(obj_size, kPageSize) / kPageSize)
               << "A rosalloc large object size " << obj_size
@@ -1822,9 +1828,9 @@
         case kPageMapRun: {
           // The start of a run.
           Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize);
-          DCHECK(run->magic_num_ == kMagicNum) << "Bad magic number" << run->magic_num_;
+          DCHECK_EQ(run->magic_num_, kMagicNum);
           size_t idx = run->size_bracket_idx_;
-          CHECK(idx < kNumOfSizeBrackets) << "Out of range size bracket index : " << idx;
+          CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << idx;
           size_t num_pages = numOfPages[idx];
           CHECK_GT(num_pages, static_cast<uintptr_t>(0))
               << "Run size must be > 0 : " << num_pages;
@@ -1858,9 +1864,9 @@
 }
 
 void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc) {
-  DCHECK(magic_num_ == kMagicNum) << "Bad magic number : " << Dump();
+  DCHECK_EQ(magic_num_, kMagicNum) << "Bad magic number : " << Dump();
   size_t idx = size_bracket_idx_;
-  CHECK(idx < kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump();
+  CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump();
   byte* slot_base = reinterpret_cast<byte*>(this) + headerSizes[idx];
   size_t num_slots = numOfSlots[idx];
   size_t bracket_size = IndexToBracketSize(idx);
@@ -1951,7 +1957,7 @@
   size_t num_vec = RoundUp(num_slots, 32) / 32;
   size_t slots = 0;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
-    DCHECK(num_slots >= slots) << "Out of bounds";
+    DCHECK_GE(num_slots, slots) << "Out of bounds";
     uint32_t vec = alloc_bit_map_[v];
     uint32_t thread_local_free_vec = ThreadLocalFreeBitMap()[v];
     size_t end = std::min(num_slots - slots, static_cast<size_t>(32));
diff --git a/runtime/method_reference.h b/runtime/method_reference.h
index 8e46d7e..f4fe9b2 100644
--- a/runtime/method_reference.h
+++ b/runtime/method_reference.h
@@ -23,9 +23,6 @@
 
 class DexFile;
 
-// A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
-typedef std::pair<const DexFile*, uint32_t> ClassReference;
-
 // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
 struct MethodReference {
   MethodReference(const DexFile* file, uint32_t index) : dex_file(file), dex_method_index(index) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 6b897cb..fe27992 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -320,15 +320,6 @@
   self->PopManagedStackFragment(fragment);
 }
 
-#ifndef NDEBUG
-size_t ArtMethod::GetSirtOffsetInBytes() {
-  CHECK(IsNative());
-  // TODO: support Sirt access from generic JNI trampoline.
-  CHECK_NE(GetEntryPointFromQuickCompiledCode(), GetQuickGenericJniTrampoline());
-  return kPointerSize;
-}
-#endif
-
 bool ArtMethod::IsRegistered() {
   void* native_method =
       GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_), false);
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 8c22e67..a9da66c 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -342,13 +342,9 @@
     return GetFrameSizeInBytes() - kPointerSize;
   }
 
-#ifndef NDEBUG
-  size_t GetSirtOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-#else
   size_t GetSirtOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return kPointerSize;
   }
-#endif
 
   bool IsRegistered();
 
diff --git a/runtime/oat.cc b/runtime/oat.cc
index d4eea85..454786d 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -132,7 +132,8 @@
 
 uint32_t OatHeader::GetInterpreterToInterpreterBridgeOffset() const {
   DCHECK(IsValid());
-  CHECK_GE(interpreter_to_interpreter_bridge_offset_, executable_offset_);
+  CHECK(interpreter_to_interpreter_bridge_offset_ == 0 ||
+        interpreter_to_interpreter_bridge_offset_ >= executable_offset_);
   return interpreter_to_interpreter_bridge_offset_;
 }
 
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 9ddeeca..96ad55f 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -394,6 +394,20 @@
     return shorty_len_;
   }
 
+  // Counts the number of references in the parameter list of the corresponding method.
+  // Note: Thus does _not_ include "this" for non-static methods.
+  uint32_t GetNumberOfReferenceArgsWithoutReceiver() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    const char* shorty = GetShorty();
+    uint32_t refs = 0;
+    for (uint32_t i = 1; i < shorty_len_ ; ++i) {
+      if (shorty[i] == 'L') {
+        refs++;
+      }
+    }
+
+    return refs;
+  }
+
   const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const DexFile& dex_file = GetDexFile();
     uint32_t dex_method_idx = method_->GetDexMethodIndex();
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/runtime/stack.cc b/runtime/stack.cc
index 15b288e..26b4de3 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -108,17 +108,11 @@
     return NULL;
   } else if (m->IsNative()) {
     if (cur_quick_frame_ != NULL) {
-      if (m->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline()) {
-        UNIMPLEMENTED(ERROR) << "Failed to determine this object of native method: "
-            << PrettyMethod(m);
-        return nullptr;
-      } else {
-        StackIndirectReferenceTable* sirt =
-            reinterpret_cast<StackIndirectReferenceTable*>(
-                reinterpret_cast<char*>(cur_quick_frame_) +
-                m->GetSirtOffsetInBytes());
-        return sirt->GetReference(0);
-      }
+      StackIndirectReferenceTable* sirt =
+          reinterpret_cast<StackIndirectReferenceTable*>(
+              reinterpret_cast<char*>(cur_quick_frame_) +
+              m->GetSirtOffsetInBytes());
+      return sirt->GetReference(0);
     } else {
       return cur_shadow_frame_->GetVRegReference(0);
     }
diff --git a/runtime/stack_indirect_reference_table.h b/runtime/stack_indirect_reference_table.h
index c2d6a59..e6dda85 100644
--- a/runtime/stack_indirect_reference_table.h
+++ b/runtime/stack_indirect_reference_table.h
@@ -39,7 +39,7 @@
 
   ~StackIndirectReferenceTable() {}
 
-  // Number of references contained within this SIRT
+  // Number of references contained within this SIRT.
   uint32_t NumberOfReferences() const {
     return number_of_references_;
   }
@@ -51,7 +51,13 @@
     return header_size + data_size;
   }
 
-  // Link to previous SIRT or NULL
+  // Get the size of the SIRT for the number of entries, with padding added for potential alignment.
+  static size_t GetAlignedSirtSize(uint32_t num_references) {
+    size_t sirt_size = SizeOf(num_references);
+    return RoundUp(sirt_size, 8);
+  }
+
+  // Link to previous SIRT or NULL.
   StackIndirectReferenceTable* GetLink() const {
     return link_;
   }
@@ -72,6 +78,12 @@
     return references_[i].AsMirrorPtr();
   }
 
+  StackReference<mirror::Object>* GetStackReference(size_t i)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK_LT(i, number_of_references_);
+    return &references_[i];
+  }
+
   void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK_LT(i, number_of_references_);
     references_[i].Assign(object);
diff --git a/runtime/thread.h b/runtime/thread.h
index 2ebc107..eaffc3e 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -95,7 +95,12 @@
 class PACKED(4) Thread {
  public:
   // Space to throw a StackOverflowError in.
-  static const size_t kStackOverflowReservedBytes = 16 * KB;
+#if __LP64__
+  // TODO: shrink reserved space, in particular for 64bit.
+  static constexpr size_t kStackOverflowReservedBytes = 24 * KB;
+#else
+  static constexpr size_t kStackOverflowReservedBytes = 16 * KB;
+#endif
 
   // Creates a new native thread corresponding to the given managed peer.
   // Used to implement Thread.start.
diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt
index 12df250..105d929 100644
--- a/test/044-proxy/expected.txt
+++ b/test/044-proxy/expected.txt
@@ -54,6 +54,7 @@
 Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final void $Proxy1.getTrace(), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()]
 Decl annos: []
 Param annos (0) : []
+Modifiers: 17
 Dupe threw expected exception
 Clash threw expected exception
 Clash2 threw expected exception
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index ea46f49..d4ce71f 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -90,6 +90,7 @@
         Annotation[][] paramAnnos = meth.getParameterAnnotations();
         System.out.println("Param annos (" + paramAnnos.length + ") : "
             + Arrays.deepToString(paramAnnos));
+        System.out.println("Modifiers: " + meth.getModifiers());
     }
 
     static Object createProxy(Object proxyMe) {
@@ -244,14 +245,15 @@
         // invocation of toString() in the print statements below.
         if (method.getDeclaringClass() == java.lang.Object.class) {
             //System.out.println("!!! object " + method.getName());
-            if (method.getName().equals("toString"))
+            if (method.getName().equals("toString")) {
                 return super.toString();
-            else if (method.getName().equals("hashCode"))
+            } else if (method.getName().equals("hashCode")) {
                 return Integer.valueOf(super.hashCode());
-            else if (method.getName().equals("equals"))
+            } else if (method.getName().equals("equals")) {
                 return Boolean.valueOf(super.equals(args[0]));
-            else
+            } else {
                 throw new RuntimeException("huh?");
+            }
         }
 
         if (method.getDeclaringClass() == Trace.class) {
@@ -277,10 +279,11 @@
         }
 
         try {
-            if (true)
+            if (true) {
                 result = method.invoke(mObj, args);
-            else
+            } else {
                 result = -1;
+            }
             System.out.println("Success: method " + method.getName()
                 + " res=" + result);
         } catch (InvocationTargetException ite) {
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/202-thread-oome/src/Main.java b/test/202-thread-oome/src/Main.java
index bacb842..f7df93b 100644
--- a/test/202-thread-oome/src/Main.java
+++ b/test/202-thread-oome/src/Main.java
@@ -16,7 +16,7 @@
 
 public class Main {
   public static void main(String[] args) throws Exception {
-    Thread t = new Thread(null, new Runnable() { public void run() {} }, "", 3*1024*1024*1024);
+    Thread t = new Thread(null, new Runnable() { public void run() {} }, "", 3L*1024*1024*1024);
     try {
       t.start();
     } catch (OutOfMemoryError expected) {
diff --git a/test/Android.mk b/test/Android.mk
index f4a0426..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=$(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)