Merge "ART: Print maps directly to log"
diff --git a/.gitignore b/.gitignore
index 1cdfed9..3d1658d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 USE_PORTABLE_COMPILER
 SMALL_ART
 SEA_IR_ART
+JIT_ART
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 3000cdf..cb34473 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -48,6 +48,18 @@
 endif
 
 #
+# Used to enable JIT
+#
+ART_JIT := false
+ifneq ($(wildcard art/JIT_ART),)
+$(info Enabling ART_JIT because of existence of art/JIT_ART)
+ART_JIT := true
+endif
+ifeq ($(WITH_ART_JIT), true)
+ART_JIT := true
+endif
+
+#
 # Used to enable smart mode
 #
 ART_SMALL_MODE := false
@@ -191,6 +203,7 @@
   -Wunreachable-code \
   -Wredundant-decls \
   -Wshadow \
+  -Wunused \
   -fvisibility=protected \
   $(art_default_gc_type_cflags)
 
diff --git a/cmdline/cmdline_parse_result.h b/cmdline/cmdline_parse_result.h
index d6ac341..717642f 100644
--- a/cmdline/cmdline_parse_result.h
+++ b/cmdline/cmdline_parse_result.h
@@ -117,9 +117,9 @@
   }
 
   // Make sure copying is allowed
-  CmdlineParseResult(const CmdlineParseResult& other) = default;
+  CmdlineParseResult(const CmdlineParseResult&) = default;
   // Make sure moving is cheap
-  CmdlineParseResult(CmdlineParseResult&& other) = default;
+  CmdlineParseResult(CmdlineParseResult&&) = default;
 
  private:
   explicit CmdlineParseResult(const T& value)
diff --git a/cmdline/cmdline_parser.h b/cmdline/cmdline_parser.h
index a555356..e4af4f9 100644
--- a/cmdline/cmdline_parser.h
+++ b/cmdline/cmdline_parser.h
@@ -490,9 +490,9 @@
   }
 
   // Ensure we have a default move constructor.
-  CmdlineParser(CmdlineParser&& other) = default;
+  CmdlineParser(CmdlineParser&&) = default;
   // Ensure we have a default move assignment operator.
-  CmdlineParser& operator=(CmdlineParser&& other) = default;
+  CmdlineParser& operator=(CmdlineParser&&) = default;
 
  private:
   friend struct Builder;
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 288f7ac..18d8c7a 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -202,6 +202,7 @@
   EXPECT_SINGLE_PARSE_VALUE(false, "-XX:DisableHSpaceCompactForOOM", M::EnableHSpaceCompactForOOM);
   EXPECT_SINGLE_PARSE_VALUE(0.5, "-XX:HeapTargetUtilization=0.5", M::HeapTargetUtilization);
   EXPECT_SINGLE_PARSE_VALUE(5u, "-XX:ParallelGCThreads=5", M::ParallelGCThreads);
+  EXPECT_SINGLE_PARSE_EXISTS("-Xno-dex-file-fallback", M::NoDexFileFallback);
 }  // TEST_F
 
 TEST_F(CmdlineParserTest, TestSimpleFailures) {
@@ -410,6 +411,26 @@
 }  // TEST_F
 
 /*
+* -Xjit, -Xnojit, -Xjitcodecachesize, Xjitcompilethreshold
+*/
+TEST_F(CmdlineParserTest, TestJitOptions) {
+ /*
+  * Test successes
+  */
+  {
+    EXPECT_SINGLE_PARSE_VALUE(true, "-Xjit", M::UseJIT);
+    EXPECT_SINGLE_PARSE_VALUE(false, "-Xnojit", M::UseJIT);
+  }
+  {
+    EXPECT_SINGLE_PARSE_VALUE(MemoryKiB(16 * KB), "-Xjitcodecachesize:16K", M::JITCodeCacheCapacity);
+    EXPECT_SINGLE_PARSE_VALUE(MemoryKiB(16 * MB), "-Xjitcodecachesize:16M", M::JITCodeCacheCapacity);
+  }
+  {
+    EXPECT_SINGLE_PARSE_VALUE(12345u, "-Xjitthreshold:12345", M::JITCompileThreshold);
+  }
+}  // TEST_F
+
+/*
 * -X-profile-*
 */
 TEST_F(CmdlineParserTest, TestProfilerOptions) {
@@ -494,9 +515,8 @@
       "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:abdef",
       "-Xdexopt:foobar", "-Xnoquithandler", "-Xjnigreflimit:ixnay", "-Xgenregmap", "-Xnogenregmap",
       "-Xverifyopt:never", "-Xcheckdexsum", "-Xincludeselectedop", "-Xjitop:noop",
-      "-Xincludeselectedmethod", "-Xjitthreshold:123", "-Xjitcodecachesize:12345",
-      "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:nosuchluck", "-Xjitoffset:none",
-      "-Xjitconfig:yes", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile",
+      "-Xincludeselectedmethod", "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:nosuchluck",
+      "-Xjitoffset:none", "-Xjitconfig:yes", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile",
       "-Xjitdisableopt", "-Xjitsuspendpoll", "-XX:mainThreadStackSize=1337"
   };
 
diff --git a/cmdline/cmdline_result.h b/cmdline/cmdline_result.h
index bf3a85d..963dfc1 100644
--- a/cmdline/cmdline_result.h
+++ b/cmdline/cmdline_result.h
@@ -65,9 +65,9 @@
     }
 
     // Make sure copying exists
-    CmdlineResult(const CmdlineResult& other) = default;
+    CmdlineResult(const CmdlineResult&) = default;
     // Make sure moving is cheap
-    CmdlineResult(CmdlineResult&& other) = default;
+    CmdlineResult(CmdlineResult&&) = default;
 
   private:
     const Status status_;
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 180baec..de99278 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -337,8 +337,8 @@
 
   // Default constructors/copy-constructors.
   MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
-  MillisecondsToNanoseconds(const MillisecondsToNanoseconds& rhs) = default;
-  MillisecondsToNanoseconds(MillisecondsToNanoseconds&& rhs) = default;
+  MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
+  MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
 
  private:
   uint64_t nanoseconds_;
@@ -421,8 +421,8 @@
   }
 
   ParseStringList() = default;
-  ParseStringList(const ParseStringList& rhs) = default;
-  ParseStringList(ParseStringList&& rhs) = default;
+  ParseStringList(const ParseStringList&) = default;
+  ParseStringList(ParseStringList&&) = default;
 
  private:
   std::vector<std::string> list_;
@@ -585,6 +585,8 @@
         log_verbosity.heap = true;
       } else if (verbose_options[j] == "jdwp") {
         log_verbosity.jdwp = true;
+      } else if (verbose_options[j] == "jit") {
+        log_verbosity.jit = true;
       } else if (verbose_options[j] == "jni") {
         log_verbosity.jni = true;
       } else if (verbose_options[j] == "monitor") {
@@ -651,8 +653,8 @@
     max_stack_depth_(0) {
   }
 
-  TestProfilerOptions(const TestProfilerOptions& other) = default;
-  TestProfilerOptions(TestProfilerOptions&& other) = default;
+  TestProfilerOptions(const TestProfilerOptions&) = default;
+  TestProfilerOptions(TestProfilerOptions&&) = default;
 };
 
 static inline std::ostream& operator<<(std::ostream& stream, const TestProfilerOptions& options) {
diff --git a/cmdline/token_range.h b/cmdline/token_range.h
index 50c54fe..5b54384 100644
--- a/cmdline/token_range.h
+++ b/cmdline/token_range.h
@@ -90,10 +90,10 @@
   }
 
   // Non-copying copy constructor.
-  TokenRange(const TokenRange& other) = default;
+  TokenRange(const TokenRange&) = default;
 
   // Non-copying move constructor.
-  TokenRange(TokenRange&& other) = default;
+  TokenRange(TokenRange&&) = default;
 
   // Non-copying constructor. Retains reference to an existing list of tokens, with offset.
   explicit TokenRange(std::shared_ptr<TokenList> token_list)
diff --git a/compiler/Android.mk b/compiler/Android.mk
index beb34dc..86a27c1 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -79,6 +79,7 @@
 	driver/compiler_driver.cc \
 	driver/compiler_options.cc \
 	driver/dex_compilation_unit.cc \
+	jit/jit_compiler.cc \
 	jni/quick/arm/calling_convention_arm.cc \
 	jni/quick/arm64/calling_convention_arm64.cc \
 	jni/quick/mips/calling_convention_mips.cc \
@@ -161,8 +162,7 @@
   driver/compiler_options.h \
   image_writer.h \
   optimizing/locations.h \
-  utils/arm/constants_arm.h \
-  utils/dex_instruction_utils.h
+  utils/arm/constants_arm.h
 
 # $(1): target or host
 # $(2): ndebug or debug
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 1cd78f8..e8354b2 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -52,19 +52,19 @@
     const SwapVector<uint8_t>* code = compiled_method->GetQuickCode();
     uint32_t code_size = code->size();
     CHECK_NE(0u, code_size);
-    const SwapVector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
-    uint32_t vmap_table_offset = vmap_table.empty() ? 0u
-        : sizeof(OatQuickMethodHeader) + vmap_table.size();
+    const SwapVector<uint8_t>* vmap_table = compiled_method->GetVmapTable();
+    uint32_t vmap_table_offset = vmap_table->empty() ? 0u
+        : sizeof(OatQuickMethodHeader) + vmap_table->size();
     const SwapVector<uint8_t>* mapping_table = compiled_method->GetMappingTable();
     bool mapping_table_used = mapping_table != nullptr && !mapping_table->empty();
     size_t mapping_table_size = mapping_table_used ? mapping_table->size() : 0U;
     uint32_t mapping_table_offset = !mapping_table_used ? 0u
-        : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size;
+        : sizeof(OatQuickMethodHeader) + vmap_table->size() + mapping_table_size;
     const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap();
     bool gc_map_used = gc_map != nullptr && !gc_map->empty();
     size_t gc_map_size = gc_map_used ? gc_map->size() : 0U;
     uint32_t gc_map_offset = !gc_map_used ? 0u
-        : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size + gc_map_size;
+        : sizeof(OatQuickMethodHeader) + vmap_table->size() + mapping_table_size + gc_map_size;
     OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
                                        compiled_method->GetFrameSizeInBytes(),
                                        compiled_method->GetCoreSpillMask(),
@@ -72,14 +72,14 @@
 
     header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
     std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
-    size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table_size +
+    size_t size = sizeof(method_header) + code_size + vmap_table->size() + mapping_table_size +
         gc_map_size;
     size_t code_offset = compiled_method->AlignCode(size - code_size);
     size_t padding = code_offset - (size - code_size);
     chunk->reserve(padding + size);
     chunk->resize(sizeof(method_header));
     memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
-    chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
+    chunk->insert(chunk->begin(), vmap_table->begin(), vmap_table->end());
     if (mapping_table_used) {
       chunk->insert(chunk->begin(), mapping_table->begin(), mapping_table->end());
     }
@@ -212,7 +212,7 @@
   CHECK(method != nullptr);
   TimingLogger timings("CommonTest::CompileMethod", false, false);
   TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
-  compiler_driver_->CompileOne(method, &timings);
+  compiler_driver_->CompileOne(Thread::Current(), method, &timings);
   TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
   MakeExecutable(method);
 }
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 22be28c..1849e7e 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -20,16 +20,29 @@
 namespace art {
 
 CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-                           const ArrayRef<const uint8_t>& quick_code)
+                           const ArrayRef<const uint8_t>& quick_code, bool owns_code_array)
     : compiler_driver_(compiler_driver), instruction_set_(instruction_set),
-      quick_code_(nullptr) {
+      owns_code_array_(owns_code_array), quick_code_(nullptr) {
   SetCode(&quick_code);
 }
 
 void CompiledCode::SetCode(const ArrayRef<const uint8_t>* quick_code) {
   if (quick_code != nullptr) {
     CHECK(!quick_code->empty());
-    quick_code_ = compiler_driver_->DeduplicateCode(*quick_code);
+    if (owns_code_array_) {
+      // If we are supposed to own the code, don't deduplicate it.
+      CHECK(quick_code_ == nullptr);
+      quick_code_ = new SwapVector<uint8_t>(quick_code->begin(), quick_code->end(),
+                                            compiler_driver_->GetSwapSpaceAllocator());
+    } else {
+      quick_code_ = compiler_driver_->DeduplicateCode(*quick_code);
+    }
+  }
+}
+
+CompiledCode::~CompiledCode() {
+  if (owns_code_array_) {
+    delete quick_code_;
   }
 }
 
@@ -46,11 +59,11 @@
   return (rhs.quick_code_ == nullptr);
 }
 
-uint32_t CompiledCode::AlignCode(uint32_t offset) const {
+size_t CompiledCode::AlignCode(size_t offset) const {
   return AlignCode(offset, instruction_set_);
 }
 
-uint32_t CompiledCode::AlignCode(uint32_t offset, InstructionSet instruction_set) {
+size_t CompiledCode::AlignCode(size_t offset, InstructionSet instruction_set) {
   return RoundUp(offset, GetInstructionSetAlignment(instruction_set));
 }
 
@@ -120,17 +133,39 @@
                                const ArrayRef<const uint8_t>& native_gc_map,
                                const ArrayRef<const uint8_t>& cfi_info,
                                const ArrayRef<LinkerPatch>& patches)
-    : CompiledCode(driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
-      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
-      src_mapping_table_(src_mapping_table == nullptr ?
-          driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) :
-          driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(src_mapping_table->Arrange()))),
-      mapping_table_(mapping_table.data() == nullptr ?
-          nullptr : driver->DeduplicateMappingTable(mapping_table)),
-      vmap_table_(driver->DeduplicateVMapTable(vmap_table)),
-      gc_map_(native_gc_map.data() == nullptr ? nullptr : driver->DeduplicateGCMap(native_gc_map)),
-      cfi_info_(cfi_info.data() == nullptr ? nullptr : driver->DeduplicateCFIInfo(cfi_info)),
+    : CompiledCode(driver, instruction_set, quick_code, !driver->DedupeEnabled()),
+      owns_arrays_(!driver->DedupeEnabled()),
+      frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask),
+      fp_spill_mask_(fp_spill_mask),
       patches_(patches.begin(), patches.end(), driver->GetSwapSpaceAllocator()) {
+  if (owns_arrays_) {
+    if (src_mapping_table == nullptr) {
+      src_mapping_table_ = new SwapSrcMap(driver->GetSwapSpaceAllocator());
+    } else {
+      src_mapping_table->Arrange();
+      src_mapping_table_ = new SwapSrcMap(src_mapping_table->begin(), src_mapping_table->end(),
+                                          driver->GetSwapSpaceAllocator());
+    }
+    mapping_table_ = mapping_table.empty() ?
+        nullptr : new SwapVector<uint8_t>(mapping_table.begin(), mapping_table.end(),
+                                          driver->GetSwapSpaceAllocator());
+    vmap_table_ = new SwapVector<uint8_t>(vmap_table.begin(), vmap_table.end(),
+                                          driver->GetSwapSpaceAllocator());
+    gc_map_ = native_gc_map.empty() ? nullptr :
+        new SwapVector<uint8_t>(native_gc_map.begin(), native_gc_map.end(),
+                                driver->GetSwapSpaceAllocator());
+    cfi_info_ = cfi_info.empty() ? nullptr :
+        new SwapVector<uint8_t>(cfi_info.begin(), cfi_info.end(), driver->GetSwapSpaceAllocator());
+  } else {
+    src_mapping_table_ = src_mapping_table == nullptr ?
+        driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) :
+        driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(src_mapping_table->Arrange()));
+    mapping_table_ = mapping_table.empty() ?
+        nullptr : driver->DeduplicateMappingTable(mapping_table);
+    vmap_table_ = driver->DeduplicateVMapTable(vmap_table);
+    gc_map_ = native_gc_map.empty() ? nullptr : driver->DeduplicateGCMap(native_gc_map);
+    cfi_info_ = cfi_info.empty() ? nullptr : driver->DeduplicateCFIInfo(cfi_info);
+  }
 }
 
 CompiledMethod* CompiledMethod::SwapAllocCompiledMethod(
@@ -194,4 +229,14 @@
   alloc.deallocate(m, 1);
 }
 
+CompiledMethod::~CompiledMethod() {
+  if (owns_arrays_) {
+    delete src_mapping_table_;
+    delete mapping_table_;
+    delete vmap_table_;
+    delete gc_map_;
+    delete cfi_info_;
+  }
+}
+
 }  // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 6013507..d6a07f6 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -27,10 +27,6 @@
 #include "utils/array_ref.h"
 #include "utils/swap_space.h"
 
-namespace llvm {
-  class Function;
-}  // namespace llvm
-
 namespace art {
 
 class CompilerDriver;
@@ -39,7 +35,9 @@
  public:
   // For Quick to supply an code blob
   CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-               const ArrayRef<const uint8_t>& quick_code);
+               const ArrayRef<const uint8_t>& quick_code, bool owns_code_array);
+
+  virtual ~CompiledCode();
 
   InstructionSet GetInstructionSet() const {
     return instruction_set_;
@@ -56,8 +54,8 @@
   // To align an offset from a page-aligned value to make it suitable
   // for code storage. For example on ARM, to ensure that PC relative
   // valu computations work out as expected.
-  uint32_t AlignCode(uint32_t offset) const;
-  static uint32_t AlignCode(uint32_t offset, InstructionSet instruction_set);
+  size_t AlignCode(size_t offset) const;
+  static size_t AlignCode(size_t offset, InstructionSet instruction_set);
 
   // returns the difference between the code address and a usable PC.
   // mainly to cope with kThumb2 where the lower bit must be set.
@@ -78,6 +76,9 @@
 
   const InstructionSet instruction_set_;
 
+  // If we own the code array (means that we free in destructor).
+  const bool owns_code_array_;
+
   // Used to store the PIC code for Quick.
   SwapVector<uint8_t>* quick_code_;
 
@@ -122,6 +123,7 @@
   using std::vector<SrcMapElem, Allocator>::size;
 
   explicit SrcMap() {}
+  explicit SrcMap(const Allocator& alloc) : std::vector<SrcMapElem, Allocator>(alloc) {}
 
   template <class InputIt>
   SrcMap(InputIt first, InputIt last, const Allocator& alloc)
@@ -291,7 +293,7 @@
                  const ArrayRef<const uint8_t>& cfi_info,
                  const ArrayRef<LinkerPatch>& patches = ArrayRef<LinkerPatch>());
 
-  ~CompiledMethod() {}
+  virtual ~CompiledMethod();
 
   static CompiledMethod* SwapAllocCompiledMethod(
       CompilerDriver* driver,
@@ -347,9 +349,9 @@
     return mapping_table_;
   }
 
-  const SwapVector<uint8_t>& GetVmapTable() const {
+  const SwapVector<uint8_t>* GetVmapTable() const {
     DCHECK(vmap_table_ != nullptr);
-    return *vmap_table_;
+    return vmap_table_;
   }
 
   SwapVector<uint8_t> const* GetGcMap() const {
@@ -365,6 +367,8 @@
   }
 
  private:
+  // Whether or not the arrays are owned by the compiled method or dedupe sets.
+  const bool owns_arrays_;
   // For quick code, the size of the activation used by the code.
   const size_t frame_size_in_bytes_;
   // For quick code, a bit mask describing spilled GPR callee-save registers.
diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc
index 54e34ea..b91c3ca 100644
--- a/compiler/dex/global_value_numbering_test.cc
+++ b/compiler/dex/global_value_numbering_test.cc
@@ -142,7 +142,7 @@
     cu_.mir_graph->ifield_lowering_infos_.reserve(count);
     for (size_t i = 0u; i != count; ++i) {
       const IFieldDef* def = &defs[i];
-      MirIFieldLoweringInfo field_info(def->field_idx, def->type);
+      MirIFieldLoweringInfo field_info(def->field_idx, def->type, false);
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
diff --git a/compiler/dex/gvn_dead_code_elimination_test.cc b/compiler/dex/gvn_dead_code_elimination_test.cc
index 954e9f1..4d2b8b3 100644
--- a/compiler/dex/gvn_dead_code_elimination_test.cc
+++ b/compiler/dex/gvn_dead_code_elimination_test.cc
@@ -143,7 +143,7 @@
     cu_.mir_graph->ifield_lowering_infos_.reserve(count);
     for (size_t i = 0u; i != count; ++i) {
       const IFieldDef* def = &defs[i];
-      MirIFieldLoweringInfo field_info(def->field_idx, def->type);
+      MirIFieldLoweringInfo field_info(def->field_idx, def->type, false);
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h
index 97ea05a..379c952 100644
--- a/compiler/dex/local_value_numbering.h
+++ b/compiler/dex/local_value_numbering.h
@@ -21,8 +21,8 @@
 
 #include "base/arena_object.h"
 #include "base/logging.h"
+#include "dex_instruction_utils.h"
 #include "global_value_numbering.h"
-#include "utils/dex_instruction_utils.h"
 
 namespace art {
 
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index d1c3a6b..566527a 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -96,7 +96,7 @@
     cu_.mir_graph->ifield_lowering_infos_.reserve(count);
     for (size_t i = 0u; i != count; ++i) {
       const IFieldDef* def = &defs[i];
-      MirIFieldLoweringInfo field_info(def->field_idx, def->type);
+      MirIFieldLoweringInfo field_info(def->field_idx, def->type, false);
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index 31dbc60..a89b250 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -416,8 +416,8 @@
   // 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
   kAnInvoke | kAnHeavyWeight,
 
-  // 73 UNUSED_73
-  kAnNone,
+  // 73 RETURN_VOID_BARRIER
+  kAnBranch,
 
   // 74 INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
   kAnInvoke | kAnHeavyWeight,
@@ -752,88 +752,88 @@
   // E2 USHR_INT_LIT8 vAA, vBB, #+CC
   kAnMath | kAnInt,
 
-  // E3 IGET_VOLATILE
+  // E3 IGET_QUICK
   kAnNone,
 
-  // E4 IPUT_VOLATILE
+  // E4 IGET_WIDE_QUICK
   kAnNone,
 
-  // E5 SGET_VOLATILE
+  // E5 IGET_OBJECT_QUICK
   kAnNone,
 
-  // E6 SPUT_VOLATILE
+  // E6 IPUT_QUICK
   kAnNone,
 
-  // E7 IGET_OBJECT_VOLATILE
+  // E7 IPUT_WIDE_QUICK
   kAnNone,
 
-  // E8 IGET_WIDE_VOLATILE
+  // E8 IPUT_OBJECT_QUICK
   kAnNone,
 
-  // E9 IPUT_WIDE_VOLATILE
-  kAnNone,
-
-  // EA SGET_WIDE_VOLATILE
-  kAnNone,
-
-  // EB SPUT_WIDE_VOLATILE
-  kAnNone,
-
-  // EC BREAKPOINT
-  kAnNone,
-
-  // ED THROW_VERIFICATION_ERROR
-  kAnHeavyWeight | kAnBranch,
-
-  // EE EXECUTE_INLINE
-  kAnNone,
-
-  // EF EXECUTE_INLINE_RANGE
-  kAnNone,
-
-  // F0 INVOKE_OBJECT_INIT_RANGE
+  // E9 INVOKE_VIRTUAL_QUICK
   kAnInvoke | kAnHeavyWeight,
 
-  // F1 RETURN_VOID_BARRIER
-  kAnBranch,
-
-  // F2 IGET_QUICK
-  kAnNone,
-
-  // F3 IGET_WIDE_QUICK
-  kAnNone,
-
-  // F4 IGET_OBJECT_QUICK
-  kAnNone,
-
-  // F5 IPUT_QUICK
-  kAnNone,
-
-  // F6 IPUT_WIDE_QUICK
-  kAnNone,
-
-  // F7 IPUT_OBJECT_QUICK
-  kAnNone,
-
-  // F8 INVOKE_VIRTUAL_QUICK
+  // EA INVOKE_VIRTUAL_RANGE_QUICK
   kAnInvoke | kAnHeavyWeight,
 
-  // F9 INVOKE_VIRTUAL_QUICK_RANGE
-  kAnInvoke | kAnHeavyWeight,
-
-  // FA INVOKE_SUPER_QUICK
-  kAnInvoke | kAnHeavyWeight,
-
-  // FB INVOKE_SUPER_QUICK_RANGE
-  kAnInvoke | kAnHeavyWeight,
-
-  // FC IPUT_OBJECT_VOLATILE
+  // EB IPUT_BOOLEAN_QUICK
   kAnNone,
 
-  // FD SGET_OBJECT_VOLATILE
+  // EC IPUT_BYTE_QUICK
   kAnNone,
 
-  // FE SPUT_OBJECT_VOLATILE
+  // ED IPUT_CHAR_QUICK
+  kAnNone,
+
+  // EE IPUT_SHORT_QUICK
+  kAnNone,
+
+  // EF IGET_BOOLEAN_QUICK
+  kAnNone,
+
+  // F0 IGET_BYTE_QUICK
+  kAnNone,
+
+  // F1 IGET_CHAR_QUICK
+  kAnNone,
+
+  // F2 IGET_SHORT_QUICK
+  kAnNone,
+
+  // F3 UNUSED_F3
+  kAnNone,
+
+  // F4 UNUSED_F4
+  kAnNone,
+
+  // F5 UNUSED_F5
+  kAnNone,
+
+  // F6 UNUSED_F6
+  kAnNone,
+
+  // F7 UNUSED_F7
+  kAnNone,
+
+  // F8 UNUSED_F8
+  kAnNone,
+
+  // F9 UNUSED_F9
+  kAnNone,
+
+  // FA UNUSED_FA
+  kAnNone,
+
+  // FB UNUSED_FB
+  kAnNone,
+
+  // FC UNUSED_FC
+  kAnNone,
+
+  // FD UNUSED_FD
+  kAnNone,
+
+  // FE UNUSED_FE
   kAnNone,
 
   // FF UNUSED_FF
@@ -1203,12 +1203,13 @@
 }
 
 void MIRGraph::DoCacheFieldLoweringInfo() {
+  static constexpr uint32_t kFieldIndexFlagQuickened = 0x80000000;
   // All IGET/IPUT/SGET/SPUT instructions take 2 code units and there must also be a RETURN.
   const uint32_t max_refs = (GetNumDalvikInsns() - 1u) / 2u;
   ScopedArenaAllocator allocator(&cu_->arena_stack);
-  uint16_t* field_idxs = allocator.AllocArray<uint16_t>(max_refs, kArenaAllocMisc);
-  DexMemAccessType* field_types = allocator.AllocArray<DexMemAccessType>(max_refs, kArenaAllocMisc);
-
+  auto* field_idxs = allocator.AllocArray<uint32_t>(max_refs, kArenaAllocMisc);
+  DexMemAccessType* field_types = allocator.AllocArray<DexMemAccessType>(
+      max_refs, kArenaAllocMisc);
   // Find IGET/IPUT/SGET/SPUT insns, store IGET/IPUT fields at the beginning, SGET/SPUT at the end.
   size_t ifield_pos = 0u;
   size_t sfield_pos = max_refs;
@@ -1221,23 +1222,36 @@
       // Get field index and try to find it among existing indexes. If found, it's usually among
       // the last few added, so we'll start the search from ifield_pos/sfield_pos. Though this
       // is a linear search, it actually performs much better than map based approach.
-      if (IsInstructionIGetOrIPut(mir->dalvikInsn.opcode)) {
-        uint16_t field_idx = mir->dalvikInsn.vC;
+      const bool is_iget_or_iput = IsInstructionIGetOrIPut(mir->dalvikInsn.opcode);
+      const bool is_iget_or_iput_quick = IsInstructionIGetQuickOrIPutQuick(mir->dalvikInsn.opcode);
+      if (is_iget_or_iput || is_iget_or_iput_quick) {
+        uint32_t field_idx;
+        DexMemAccessType access_type;
+        if (is_iget_or_iput) {
+          field_idx = mir->dalvikInsn.vC;
+          access_type = IGetOrIPutMemAccessType(mir->dalvikInsn.opcode);
+        } else {
+          DCHECK(is_iget_or_iput_quick);
+          // Set kFieldIndexFlagQuickened so that we don't deduplicate against non quickened field
+          // indexes.
+          field_idx = mir->offset | kFieldIndexFlagQuickened;
+          access_type = IGetQuickOrIPutQuickMemAccessType(mir->dalvikInsn.opcode);
+        }
         size_t i = ifield_pos;
         while (i != 0u && field_idxs[i - 1] != field_idx) {
           --i;
         }
         if (i != 0u) {
           mir->meta.ifield_lowering_info = i - 1;
-          DCHECK_EQ(field_types[i - 1], IGetOrIPutMemAccessType(mir->dalvikInsn.opcode));
+          DCHECK_EQ(field_types[i - 1], access_type);
         } else {
           mir->meta.ifield_lowering_info = ifield_pos;
           field_idxs[ifield_pos] = field_idx;
-          field_types[ifield_pos] = IGetOrIPutMemAccessType(mir->dalvikInsn.opcode);
+          field_types[ifield_pos] = access_type;
           ++ifield_pos;
         }
       } else if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) {
-        uint16_t field_idx = mir->dalvikInsn.vB;
+        auto field_idx = mir->dalvikInsn.vB;
         size_t i = sfield_pos;
         while (i != max_refs && field_idxs[i] != field_idx) {
           ++i;
@@ -1261,7 +1275,12 @@
     DCHECK_EQ(ifield_lowering_infos_.size(), 0u);
     ifield_lowering_infos_.reserve(ifield_pos);
     for (size_t pos = 0u; pos != ifield_pos; ++pos) {
-      ifield_lowering_infos_.push_back(MirIFieldLoweringInfo(field_idxs[pos], field_types[pos]));
+      const uint32_t field_idx = field_idxs[pos];
+      const bool is_quickened = (field_idx & kFieldIndexFlagQuickened) != 0;
+      const uint32_t masked_field_idx = field_idx & ~kFieldIndexFlagQuickened;
+      CHECK_LT(masked_field_idx, 1u << 16);
+      ifield_lowering_infos_.push_back(
+          MirIFieldLoweringInfo(masked_field_idx, field_types[pos], is_quickened));
     }
     MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(),
                                    ifield_lowering_infos_.data(), ifield_pos);
@@ -1282,18 +1301,19 @@
 
 void MIRGraph::DoCacheMethodLoweringInfo() {
   static constexpr uint16_t invoke_types[] = { kVirtual, kSuper, kDirect, kStatic, kInterface };
+  static constexpr uint32_t kMethodIdxFlagQuickened = 0x80000000;
 
   // Embed the map value in the entry to avoid extra padding in 64-bit builds.
   struct MapEntry {
     // Map key: target_method_idx, invoke_type, devirt_target. Ordered to avoid padding.
     const MethodReference* devirt_target;
-    uint16_t target_method_idx;
+    uint32_t target_method_idx;
+    uint32_t vtable_idx;
     uint16_t invoke_type;
     // Map value.
     uint32_t lowering_info_index;
   };
 
-  // Sort INVOKEs by method index, then by opcode, then by devirtualization target.
   struct MapEntryComparator {
     bool operator()(const MapEntry& lhs, const MapEntry& rhs) const {
       if (lhs.target_method_idx != rhs.target_method_idx) {
@@ -1302,6 +1322,9 @@
       if (lhs.invoke_type != rhs.invoke_type) {
         return lhs.invoke_type < rhs.invoke_type;
       }
+      if (lhs.vtable_idx != rhs.vtable_idx) {
+        return lhs.vtable_idx < rhs.vtable_idx;
+      }
       if (lhs.devirt_target != rhs.devirt_target) {
         if (lhs.devirt_target == nullptr) {
           return true;
@@ -1319,7 +1342,7 @@
   ScopedArenaAllocator allocator(&cu_->arena_stack);
 
   // All INVOKE instructions take 3 code units and there must also be a RETURN.
-  uint32_t max_refs = (GetNumDalvikInsns() - 1u) / 3u;
+  const uint32_t max_refs = (GetNumDalvikInsns() - 1u) / 3u;
 
   // Map invoke key (see MapEntry) to lowering info index and vice versa.
   // The invoke_map and sequential entries are essentially equivalent to Boost.MultiIndex's
@@ -1330,28 +1353,43 @@
       allocator.AllocArray<const MapEntry*>(max_refs, kArenaAllocMisc);
 
   // Find INVOKE insns and their devirtualization targets.
+  const VerifiedMethod* verified_method = GetCurrentDexCompilationUnit()->GetVerifiedMethod();
   AllNodesIterator iter(this);
   for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
     if (bb->block_type != kDalvikByteCode) {
       continue;
     }
     for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
-      if (IsInstructionInvoke(mir->dalvikInsn.opcode)) {
-        // Decode target method index and invoke type.
-        uint16_t target_method_idx = mir->dalvikInsn.vB;
-        DexInvokeType invoke_type_idx = InvokeInstructionType(mir->dalvikInsn.opcode);
-
+      const bool is_quick_invoke = IsInstructionQuickInvoke(mir->dalvikInsn.opcode);
+      const bool is_invoke = IsInstructionInvoke(mir->dalvikInsn.opcode);
+      if (is_quick_invoke || is_invoke) {
+        uint32_t vtable_index = 0;
+        uint32_t target_method_idx = 0;
+        uint32_t invoke_type_idx = 0;  // Default to virtual (in case of quickened).
+        DCHECK_EQ(invoke_types[invoke_type_idx], kVirtual);
+        if (is_quick_invoke) {
+          // We need to store the vtable index since we can't necessarily recreate it at resolve
+          // phase if the dequickening resolved to an interface method.
+          vtable_index = mir->dalvikInsn.vB;
+          // Fake up the method index by storing the mir offset so that we can read the dequicken
+          // info in resolve.
+          target_method_idx = mir->offset | kMethodIdxFlagQuickened;
+        } else {
+          DCHECK(is_invoke);
+          // Decode target method index and invoke type.
+          invoke_type_idx = InvokeInstructionType(mir->dalvikInsn.opcode);
+          target_method_idx = mir->dalvikInsn.vB;
+        }
         // Find devirtualization target.
         // TODO: The devirt map is ordered by the dex pc here. Is there a way to get INVOKEs
         // ordered by dex pc as well? That would allow us to keep an iterator to devirt targets
         // and increment it as needed instead of making O(log n) lookups.
-        const VerifiedMethod* verified_method = GetCurrentDexCompilationUnit()->GetVerifiedMethod();
         const MethodReference* devirt_target = verified_method->GetDevirtTarget(mir->offset);
-
         // Try to insert a new entry. If the insertion fails, we will have found an old one.
         MapEntry entry = {
             devirt_target,
             target_method_idx,
+            vtable_index,
             invoke_types[invoke_type_idx],
             static_cast<uint32_t>(invoke_map.size())
         };
@@ -1362,22 +1400,24 @@
       }
     }
   }
-
   if (invoke_map.empty()) {
     return;
   }
-
   // Prepare unique method infos, set method info indexes for their MIRs.
-  DCHECK_EQ(method_lowering_infos_.size(), 0u);
   const size_t count = invoke_map.size();
   method_lowering_infos_.reserve(count);
   for (size_t pos = 0u; pos != count; ++pos) {
     const MapEntry* entry = sequential_entries[pos];
-    MirMethodLoweringInfo method_info(entry->target_method_idx,
-                                      static_cast<InvokeType>(entry->invoke_type));
+    const bool is_quick = (entry->target_method_idx & kMethodIdxFlagQuickened) != 0;
+    const uint32_t masked_method_idx = entry->target_method_idx & ~kMethodIdxFlagQuickened;
+    MirMethodLoweringInfo method_info(masked_method_idx,
+                                      static_cast<InvokeType>(entry->invoke_type), is_quick);
     if (entry->devirt_target != nullptr) {
       method_info.SetDevirtualizationTarget(*entry->devirt_target);
     }
+    if (is_quick) {
+      method_info.SetVTableIndex(entry->vtable_idx);
+    }
     method_lowering_infos_.push_back(method_info);
   }
   MirMethodLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(),
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index f9f7e22..dfaff6c 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -374,7 +374,7 @@
   // 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
   DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
 
-  // 73 UNUSED_73
+  // 73 RETURN_VOID_BARRIER
   DF_NOP,
 
   // 74 INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
@@ -710,89 +710,89 @@
   // E2 USHR_INT_LIT8 vAA, vBB, #+CC
   DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
 
-  // E3 IGET_VOLATILE
+  // E3 IGET_QUICK
   DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
-  // E4 IPUT_VOLATILE
-  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
-
-  // E5 SGET_VOLATILE
-  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
-
-  // E6 SPUT_VOLATILE
-  DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS,
-
-  // E7 IGET_OBJECT_VOLATILE
-  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
-
-  // E8 IGET_WIDE_VOLATILE
+  // E4 IGET_WIDE_QUICK
   DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
-  // E9 IPUT_WIDE_VOLATILE
+  // E5 IGET_OBJECT_QUICK
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // E6 IPUT_QUICK
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // E7 IPUT_WIDE_QUICK
   DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
-  // EA SGET_WIDE_VOLATILE
-  DF_DA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS,
-
-  // EB SPUT_WIDE_VOLATILE
-  DF_UA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS,
-
-  // EC BREAKPOINT
-  DF_NOP,
-
-  // ED THROW_VERIFICATION_ERROR
-  DF_NOP | DF_UMS,
-
-  // EE EXECUTE_INLINE
-  DF_FORMAT_35C,
-
-  // EF EXECUTE_INLINE_RANGE
-  DF_FORMAT_3RC,
-
-  // F0 INVOKE_OBJECT_INIT_RANGE
-  DF_NOP,
-
-  // F1 RETURN_VOID_BARRIER
-  DF_NOP,
-
-  // F2 IGET_QUICK
-  DF_DA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
-
-  // F3 IGET_WIDE_QUICK
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
-
-  // F4 IGET_OBJECT_QUICK
-  DF_DA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
-
-  // F5 IPUT_QUICK
-  DF_UA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
-
-  // F6 IPUT_WIDE_QUICK
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
-
-  // F7 IPUT_OBJECT_QUICK
-  DF_UA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
-
-  // F8 INVOKE_VIRTUAL_QUICK
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // F9 INVOKE_VIRTUAL_QUICK_RANGE
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // FA INVOKE_SUPER_QUICK
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // FB INVOKE_SUPER_QUICK_RANGE
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // FC IPUT_OBJECT_VOLATILE
+  // E8 IPUT_OBJECT_QUICK
   DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
 
-  // FD SGET_OBJECT_VOLATILE
-  DF_DA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS,
+  // E9 INVOKE_VIRTUAL_QUICK
+  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
 
-  // FE SPUT_OBJECT_VOLATILE
-  DF_UA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS,
+  // EA INVOKE_VIRTUAL_RANGE_QUICK
+  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
+
+  // EB IPUT_BOOLEAN_QUICK vA, vB, index
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // EC IPUT_BYTE_QUICK vA, vB, index
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // ED IPUT_CHAR_QUICK vA, vB, index
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // EE IPUT_SHORT_QUICK vA, vB, index
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // EF IGET_BOOLEAN_QUICK vA, vB, index
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // F0 IGET_BYTE_QUICK vA, vB, index
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // F1 IGET_CHAR_QUICK vA, vB, index
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // F2 IGET_SHORT_QUICK vA, vB, index
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
+
+  // F3 UNUSED_F3
+  DF_NOP,
+
+  // F4 UNUSED_F4
+  DF_NOP,
+
+  // F5 UNUSED_F5
+  DF_NOP,
+
+  // F6 UNUSED_F6
+  DF_NOP,
+
+  // F7 UNUSED_F7
+  DF_NOP,
+
+  // F8 UNUSED_F8
+  DF_NOP,
+
+  // F9 UNUSED_F9
+  DF_NOP,
+
+  // FA UNUSED_FA
+  DF_NOP,
+
+  // FB UNUSED_FB
+  DF_NOP,
+
+  // FC UNUSED_FC
+  DF_NOP,
+
+  // FD UNUSED_FD
+  DF_NOP,
+
+  // FE UNUSED_FE
+  DF_NOP,
 
   // FF UNUSED_FF
   DF_NOP,
diff --git a/compiler/dex/mir_field_info.cc b/compiler/dex/mir_field_info.cc
index 53afcad..d2079a2 100644
--- a/compiler/dex/mir_field_info.cc
+++ b/compiler/dex/mir_field_info.cc
@@ -35,8 +35,9 @@
     DCHECK(field_infos != nullptr);
     DCHECK_NE(count, 0u);
     for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
-      MirIFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType());
-      DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0);
+      MirIFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType(), it->IsQuickened());
+      unresolved.field_offset_ = it->field_offset_;
+      unresolved.CheckEquals(*it);
     }
   }
 
@@ -49,13 +50,30 @@
       hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
   Handle<mirror::Class> referrer_class(hs.NewHandle(
       compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
+  const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod();
   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
   // definition) we still want to resolve fields and record all available info.
-
   for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
-    uint32_t field_idx = it->field_idx_;
-    mirror::ArtField* resolved_field =
-        compiler_driver->ResolveField(soa, dex_cache, class_loader, mUnit, field_idx, false);
+    uint32_t field_idx;
+    mirror::ArtField* resolved_field;
+    if (!it->IsQuickened()) {
+      field_idx = it->field_idx_;
+      resolved_field = compiler_driver->ResolveField(soa, dex_cache, class_loader, mUnit,
+                                                     field_idx, false);
+    } else {
+      const auto mir_offset = it->field_idx_;
+      // For quickened instructions, it->field_offset_ actually contains the mir offset.
+      // We need to use the de-quickening info to get dex file / field idx
+      auto* field_idx_ptr = verified_method->GetDequickenIndex(mir_offset);
+      CHECK(field_idx_ptr != nullptr);
+      field_idx = field_idx_ptr->index;
+      StackHandleScope<1> hs2(soa.Self());
+      auto h_dex_cache = hs2.NewHandle(compiler_driver->FindDexCache(field_idx_ptr->dex_file));
+      resolved_field = compiler_driver->ResolveFieldWithDexFile(
+          soa, h_dex_cache, class_loader, field_idx_ptr->dex_file, field_idx, false);
+      // Since we don't have a valid field index we can't go slow path later.
+      CHECK(resolved_field != nullptr);
+    }
     if (UNLIKELY(resolved_field == nullptr)) {
       continue;
     }
diff --git a/compiler/dex/mir_field_info.h b/compiler/dex/mir_field_info.h
index 98b2da8..ca56958 100644
--- a/compiler/dex/mir_field_info.h
+++ b/compiler/dex/mir_field_info.h
@@ -19,8 +19,8 @@
 
 #include "base/macros.h"
 #include "dex_file.h"
+#include "dex_instruction_utils.h"
 #include "offsets.h"
-#include "utils/dex_instruction_utils.h"
 
 namespace art {
 
@@ -39,6 +39,9 @@
   uint16_t FieldIndex() const {
     return field_idx_;
   }
+  void SetFieldIndex(uint16_t field_idx) {
+    field_idx_ = field_idx;
+  }
 
   bool IsStatic() const {
     return (flags_ & kFlagIsStatic) != 0u;
@@ -51,6 +54,9 @@
   const DexFile* DeclaringDexFile() const {
     return declaring_dex_file_;
   }
+  void SetDeclaringDexFile(const DexFile* dex_file) {
+    declaring_dex_file_ = dex_file;
+  }
 
   uint16_t DeclaringClassIndex() const {
     return declaring_class_idx_;
@@ -64,20 +70,35 @@
     return (flags_ & kFlagIsVolatile) != 0u;
   }
 
+  // IGET_QUICK, IGET_BYTE_QUICK, ...
+  bool IsQuickened() const {
+    return (flags_ & kFlagIsQuickened) != 0u;
+  }
+
   DexMemAccessType MemAccessType() const {
     return static_cast<DexMemAccessType>((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask);
   }
 
+  void CheckEquals(const MirFieldInfo& other) const {
+    CHECK_EQ(field_idx_, other.field_idx_);
+    CHECK_EQ(flags_, other.flags_);
+    CHECK_EQ(declaring_field_idx_, other.declaring_field_idx_);
+    CHECK_EQ(declaring_class_idx_, other.declaring_class_idx_);
+    CHECK_EQ(declaring_dex_file_, other.declaring_dex_file_);
+  }
+
  protected:
   enum {
     kBitIsStatic = 0,
     kBitIsVolatile,
+    kBitIsQuickened,
     kBitMemAccessTypeBegin,
     kBitMemAccessTypeEnd = kBitMemAccessTypeBegin + 3,  // 3 bits for raw type.
     kFieldInfoBitEnd = kBitMemAccessTypeEnd
   };
   static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile;
   static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic;
+  static constexpr uint16_t kFlagIsQuickened = 1u << kBitIsQuickened;
   static constexpr uint16_t kMemAccessTypeMask = 7u;
   static_assert((1u << (kBitMemAccessTypeEnd - kBitMemAccessTypeBegin)) - 1u == kMemAccessTypeMask,
                 "Invalid raw type mask");
@@ -117,8 +138,10 @@
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Construct an unresolved instance field lowering info.
-  explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type)
-      : MirFieldInfo(field_idx, kFlagIsVolatile, type),  // Without kFlagIsStatic.
+  explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type, bool is_quickened)
+      : MirFieldInfo(field_idx,
+                     kFlagIsVolatile | (is_quickened ? kFlagIsQuickened : 0u),
+                     type),  // Without kFlagIsStatic.
         field_offset_(0u) {
   }
 
@@ -134,6 +157,11 @@
     return field_offset_;
   }
 
+  void CheckEquals(const MirIFieldLoweringInfo& other) const {
+    MirFieldInfo::CheckEquals(other);
+    CHECK_EQ(field_offset_.Uint32Value(), other.field_offset_.Uint32Value());
+  }
+
  private:
   enum {
     kBitFastGet = kFieldInfoBitEnd,
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 76b5e44..f354a49 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -1673,12 +1673,6 @@
   }
 }
 
-const char* MIRGraph::GetShortyFromTargetIdx(int target_idx) {
-  // TODO: for inlining support, use current code unit.
-  const DexFile::MethodId& method_id = cu_->dex_file->GetMethodId(target_idx);
-  return cu_->dex_file->GetShorty(method_id.proto_idx_);
-}
-
 const char* MIRGraph::GetShortyFromMethodReference(const MethodReference& target_method) {
   const DexFile::MethodId& method_id =
       target_method.dex_file->GetMethodId(target_method.dex_method_index);
@@ -1724,8 +1718,7 @@
  * high-word loc for wide arguments.  Also pull up any following
  * MOVE_RESULT and incorporate it into the invoke.
  */
-CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type,
-                                  bool is_range) {
+CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range) {
   CallInfo* info = static_cast<CallInfo*>(arena_->Alloc(sizeof(CallInfo),
                                                         kArenaAllocMisc));
   MIR* move_result_mir = FindMoveResult(bb, mir);
@@ -1744,6 +1737,13 @@
   info->opt_flags = mir->optimization_flags;
   info->type = type;
   info->is_range = is_range;
+  if (IsInstructionQuickInvoke(mir->dalvikInsn.opcode)) {
+    const auto& method_info = GetMethodLoweringInfo(mir);
+    info->method_ref = method_info.GetTargetMethod();
+  } else {
+    info->method_ref = MethodReference(GetCurrentDexCompilationUnit()->GetDexFile(),
+                                       mir->dalvikInsn.vB);
+  }
   info->index = mir->dalvikInsn.vB;
   info->offset = mir->offset;
   info->mir = mir;
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index e5abd3b..3dae5b4 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -504,6 +504,7 @@
   int opt_flags;
   InvokeType type;
   uint32_t dex_idx;
+  MethodReference method_ref;
   uint32_t index;         // Method idx for invokes, type idx for FilledNewArray.
   uintptr_t direct_code;
   uintptr_t direct_method;
@@ -687,7 +688,7 @@
 
   void DoCacheMethodLoweringInfo();
 
-  const MirMethodLoweringInfo& GetMethodLoweringInfo(MIR* mir) {
+  const MirMethodLoweringInfo& GetMethodLoweringInfo(MIR* mir) const {
     DCHECK_LT(mir->meta.method_lowering_info, method_lowering_infos_.size());
     return method_lowering_infos_[mir->meta.method_lowering_info];
   }
@@ -1132,7 +1133,6 @@
   std::string GetSSAName(int ssa_reg);
   std::string GetSSANameWithConst(int ssa_reg, bool singles_only);
   void GetBlockName(BasicBlock* bb, char* name);
-  const char* GetShortyFromTargetIdx(int);
   const char* GetShortyFromMethodReference(const MethodReference& target_method);
   void DumpMIRGraph();
   CallInfo* NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range);
diff --git a/compiler/dex/mir_method_info.cc b/compiler/dex/mir_method_info.cc
index b234950..3d3d979 100644
--- a/compiler/dex/mir_method_info.cc
+++ b/compiler/dex/mir_method_info.cc
@@ -33,51 +33,103 @@
     DCHECK(method_infos != nullptr);
     DCHECK_NE(count, 0u);
     for (auto it = method_infos, end = method_infos + count; it != end; ++it) {
-      MirMethodLoweringInfo unresolved(it->MethodIndex(), it->GetInvokeType());
+      MirMethodLoweringInfo unresolved(it->MethodIndex(), it->GetInvokeType(), it->IsQuickened());
+      unresolved.declaring_dex_file_ = it->declaring_dex_file_;
+      unresolved.vtable_idx_ = it->vtable_idx_;
       if (it->target_dex_file_ != nullptr) {
         unresolved.target_dex_file_ = it->target_dex_file_;
         unresolved.target_method_idx_ = it->target_method_idx_;
       }
-      DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0);
+      if (kIsDebugBuild) {
+        unresolved.CheckEquals(*it);
+      }
     }
   }
 
   // We're going to resolve methods and check access in a tight loop. It's better to hold
   // the lock and needed references once than re-acquiring them again and again.
   ScopedObjectAccess soa(Thread::Current());
-  StackHandleScope<3> hs(soa.Self());
+  StackHandleScope<4> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
   Handle<mirror::ClassLoader> class_loader(
       hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
   Handle<mirror::Class> referrer_class(hs.NewHandle(
       compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
+  auto current_dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
   // definition) we still want to resolve methods and record all available info.
+  const DexFile* const dex_file = mUnit->GetDexFile();
+  const bool use_jit = Runtime::Current()->UseJit();
+  const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod();
 
   for (auto it = method_infos, end = method_infos + count; it != end; ++it) {
+    // For quickened invokes, the dex method idx is actually the mir offset.
+    if (it->IsQuickened()) {
+      const auto* dequicken_ref = verified_method->GetDequickenIndex(it->method_idx_);
+      CHECK(dequicken_ref != nullptr);
+      it->target_dex_file_ = dequicken_ref->dex_file;
+      it->target_method_idx_ = dequicken_ref->index;
+    }
     // Remember devirtualized invoke target and set the called method to the default.
     MethodReference devirt_ref(it->target_dex_file_, it->target_method_idx_);
     MethodReference* devirt_target = (it->target_dex_file_ != nullptr) ? &devirt_ref : nullptr;
-    it->target_dex_file_ = mUnit->GetDexFile();
-    it->target_method_idx_ = it->MethodIndex();
-
     InvokeType invoke_type = it->GetInvokeType();
-    mirror::ArtMethod* resolved_method =
-        compiler_driver->ResolveMethod(soa, dex_cache, class_loader, mUnit, it->MethodIndex(),
-                                       invoke_type);
+    mirror::ArtMethod* resolved_method = nullptr;
+    if (!it->IsQuickened()) {
+      it->target_dex_file_ = dex_file;
+      it->target_method_idx_ = it->MethodIndex();
+      current_dex_cache.Assign(dex_cache.Get());
+      resolved_method = compiler_driver->ResolveMethod(soa, dex_cache, class_loader, mUnit,
+                                                       it->MethodIndex(), invoke_type);
+    } else {
+      // The method index is actually the dex PC in this case.
+      // Calculate the proper dex file and target method idx.
+      CHECK(use_jit);
+      CHECK_EQ(invoke_type, kVirtual);
+      // Don't devirt if we are in a different dex file since we can't have direct invokes in
+      // another dex file unless we always put a direct / patch pointer.
+      devirt_target = nullptr;
+      current_dex_cache.Assign(
+          Runtime::Current()->GetClassLinker()->FindDexCache(*it->target_dex_file_));
+      CHECK(current_dex_cache.Get() != nullptr);
+      DexCompilationUnit cu(
+          mUnit->GetCompilationUnit(), mUnit->GetClassLoader(), mUnit->GetClassLinker(),
+          *it->target_dex_file_, nullptr /* code_item not used */, 0u /* class_def_idx not used */,
+          it->target_method_idx_, 0u /* access_flags not used */,
+          nullptr /* verified_method not used */);
+      resolved_method = compiler_driver->ResolveMethod(soa, current_dex_cache, class_loader, &cu,
+                                                       it->target_method_idx_, invoke_type, false);
+      if (resolved_method != nullptr) {
+        // Since this was a dequickened virtual, it is guaranteed to be resolved. However, it may be
+        // resolved to an interface method. If this is the case then change the invoke type to
+        // interface with the assumption that sharp_type will be kVirtual.
+        if (resolved_method->GetInvokeType() == kInterface) {
+          it->flags_ = (it->flags_ & ~(kInvokeTypeMask << kBitInvokeTypeBegin)) |
+              (static_cast<uint16_t>(kInterface) << kBitInvokeTypeBegin);
+        }
+      }
+    }
     if (UNLIKELY(resolved_method == nullptr)) {
       continue;
     }
     compiler_driver->GetResolvedMethodDexFileLocation(resolved_method,
         &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_method_idx_);
-    it->vtable_idx_ = compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type);
+    if (!it->IsQuickened()) {
+      // For quickened invoke virtuals we may have desharpened to an interface method which
+      // wont give us the right method index, in this case blindly dispatch or else we can't
+      // compile the method. Converting the invoke to interface dispatch doesn't work since we
+      // have no way to get the dex method index for quickened invoke virtuals in the interface
+      // trampolines.
+      it->vtable_idx_ =
+          compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type);
+    }
 
-    MethodReference target_method(mUnit->GetDexFile(), it->MethodIndex());
+    MethodReference target_method(it->target_dex_file_, it->target_method_idx_);
     int fast_path_flags = compiler_driver->IsFastInvoke(
-        soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method, &invoke_type,
-        &target_method, devirt_target, &it->direct_code_, &it->direct_method_);
-    bool is_referrers_class = (referrer_class.Get() == resolved_method->GetDeclaringClass());
-    bool is_class_initialized =
+        soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method,
+        &invoke_type, &target_method, devirt_target, &it->direct_code_, &it->direct_method_);
+    const bool is_referrers_class = referrer_class.Get() == resolved_method->GetDeclaringClass();
+    const bool is_class_initialized =
         compiler_driver->IsMethodsClassInitialized(referrer_class.Get(), resolved_method);
     uint16_t other_flags = it->flags_ &
         ~(kFlagFastPath | kFlagClassIsInitialized | (kInvokeTypeMask << kBitSharpTypeBegin));
diff --git a/compiler/dex/mir_method_info.h b/compiler/dex/mir_method_info.h
index 08fb103..e131c96 100644
--- a/compiler/dex/mir_method_info.h
+++ b/compiler/dex/mir_method_info.h
@@ -46,6 +46,9 @@
   const DexFile* DeclaringDexFile() const {
     return declaring_dex_file_;
   }
+  void SetDeclaringDexFile(const DexFile* dex_file) {
+    declaring_dex_file_ = dex_file;
+  }
 
   uint16_t DeclaringClassIndex() const {
     return declaring_class_idx_;
@@ -98,11 +101,12 @@
                       MirMethodLoweringInfo* method_infos, size_t count)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  MirMethodLoweringInfo(uint16_t method_idx, InvokeType type)
+  MirMethodLoweringInfo(uint16_t method_idx, InvokeType type, bool is_quickened)
       : MirMethodInfo(method_idx,
                       ((type == kStatic) ? kFlagIsStatic : 0u) |
                       (static_cast<uint16_t>(type) << kBitInvokeTypeBegin) |
-                      (static_cast<uint16_t>(type) << kBitSharpTypeBegin)),
+                      (static_cast<uint16_t>(type) << kBitSharpTypeBegin) |
+                      (is_quickened ? kFlagQuickened : 0u)),
         direct_code_(0u),
         direct_method_(0u),
         target_dex_file_(nullptr),
@@ -131,6 +135,11 @@
     return (flags_ & kFlagClassIsInitialized) != 0u;
   }
 
+  // Returns true iff the method invoke is INVOKE_VIRTUAL_QUICK or INVOKE_VIRTUAL_RANGE_QUICK.
+  bool IsQuickened() const {
+    return (flags_ & kFlagQuickened) != 0u;
+  }
+
   InvokeType GetInvokeType() const {
     return static_cast<InvokeType>((flags_ >> kBitInvokeTypeBegin) & kInvokeTypeMask);
   }
@@ -146,6 +155,9 @@
   uint16_t VTableIndex() const {
     return vtable_idx_;
   }
+  void SetVTableIndex(uint16_t index) {
+    vtable_idx_ = index;
+  }
 
   uintptr_t DirectCode() const {
     return direct_code_;
@@ -159,6 +171,20 @@
     return stats_flags_;
   }
 
+  void CheckEquals(const MirMethodLoweringInfo& info) const {
+    CHECK_EQ(method_idx_, info.method_idx_);
+    CHECK_EQ(flags_, info.flags_);
+    CHECK_EQ(declaring_method_idx_, info.declaring_method_idx_);
+    CHECK_EQ(declaring_class_idx_, info.declaring_class_idx_);
+    CHECK_EQ(declaring_dex_file_, info.declaring_dex_file_);
+    CHECK_EQ(direct_code_, info.direct_code_);
+    CHECK_EQ(direct_method_, info.direct_method_);
+    CHECK_EQ(target_dex_file_, info.target_dex_file_);
+    CHECK_EQ(target_method_idx_, info.target_method_idx_);
+    CHECK_EQ(vtable_idx_, info.vtable_idx_);
+    CHECK_EQ(stats_flags_, info.stats_flags_);
+  }
+
  private:
   enum {
     kBitFastPath = kMethodInfoBitEnd,
@@ -168,12 +194,14 @@
     kBitSharpTypeEnd = kBitSharpTypeBegin + 3,  // 3 bits for sharp type.
     kBitIsReferrersClass = kBitSharpTypeEnd,
     kBitClassIsInitialized,
+    kBitQuickened,
     kMethodLoweringInfoBitEnd
   };
   static_assert(kMethodLoweringInfoBitEnd <= 16, "Too many flags");
   static constexpr uint16_t kFlagFastPath = 1u << kBitFastPath;
   static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass;
   static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized;
+  static constexpr uint16_t kFlagQuickened = 1u << kBitQuickened;
   static constexpr uint16_t kInvokeTypeMask = 7u;
   static_assert((1u << (kBitInvokeTypeEnd - kBitInvokeTypeBegin)) - 1u == kInvokeTypeMask,
                 "assert invoke type bits failed");
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index fd67d4e..93749e4 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -1437,7 +1437,7 @@
       nullptr /* code_item not used */, 0u /* class_def_idx not used */, target.dex_method_index,
       0u /* access_flags not used */, nullptr /* verified_method not used */);
   DexMemAccessType type = IGetOrIPutMemAccessType(iget_or_iput->dalvikInsn.opcode);
-  MirIFieldLoweringInfo inlined_field_info(field_idx, type);
+  MirIFieldLoweringInfo inlined_field_info(field_idx, type, false);
   MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, &inlined_unit, &inlined_field_info, 1u);
   DCHECK(inlined_field_info.IsResolved());
 
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index be05b80..9ce5ebb 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -254,7 +254,7 @@
     cu_.mir_graph->method_lowering_infos_.reserve(count);
     for (size_t i = 0u; i != count; ++i) {
       const MethodDef* def = &defs[i];
-      MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type);
+      MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type, false);
       if (def->declaring_dex_file != 0u) {
         method_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         method_info.declaring_class_idx_ = def->declaring_class_idx;
@@ -407,7 +407,7 @@
     cu_.mir_graph->ifield_lowering_infos_.reserve(count);
     for (size_t i = 0u; i != count; ++i) {
       const IFieldDef* def = &defs[i];
-      MirIFieldLoweringInfo field_info(def->field_idx, def->type);
+      MirIFieldLoweringInfo field_info(def->field_idx, def->type, false);
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_class_idx_ = def->declaring_class_idx;
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 7245853..f636e3b 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -427,7 +427,7 @@
   InlineMethod intrinsic;
   {
     ReaderMutexLock mu(Thread::Current(), lock_);
-    auto it = inline_methods_.find(info->index);
+    auto it = inline_methods_.find(info->method_ref.dex_method_index);
     if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) {
       return false;
     }
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 3c9b7a3..afae89d 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -865,7 +865,12 @@
 void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size, Primitive::Type type,
                       RegLocation rl_dest, RegLocation rl_obj) {
   const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
-  DCHECK_EQ(IGetMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
+  if (kIsDebugBuild) {
+    auto mem_access_type = IsInstructionIGetQuickOrIPutQuick(mir->dalvikInsn.opcode) ?
+        IGetQuickOrIPutQuickMemAccessType(mir->dalvikInsn.opcode) :
+        IGetMemAccessType(mir->dalvikInsn.opcode);
+    DCHECK_EQ(mem_access_type, field_info.MemAccessType()) << mir->dalvikInsn.opcode;
+  }
   cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet());
   if (!ForceSlowFieldPath(cu_) && field_info.FastGet()) {
     RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile());
@@ -939,7 +944,12 @@
 void Mir2Lir::GenIPut(MIR* mir, int opt_flags, OpSize size,
                       RegLocation rl_src, RegLocation rl_obj) {
   const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
-  DCHECK_EQ(IPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
+  if (kIsDebugBuild) {
+    auto mem_access_type = IsInstructionIGetQuickOrIPutQuick(mir->dalvikInsn.opcode) ?
+        IGetQuickOrIPutQuickMemAccessType(mir->dalvikInsn.opcode) :
+        IPutMemAccessType(mir->dalvikInsn.opcode);
+    DCHECK_EQ(mem_access_type, field_info.MemAccessType());
+  }
   cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut());
   if (!ForceSlowFieldPath(cu_) && field_info.FastPut()) {
     RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile());
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 8e3df7c..040b07c 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -863,11 +863,12 @@
   RegLocation res;
   if (info->result.location == kLocInvalid) {
     // If result is unused, return a sink target based on type of invoke target.
-    res = GetReturn(ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0]));
+    res = GetReturn(
+        ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0]));
   } else {
     res = info->result;
     DCHECK_EQ(LocToRegClass(res),
-              ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0]));
+              ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0]));
   }
   return res;
 }
@@ -876,11 +877,12 @@
   RegLocation res;
   if (info->result.location == kLocInvalid) {
     // If result is unused, return a sink target based on type of invoke target.
-    res = GetReturnWide(ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0]));
+    res = GetReturnWide(ShortyToRegClass(
+        mir_graph_->GetShortyFromMethodReference(info->method_ref)[0]));
   } else {
     res = info->result;
     DCHECK_EQ(LocToRegClass(res),
-              ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0]));
+              ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0]));
   }
   return res;
 }
@@ -1418,7 +1420,8 @@
 
 void Mir2Lir::GenInvoke(CallInfo* info) {
   DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
-  if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
+  const DexFile* dex_file = info->method_ref.dex_file;
+  if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(dex_file)
       ->GenIntrinsic(this, info)) {
     return;
   }
@@ -1428,7 +1431,7 @@
 void Mir2Lir::GenInvokeNoInline(CallInfo* info) {
   int call_state = 0;
   LIR* null_ck;
-  LIR** p_null_ck = NULL;
+  LIR** p_null_ck = nullptr;
   NextCallInsn next_call_insn;
   FlushAllRegs();  /* Everything to home location */
   // Explicit register usage
@@ -1440,6 +1443,7 @@
   info->type = method_info.GetSharpType();
   bool fast_path = method_info.FastPath();
   bool skip_this;
+
   if (info->type == kInterface) {
     next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
     skip_this = fast_path;
@@ -1469,7 +1473,8 @@
   // Finish up any of the call sequence not interleaved in arg loading
   while (call_state >= 0) {
     call_state = next_call_insn(cu_, info, call_state, target_method, method_info.VTableIndex(),
-                                method_info.DirectCode(), method_info.DirectMethod(), original_type);
+                                method_info.DirectCode(), method_info.DirectMethod(),
+                                original_type);
   }
   LIR* call_insn = GenCallInsn(method_info);
   MarkSafepointPC(call_insn);
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 34e5e25..966a92d 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -540,6 +540,7 @@
       GenMoveException(rl_dest);
       break;
 
+    case Instruction::RETURN_VOID_BARRIER:
     case Instruction::RETURN_VOID:
       if (((cu_->access_flags & kAccConstructor) != 0) &&
           cu_->compiler_driver->RequiresConstructorBarrier(Thread::Current(), cu_->dex_file,
@@ -790,10 +791,12 @@
       GenArrayPut(opt_flags, kUnsignedByte, rl_src[1], rl_src[2], rl_src[0], 0, false);
       break;
 
+    case Instruction::IGET_OBJECT_QUICK:
     case Instruction::IGET_OBJECT:
       GenIGet(mir, opt_flags, kReference, Primitive::kPrimNot, rl_dest, rl_src[0]);
       break;
 
+    case Instruction::IGET_WIDE_QUICK:
     case Instruction::IGET_WIDE:
       // kPrimLong and kPrimDouble share the same entrypoints.
       if (rl_dest.fp) {
@@ -803,6 +806,7 @@
       }
       break;
 
+    case Instruction::IGET_QUICK:
     case Instruction::IGET:
       if (rl_dest.fp) {
         GenIGet(mir, opt_flags, kSingle, Primitive::kPrimFloat, rl_dest, rl_src[0]);
@@ -811,43 +815,54 @@
       }
       break;
 
+    case Instruction::IGET_CHAR_QUICK:
     case Instruction::IGET_CHAR:
       GenIGet(mir, opt_flags, kUnsignedHalf, Primitive::kPrimChar, rl_dest, rl_src[0]);
       break;
 
+    case Instruction::IGET_SHORT_QUICK:
     case Instruction::IGET_SHORT:
       GenIGet(mir, opt_flags, kSignedHalf, Primitive::kPrimShort, rl_dest, rl_src[0]);
       break;
 
+    case Instruction::IGET_BOOLEAN_QUICK:
     case Instruction::IGET_BOOLEAN:
       GenIGet(mir, opt_flags, kUnsignedByte, Primitive::kPrimBoolean, rl_dest, rl_src[0]);
       break;
 
+    case Instruction::IGET_BYTE_QUICK:
     case Instruction::IGET_BYTE:
       GenIGet(mir, opt_flags, kSignedByte, Primitive::kPrimByte, rl_dest, rl_src[0]);
       break;
 
+    case Instruction::IPUT_WIDE_QUICK:
     case Instruction::IPUT_WIDE:
       GenIPut(mir, opt_flags, rl_src[0].fp ? kDouble : k64, rl_src[0], rl_src[1]);
       break;
 
+    case Instruction::IPUT_OBJECT_QUICK:
     case Instruction::IPUT_OBJECT:
       GenIPut(mir, opt_flags, kReference, rl_src[0], rl_src[1]);
       break;
 
+    case Instruction::IPUT_QUICK:
     case Instruction::IPUT:
       GenIPut(mir, opt_flags, rl_src[0].fp ? kSingle : k32, rl_src[0], rl_src[1]);
       break;
 
+    case Instruction::IPUT_BYTE_QUICK:
+    case Instruction::IPUT_BOOLEAN_QUICK:
     case Instruction::IPUT_BYTE:
     case Instruction::IPUT_BOOLEAN:
       GenIPut(mir, opt_flags, kUnsignedByte, rl_src[0], rl_src[1]);
       break;
 
+    case Instruction::IPUT_CHAR_QUICK:
     case Instruction::IPUT_CHAR:
       GenIPut(mir, opt_flags, kUnsignedHalf, rl_src[0], rl_src[1]);
       break;
 
+    case Instruction::IPUT_SHORT_QUICK:
     case Instruction::IPUT_SHORT:
       GenIPut(mir, opt_flags, kSignedHalf, rl_src[0], rl_src[1]);
       break;
@@ -921,9 +936,12 @@
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, true));
       break;
 
+    case Instruction::INVOKE_VIRTUAL_QUICK:
     case Instruction::INVOKE_VIRTUAL:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, false));
       break;
+
+    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
     case Instruction::INVOKE_VIRTUAL_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, true));
       break;
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index 19c2a5a..fcf4716 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -542,6 +542,11 @@
 void QuickCompiler::InitCompilationUnit(CompilationUnit& cu) const {
   // Disable optimizations according to instruction set.
   cu.disable_opt |= kDisabledOptimizationsPerISA[cu.instruction_set];
+  if (Runtime::Current()->UseJit()) {
+    // Disable these optimizations for JIT until quickened byte codes are done being implemented.
+    // TODO: Find a cleaner way to do this.
+    cu.disable_opt |= 1u << kLocalValueNumbering;
+  }
 }
 
 void QuickCompiler::Init() {
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 4ff173d..51a3d84 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -66,8 +66,10 @@
     // TODO: Investigate why are we doing the work again for this method and try to avoid it.
     LOG(WARNING) << "Method processed more than once: "
         << PrettyMethod(ref.dex_method_index, *ref.dex_file);
-    DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
-    DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
+    if (!Runtime::Current()->UseJit()) {
+      DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
+      DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
+    }
     DCHECK_EQ(it->second->GetDexGcMap().size(), verified_method->GetDexGcMap().size());
     delete it->second;
     verified_methods_.erase(it);
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 21e965d..42d66be 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -24,6 +24,7 @@
 #include "base/stl_util.h"
 #include "dex_file.h"
 #include "dex_instruction-inl.h"
+#include "dex_instruction_utils.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
@@ -52,6 +53,11 @@
     if (method_verifier->HasVirtualOrInterfaceInvokes()) {
       verified_method->GenerateDevirtMap(method_verifier);
     }
+
+    // Only need dequicken info for JIT so far.
+    if (Runtime::Current()->UseJit()) {
+      verified_method->GenerateDequickenMap(method_verifier);
+    }
   }
 
   if (method_verifier->HasCheckCasts()) {
@@ -65,6 +71,12 @@
   return (it != devirt_map_.end()) ? &it->second : nullptr;
 }
 
+const DexFileReference* VerifiedMethod::GetDequickenIndex(uint32_t dex_pc) const {
+  DCHECK(Runtime::Current()->UseJit());
+  auto it = dequicken_map_.find(dex_pc);
+  return (it != dequicken_map_.end()) ? &it->second : nullptr;
+}
+
 bool VerifiedMethod::IsSafeCast(uint32_t pc) const {
   return std::binary_search(safe_cast_set_.begin(), safe_cast_set_.end(), pc);
 }
@@ -182,7 +194,7 @@
   *log2_max_gc_pc = i;
 }
 
-void VerifiedMethod::GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier) {
+void VerifiedMethod::GenerateDequickenMap(verifier::MethodVerifier* method_verifier) {
   if (method_verifier->HasFailures()) {
     return;
   }
@@ -196,13 +208,24 @@
     if (is_virtual_quick || is_range_quick) {
       uint32_t dex_pc = inst->GetDexPc(insns);
       verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
-      mirror::ArtMethod* method = method_verifier->GetQuickInvokedMethod(inst, line,
-                                                                         is_range_quick);
+      mirror::ArtMethod* method =
+          method_verifier->GetQuickInvokedMethod(inst, line, is_range_quick);
       CHECK(method != nullptr);
       // The verifier must know what the type of the object was or else we would have gotten a
       // failure. Put the dex method index in the dequicken map since we need this to get number of
       // arguments in the compiler.
-      dequicken_map_.Put(dex_pc, method->ToMethodReference());
+      dequicken_map_.Put(dex_pc, DexFileReference(method->GetDexFile(),
+                                                  method->GetDexMethodIndex()));
+    } else if (IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) {
+      uint32_t dex_pc = inst->GetDexPc(insns);
+      verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+      mirror::ArtField* field = method_verifier->GetQuickFieldAccess(inst, line);
+      CHECK(field != nullptr);
+      // The verifier must know what the type of the field was or else we would have gotten a
+      // failure. Put the dex field index in the dequicken map since we need this for lowering
+      // in the compiler.
+      // TODO: Putting a field index in a method reference is gross.
+      dequicken_map_.Put(dex_pc, DexFileReference(field->GetDexFile(), field->GetDexFieldIndex()));
     }
   }
 }
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index fe9dfd1..748bdcb 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/mutex.h"
+#include "dex_file.h"
 #include "method_reference.h"
 #include "safe_map.h"
 
@@ -39,6 +40,9 @@
   // Devirtualization map type maps dex offset to concrete method reference.
   typedef SafeMap<uint32_t, MethodReference> DevirtualizationMap;
 
+  // Devirtualization map type maps dex offset to field / method idx.
+  typedef SafeMap<uint32_t, DexFileReference> DequickenMap;
+
   static const VerifiedMethod* Create(verifier::MethodVerifier* method_verifier, bool compile)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   ~VerifiedMethod() = default;
@@ -58,6 +62,10 @@
   // Returns the devirtualization target method, or nullptr if none.
   const MethodReference* GetDevirtTarget(uint32_t dex_pc) const;
 
+  // Returns the dequicken field / method for a quick invoke / field get. Returns null if there is
+  // no entry for that dex pc.
+  const DexFileReference* GetDequickenIndex(uint32_t dex_pc) const;
+
   // Returns true if the cast can statically be verified to be redundant
   // by using the check-cast elision peephole optimization in the verifier.
   bool IsSafeCast(uint32_t pc) const;
@@ -86,7 +94,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Generate dequickening map into dequicken_map_.
-  void GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier)
+  void GenerateDequickenMap(verifier::MethodVerifier* method_verifier)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Generate safe case set into safe_cast_set_.
@@ -95,9 +103,9 @@
 
   std::vector<uint8_t> dex_gc_map_;
   DevirtualizationMap devirt_map_;
-  // Dequicken map is required for having the compiler compiled quickened invokes. The quicken map
-  // enables us to get the dex method index so that we can get the required argument count.
-  DevirtualizationMap dequicken_map_;
+  // Dequicken map is required for compiling quickened byte codes. The quicken maps from
+  // dex PC to dex method index or dex field index based on the instruction.
+  DequickenMap dequicken_map_;
   SafeCastSet safe_cast_set_;
 };
 
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index b620969..2b78e38 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -19,6 +19,7 @@
 #include "compiler_ir.h"
 #include "dex/dataflow_iterator-inl.h"
 #include "dex_flags.h"
+#include "driver/dex_compilation_unit.h"
 
 namespace art {
 
@@ -259,8 +260,8 @@
     if ((flags & Instruction::kInvoke) &&
         (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
       DCHECK_EQ(next, 0);
-      int target_idx = mir->dalvikInsn.vB;
-      const char* shorty = GetShortyFromTargetIdx(target_idx);
+      const auto& lowering_info = GetMethodLoweringInfo(mir);
+      const char* shorty = GetShortyFromMethodReference(lowering_info.GetTargetMethod());
       // Handle result type if floating point
       if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
         MIR* move_result_mir = FindMoveResult(bb, mir);
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 9948c82..4a35e9f 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -56,14 +56,13 @@
   return referrer_class;
 }
 
-inline mirror::ArtField* CompilerDriver::ResolveField(
+inline mirror::ArtField* CompilerDriver::ResolveFieldWithDexFile(
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
+    Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
     uint32_t field_idx, bool is_static) {
-  DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
-  mirror::ArtField* resolved_field = mUnit->GetClassLinker()->ResolveField(
-      *mUnit->GetDexFile(), field_idx, dex_cache, class_loader, is_static);
+  DCHECK_EQ(dex_cache->GetDexFile(), dex_file);
+  mirror::ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField(
+      *dex_file, field_idx, dex_cache, class_loader, is_static);
   DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
   if (UNLIKELY(resolved_field == nullptr)) {
     // Clean up any exception left by type resolution.
@@ -78,6 +77,19 @@
   return resolved_field;
 }
 
+inline mirror::DexCache* CompilerDriver::FindDexCache(const DexFile* dex_file) {
+  return Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
+}
+
+inline mirror::ArtField* CompilerDriver::ResolveField(
+    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
+    uint32_t field_idx, bool is_static) {
+  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
+                                 is_static);
+}
+
 inline void CompilerDriver::GetResolvedFieldDexFileLocation(
     mirror::ArtField* resolved_field, const DexFile** declaring_dex_file,
     uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) {
@@ -172,7 +184,7 @@
 inline mirror::ArtMethod* CompilerDriver::ResolveMethod(
     ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
-    uint32_t method_idx, InvokeType invoke_type) {
+    uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
   DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
   mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod(
@@ -184,7 +196,8 @@
     soa.Self()->ClearException();
     return nullptr;
   }
-  if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) {
+  if (check_incompatible_class_change &&
+      UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) {
     // Silently return nullptr on incompatible class change.
     return nullptr;
   }
@@ -227,14 +240,14 @@
                                                         target_method->dex_method_index))) {
     return 0;
   }
-
   // Sharpen a virtual call into a direct call when the target is known not to have been
   // overridden (ie is final).
-  bool can_sharpen_virtual_based_on_type =
+  const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile();
+  bool can_sharpen_virtual_based_on_type = same_dex_file &&
       (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
   // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
   // the super class.
-  bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) &&
+  bool can_sharpen_super_based_on_type = same_dex_file && (*invoke_type == kSuper) &&
       (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
       resolved_method->GetMethodIndex() < methods_class->GetVTableLength() &&
       (methods_class->GetVTableEntry(resolved_method->GetMethodIndex()) == resolved_method) &&
@@ -243,10 +256,10 @@
   if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) {
     // Sharpen a virtual call into a direct call. The method_idx is into referrer's
     // dex cache, check that this resolved method is where we expect it.
-    CHECK(target_method->dex_file == mUnit->GetDexFile());
-    DCHECK(dex_cache.Get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
-    CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) ==
-        resolved_method) << PrettyMethod(resolved_method);
+    CHECK_EQ(target_method->dex_file, mUnit->GetDexFile());
+    DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+    CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index),
+             resolved_method) << PrettyMethod(resolved_method);
     int stats_flags = kFlagMethodResolved;
     GetCodeAndMethodForDirectCall(/*out*/invoke_type,
                                   kDirect,  // Sharp type
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index b8a8936..15b3d08 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -360,6 +360,7 @@
       classes_to_compile_(compiled_classes),
       thread_count_(thread_count),
       stats_(new AOTCompilationStats),
+      dedupe_enabled_(true),
       dump_stats_(dump_stats),
       dump_passes_(dump_passes),
       dump_cfg_file_name_(dump_cfg_file_name),
@@ -380,12 +381,7 @@
 
   compiler_->Init();
 
-  CHECK(!Runtime::Current()->IsStarted());
-  if (image_) {
-    CHECK(image_classes_.get() != nullptr);
-  } else {
-    CHECK(image_classes_.get() == nullptr);
-  }
+  CHECK_EQ(image_, image_classes_.get() != nullptr);
 
   // Read the profile file if one is provided.
   if (!profile_file.empty()) {
@@ -399,26 +395,32 @@
 }
 
 SwapVector<uint8_t>* CompilerDriver::DeduplicateCode(const ArrayRef<const uint8_t>& code) {
+  DCHECK(dedupe_enabled_);
   return dedupe_code_.Add(Thread::Current(), code);
 }
 
 SwapSrcMap* CompilerDriver::DeduplicateSrcMappingTable(const ArrayRef<SrcMapElem>& src_map) {
+  DCHECK(dedupe_enabled_);
   return dedupe_src_mapping_table_.Add(Thread::Current(), src_map);
 }
 
 SwapVector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const ArrayRef<const uint8_t>& code) {
+  DCHECK(dedupe_enabled_);
   return dedupe_mapping_table_.Add(Thread::Current(), code);
 }
 
 SwapVector<uint8_t>* CompilerDriver::DeduplicateVMapTable(const ArrayRef<const uint8_t>& code) {
+  DCHECK(dedupe_enabled_);
   return dedupe_vmap_table_.Add(Thread::Current(), code);
 }
 
 SwapVector<uint8_t>* CompilerDriver::DeduplicateGCMap(const ArrayRef<const uint8_t>& code) {
+  DCHECK(dedupe_enabled_);
   return dedupe_gc_map_.Add(Thread::Current(), code);
 }
 
 SwapVector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info) {
+  DCHECK(dedupe_enabled_);
   return dedupe_cfi_info_.Add(Thread::Current(), cfi_info);
 }
 
@@ -491,8 +493,12 @@
 static DexToDexCompilationLevel GetDexToDexCompilationlevel(
     Thread* self, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file,
     const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  auto* const runtime = Runtime::Current();
+  if (runtime->UseJit()) {
+    return kDontDexToDexCompile;
+  }
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ClassLinker* class_linker = runtime->GetClassLinker();
   mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader);
   if (klass == nullptr) {
     CHECK(self->IsExceptionPending());
@@ -518,9 +524,8 @@
   }
 }
 
-void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger* timings) {
+void CompilerDriver::CompileOne(Thread* self, mirror::ArtMethod* method, TimingLogger* timings) {
   DCHECK(!Runtime::Current()->IsStarted());
-  Thread* self = Thread::Current();
   jobject jclass_loader;
   const DexFile* dex_file;
   uint16_t class_def_idx;
@@ -529,9 +534,8 @@
   InvokeType invoke_type = method->GetInvokeType();
   {
     ScopedObjectAccessUnchecked soa(self);
-    ScopedLocalRef<jobject>
-      local_class_loader(soa.Env(),
-                    soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader()));
+    ScopedLocalRef<jobject> local_class_loader(
+        soa.Env(), soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader()));
     jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
     // Find the dex_file
     dex_file = method->GetDexFile();
@@ -549,7 +553,7 @@
   // Can we run DEX-to-DEX compiler on this class ?
   DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
   {
-    ScopedObjectAccess soa(Thread::Current());
+    ScopedObjectAccess soa(self);
     const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
@@ -557,14 +561,35 @@
     dex_to_dex_compilation_level = GetDexToDexCompilationlevel(self, class_loader, *dex_file,
                                                                class_def);
   }
-  CompileMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, jclass_loader,
-                *dex_file, dex_to_dex_compilation_level, true);
+  CompileMethod(self, code_item, access_flags, invoke_type, class_def_idx, method_idx,
+                jclass_loader, *dex_file, dex_to_dex_compilation_level, true);
 
   self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
-
   self->TransitionFromSuspendedToRunnable();
 }
 
+CompiledMethod* CompilerDriver::CompileMethod(Thread* self, mirror::ArtMethod* method) {
+  const uint32_t method_idx = method->GetDexMethodIndex();
+  const uint32_t access_flags = method->GetAccessFlags();
+  const InvokeType invoke_type = method->GetInvokeType();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      method->GetDeclaringClass()->GetClassLoader()));
+  jobject jclass_loader = class_loader.ToJObject();
+  const DexFile* dex_file = method->GetDexFile();
+  const uint16_t class_def_idx = method->GetClassDefIndex();
+  const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
+  DexToDexCompilationLevel dex_to_dex_compilation_level =
+      GetDexToDexCompilationlevel(self, class_loader, *dex_file, class_def);
+  const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+  self->TransitionFromRunnableToSuspended(kNative);
+  CompileMethod(self, code_item, access_flags, invoke_type, class_def_idx, method_idx,
+                jclass_loader, *dex_file, dex_to_dex_compilation_level, true);
+  auto* compiled_method = GetCompiledMethod(MethodReference(dex_file, method_idx));
+  self->TransitionFromSuspendedToRunnable();
+  return compiled_method;
+}
+
 void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                              ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
@@ -1035,7 +1060,8 @@
                                         bool* is_type_initialized, bool* use_direct_type_ptr,
                                         uintptr_t* direct_type_ptr, bool* out_is_finalizable) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
+  Runtime* runtime = Runtime::Current();
+  mirror::DexCache* dex_cache = runtime->GetClassLinker()->FindDexCache(dex_file);
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == nullptr) {
     return false;
@@ -1045,7 +1071,8 @@
     return false;
   }
   *out_is_finalizable = resolved_class->IsFinalizable();
-  const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
+  gc::Heap* heap = runtime->GetHeap();
+  const bool compiling_boot = heap->IsCompilingBoot();
   const bool support_boot_image_fixup = GetSupportBootImageFixup();
   if (compiling_boot) {
     // boot -> boot class pointers.
@@ -1061,10 +1088,15 @@
     } else {
       return false;
     }
+  } else if (runtime->UseJit() && !heap->IsMovableObject(resolved_class)) {
+    *is_type_initialized = resolved_class->IsInitialized();
+    // If the class may move around, then don't embed it as a direct pointer.
+    *use_direct_type_ptr = true;
+    *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class);
+    return true;
   } else {
     // True if the class is in the image at app compiling time.
-    const bool class_in_image =
-        Runtime::Current()->GetHeap()->FindSpaceFromObject(resolved_class, false)->IsImageSpace();
+    const bool class_in_image = heap->FindSpaceFromObject(resolved_class, false)->IsImageSpace();
     if (class_in_image && support_boot_image_fixup) {
       // boot -> app class pointers.
       *is_type_initialized = resolved_class->IsInitialized();
@@ -1257,8 +1289,10 @@
   // invoked, so this can be passed to the out-of-line runtime support code.
   *direct_code = 0;
   *direct_method = 0;
+  Runtime* const runtime = Runtime::Current();
+  gc::Heap* const heap = runtime->GetHeap();
   bool use_dex_cache = GetCompilerOptions().GetCompilePic();  // Off by default
-  const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
+  const bool compiling_boot = heap->IsCompilingBoot();
   // TODO This is somewhat hacky. We should refactor all of this invoke codepath.
   const bool force_relocations = (compiling_boot ||
                                   GetCompilerOptions().GetIncludePatchInformation());
@@ -1267,14 +1301,15 @@
   }
   // TODO: support patching on all architectures.
   use_dex_cache = use_dex_cache || (force_relocations && !support_boot_image_fixup_);
-  bool method_code_in_boot = (method->GetDeclaringClass()->GetClassLoader() == nullptr);
+  mirror::Class* declaring_class = method->GetDeclaringClass();
+  bool method_code_in_boot = declaring_class->GetClassLoader() == nullptr;
   if (!use_dex_cache) {
     if (!method_code_in_boot) {
       use_dex_cache = true;
     } else {
       bool has_clinit_trampoline =
-          method->IsStatic() && !method->GetDeclaringClass()->IsInitialized();
-      if (has_clinit_trampoline && (method->GetDeclaringClass() != referrer_class)) {
+          method->IsStatic() && !declaring_class->IsInitialized();
+      if (has_clinit_trampoline && declaring_class != referrer_class) {
         // Ensure we run the clinit trampoline unless we are invoking a static method in the same
         // class.
         use_dex_cache = true;
@@ -1302,7 +1337,9 @@
   // The method is defined not within this dex file. We need a dex cache slot within the current
   // dex file or direct pointers.
   bool must_use_direct_pointers = false;
-  if (target_method->dex_file == method->GetDeclaringClass()->GetDexCache()->GetDexFile()) {
+  mirror::DexCache* dex_cache = declaring_class->GetDexCache();
+  if (target_method->dex_file == dex_cache->GetDexFile() &&
+    !(runtime->UseJit() && dex_cache->GetResolvedMethod(method->GetDexMethodIndex()) == nullptr)) {
     target_method->dex_method_index = method->GetDexMethodIndex();
   } else {
     if (no_guarantee_of_dex_cache_entry) {
@@ -1315,7 +1352,7 @@
       } else {
         if (force_relocations && !use_dex_cache) {
           target_method->dex_method_index = method->GetDexMethodIndex();
-          target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+          target_method->dex_file = dex_cache->GetDexFile();
         }
         must_use_direct_pointers = true;
       }
@@ -1330,8 +1367,7 @@
       *type = sharp_type;
     }
   } else {
-    bool method_in_image =
-        Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace();
+    bool method_in_image = heap->FindSpaceFromObject(method, false)->IsImageSpace();
     if (method_in_image || compiling_boot) {
       // We know we must be able to get to the method in the image, so use that pointer.
       CHECK(!method->IsAbstract());
@@ -2000,10 +2036,11 @@
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
   ClassLinker* class_linker = manager->GetClassLinker();
   jobject jclass_loader = manager->GetClassLoader();
+  Thread* self = Thread::Current();
   {
     // Use a scoped object access to perform to the quick SkipClass check.
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
-    ScopedObjectAccess soa(Thread::Current());
+    ScopedObjectAccess soa(self);
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
@@ -2030,7 +2067,7 @@
   // Can we run DEX-to-DEX compiler on this class ?
   DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
   {
-    ScopedObjectAccess soa(Thread::Current());
+    ScopedObjectAccess soa(self);
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
@@ -2061,7 +2098,7 @@
       continue;
     }
     previous_direct_method_idx = method_idx;
-    driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
+    driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                           it.GetMethodInvokeType(class_def), class_def_index,
                           method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
                           compilation_enabled);
@@ -2078,7 +2115,7 @@
       continue;
     }
     previous_virtual_method_idx = method_idx;
-    driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
+    driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                           it.GetMethodInvokeType(class_def), class_def_index,
                           method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
                           compilation_enabled);
@@ -2111,10 +2148,10 @@
   }
 }
 
-void CompilerDriver::CompileMethod(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,
+void CompilerDriver::CompileMethod(Thread* self, 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,
                                    DexToDexCompilationLevel dex_to_dex_compilation_level,
                                    bool compilation_enabled) {
   CompiledMethod* compiled_method = nullptr;
@@ -2162,7 +2199,6 @@
     }
   }
 
-  Thread* self = Thread::Current();
   if (compiled_method != nullptr) {
     // Count non-relative linker patches.
     size_t non_relative_linker_patch_count = 0u;
@@ -2194,6 +2230,21 @@
   }
 }
 
+void CompilerDriver::RemoveCompiledMethod(const MethodReference& method_ref) {
+  CompiledMethod* compiled_method = nullptr;
+  {
+    MutexLock mu(Thread::Current(), compiled_methods_lock_);
+    auto it = compiled_methods_.find(method_ref);
+    if (it != compiled_methods_.end()) {
+      compiled_method = it->second;
+      compiled_methods_.erase(it);
+    }
+  }
+  if (compiled_method != nullptr) {
+    CompiledMethod::ReleaseSwapAllocatedCompiledMethod(this, compiled_method);
+  }
+}
+
 CompiledClass* CompilerDriver::GetCompiledClass(ClassReference ref) const {
   MutexLock mu(Thread::Current(), compiled_classes_lock_);
   ClassTable::const_iterator it = compiled_classes_.find(ref);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index b756244..24b6f17 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -45,6 +45,10 @@
 
 namespace art {
 
+namespace mirror {
+class DexCache;
+}  // namespace mirror
+
 namespace verifier {
 class MethodVerifier;
 }  // namespace verifier
@@ -107,8 +111,11 @@
                   TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  CompiledMethod* CompileMethod(Thread* self, mirror::ArtMethod*)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) WARN_UNUSED;
+
   // Compile a single Method.
-  void CompileOne(mirror::ArtMethod* method, TimingLogger* timings)
+  void CompileOne(Thread* self, mirror::ArtMethod* method, TimingLogger* timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   VerificationResults* GetVerificationResults() const {
@@ -172,6 +179,9 @@
   size_t GetNonRelativeLinkerPatchCount() const
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
+  // Remove and delete a compiled method.
+  void RemoveCompiledMethod(const MethodReference& method_ref);
+
   void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
                                      uint16_t class_def_index);
   bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, uint16_t class_def_index);
@@ -226,6 +236,13 @@
       uint32_t field_idx, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Resolve a field with a given dex file.
+  mirror::ArtField* ResolveFieldWithDexFile(
+      const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+      Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
+      uint32_t field_idx, bool is_static)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Get declaration location of a resolved field.
   void GetResolvedFieldDexFileLocation(
       mirror::ArtField* resolved_field, const DexFile** declaring_dex_file,
@@ -235,6 +252,10 @@
   bool IsFieldVolatile(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   MemberOffset GetFieldOffset(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Find a dex cache for a dex file.
+  inline mirror::DexCache* FindDexCache(const DexFile* dex_file)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset.
   std::pair<bool, bool> IsFastInstanceField(
       mirror::DexCache* dex_cache, mirror::Class* referrer_class,
@@ -261,7 +282,7 @@
   mirror::ArtMethod* ResolveMethod(
       ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
       Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
-      uint32_t method_idx, InvokeType invoke_type)
+      uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change = true)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get declaration location of a resolved field.
@@ -295,6 +316,13 @@
   void ProcessedStaticField(bool resolved, bool local);
   void ProcessedInvoke(InvokeType invoke_type, int flags);
 
+  void ComputeFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
+                        const ScopedObjectAccess& soa, bool is_static,
+                        mirror::ArtField** resolved_field,
+                        mirror::Class** referrer_class,
+                        mirror::DexCache** dex_cache)
+      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)
@@ -380,6 +408,13 @@
     return timings_logger_;
   }
 
+  void SetDedupeEnabled(bool dedupe_enabled) {
+    dedupe_enabled_ = dedupe_enabled;
+  }
+  bool DedupeEnabled() const {
+    return dedupe_enabled_;
+  }
+
   // Checks if class specified by type_idx is one of the image_classes_
   bool IsImageClass(const char* descriptor) const;
 
@@ -484,7 +519,7 @@
                       const std::vector<const DexFile*>& dex_files,
                       ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
-  void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
+  void CompileMethod(Thread* self, 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,
                      DexToDexCompilationLevel dex_to_dex_compilation_level,
@@ -545,6 +580,7 @@
   class AOTCompilationStats;
   std::unique_ptr<AOTCompilationStats> stats_;
 
+  bool dedupe_enabled_;
   bool dump_stats_;
   const bool dump_passes_;
   const std::string& dump_cfg_file_name_;
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
new file mode 100644
index 0000000..b1d972e
--- /dev/null
+++ b/compiler/jit/jit_compiler.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright 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 "jit_compiler.h"
+
+#include "arch/instruction_set.h"
+#include "arch/instruction_set_features.h"
+#include "compiler_callbacks.h"
+#include "dex/pass_manager.h"
+#include "dex/quick_compiler_callbacks.h"
+#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
+#include "mirror/art_method-inl.h"
+#include "oat_file-inl.h"
+#include "object_lock.h"
+#include "thread_list.h"
+#include "verifier/method_verifier-inl.h"
+
+namespace art {
+namespace jit {
+
+JitCompiler* JitCompiler::Create() {
+  return new JitCompiler();
+}
+
+extern "C" void* jit_load(CompilerCallbacks** callbacks) {
+  VLOG(jit) << "loading jit compiler";
+  auto* const jit_compiler = JitCompiler::Create();
+  CHECK(jit_compiler != nullptr);
+  *callbacks = jit_compiler->GetCompilerCallbacks();
+  VLOG(jit) << "Done loading jit compiler";
+  return jit_compiler;
+}
+
+extern "C" void jit_unload(void* handle) {
+  DCHECK(handle != nullptr);
+  delete reinterpret_cast<JitCompiler*>(handle);
+}
+
+extern "C" bool jit_compile_method(void* handle, mirror::ArtMethod* method, Thread* self)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
+  DCHECK(jit_compiler != nullptr);
+  return jit_compiler->CompileMethod(self, method);
+}
+
+JitCompiler::JitCompiler() : total_time_(0) {
+  auto* pass_manager_options = new PassManagerOptions;
+  pass_manager_options->SetDisablePassList("GVN,DCE");
+  compiler_options_.reset(new CompilerOptions(
+      CompilerOptions::kDefaultCompilerFilter,
+      CompilerOptions::kDefaultHugeMethodThreshold,
+      CompilerOptions::kDefaultLargeMethodThreshold,
+      CompilerOptions::kDefaultSmallMethodThreshold,
+      CompilerOptions::kDefaultTinyMethodThreshold,
+      CompilerOptions::kDefaultNumDexMethodsThreshold,
+      false,
+      false,
+      CompilerOptions::kDefaultTopKProfileThreshold,
+      false,
+      false,
+      false,
+      false,
+      true,  // pic
+      nullptr,
+      pass_manager_options,
+      nullptr));
+  const InstructionSet instruction_set = kRuntimeISA;
+  instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
+  cumulative_logger_.reset(new CumulativeLogger("jit times"));
+  verification_results_.reset(new VerificationResults(compiler_options_.get()));
+  method_inliner_map_.reset(new DexFileToMethodInlinerMap);
+  callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
+                                              method_inliner_map_.get()));
+  compiler_driver_.reset(new CompilerDriver(
+      compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(),
+      Compiler::kQuick, instruction_set, instruction_set_features_.get(), false,
+      nullptr, new std::set<std::string>, 1, false, true,
+      std::string(), cumulative_logger_.get(), -1, std::string()));
+  // Disable dedupe so we can remove compiled methods.
+  compiler_driver_->SetDedupeEnabled(false);
+  compiler_driver_->SetSupportBootImageFixup(false);
+}
+
+JitCompiler::~JitCompiler() {
+}
+
+bool JitCompiler::CompileMethod(Thread* self, mirror::ArtMethod* method) {
+  uint64_t start_time = NanoTime();
+  StackHandleScope<2> hs(self);
+  self->AssertNoPendingException();
+  Runtime* runtime = Runtime::Current();
+  Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
+  if (runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) {
+    VLOG(jit) << "Already compiled " << PrettyMethod(method);
+    return true;  // Already compiled
+  }
+  Handle<mirror::Class> h_class(hs.NewHandle(h_method->GetDeclaringClass()));
+  if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
+    VLOG(jit) << "JIT failed to initialize " << PrettyMethod(h_method.Get());
+    return false;
+  }
+  const DexFile* dex_file = h_class->GetDexCache()->GetDexFile();
+  MethodReference method_ref(dex_file, h_method->GetDexMethodIndex());
+  // Only verify if we don't already have verification results.
+  if (verification_results_->GetVerifiedMethod(method_ref) == nullptr) {
+    std::string error;
+    if (verifier::MethodVerifier::VerifyMethod(h_method.Get(), true, &error) ==
+        verifier::MethodVerifier::kHardFailure) {
+      VLOG(jit) << "Not compile method " << PrettyMethod(h_method.Get())
+          << " due to verification failure " << error;
+      return false;
+    }
+  }
+  CompiledMethod* compiled_method(compiler_driver_->CompileMethod(self, h_method.Get()));
+  if (compiled_method == nullptr) {
+    return false;
+  }
+  total_time_ += NanoTime() - start_time;
+  const bool result = MakeExecutable(compiled_method, h_method.Get());
+  // Remove the compiled method to save memory.
+  compiler_driver_->RemoveCompiledMethod(method_ref);
+  return result;
+}
+
+CompilerCallbacks* JitCompiler::GetCompilerCallbacks() const {
+  return callbacks_.get();
+}
+
+uint8_t* JitCompiler::WriteMethodHeaderAndCode(const CompiledMethod* compiled_method,
+                                               uint8_t* reserve_begin, uint8_t* reserve_end,
+                                               const uint8_t* mapping_table,
+                                               const uint8_t* vmap_table,
+                                               const uint8_t* gc_map) {
+  reserve_begin += sizeof(OatQuickMethodHeader);
+  reserve_begin = reinterpret_cast<uint8_t*>(
+      compiled_method->AlignCode(reinterpret_cast<uintptr_t>(reserve_begin)));
+  const auto* quick_code = compiled_method->GetQuickCode();
+  CHECK_LE(reserve_begin, reserve_end);
+  CHECK_LE(quick_code->size(), static_cast<size_t>(reserve_end - reserve_begin));
+  auto* code_ptr = reserve_begin;
+  OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(code_ptr) - 1;
+  // Construct the header last.
+  const auto frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+  const auto core_spill_mask = compiled_method->GetCoreSpillMask();
+  const auto fp_spill_mask = compiled_method->GetFpSpillMask();
+  const auto code_size = quick_code->size();
+  CHECK_NE(code_size, 0U);
+  std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr);
+  // After we are done writing we need to update the method header.
+  // Write out the method header last.
+  method_header = new(method_header)OatQuickMethodHeader(
+      code_ptr - mapping_table, code_ptr - vmap_table, code_ptr - gc_map, frame_size_in_bytes,
+      core_spill_mask, fp_spill_mask, code_size);
+  // Return the code ptr.
+  return code_ptr;
+}
+
+bool JitCompiler::AddToCodeCache(mirror::ArtMethod* method, const CompiledMethod* compiled_method,
+                                 OatFile::OatMethod* out_method) {
+  Runtime* runtime = Runtime::Current();
+  JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
+  const auto* quick_code = compiled_method->GetQuickCode();
+  if (quick_code == nullptr) {
+    return false;
+  }
+  const auto code_size = quick_code->size();
+  Thread* const self = Thread::Current();
+  const uint8_t* base = code_cache->CodeCachePtr();
+  auto* const mapping_table = compiled_method->GetMappingTable();
+  auto* const vmap_table = compiled_method->GetVmapTable();
+  auto* const gc_map = compiled_method->GetGcMap();
+  // Write out pre-header stuff.
+  uint8_t* const mapping_table_ptr = code_cache->AddDataArray(
+      self, mapping_table->data(), mapping_table->data() + mapping_table->size());
+  if (mapping_table == nullptr) {
+    return false;  // Out of data cache.
+  }
+  uint8_t* const vmap_table_ptr = code_cache->AddDataArray(
+      self, vmap_table->data(), vmap_table->data() + vmap_table->size());
+  if (vmap_table == nullptr) {
+    return false;  // Out of data cache.
+  }
+  uint8_t* const gc_map_ptr = code_cache->AddDataArray(
+      self, gc_map->data(), gc_map->data() + gc_map->size());
+  if (gc_map == nullptr) {
+    return false;  // Out of data cache.
+  }
+  // Don't touch this until you protect / unprotect the code.
+  const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32;
+  uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size);
+  if (code_reserve == nullptr) {
+    return false;
+  }
+  auto* code_ptr = WriteMethodHeaderAndCode(
+      compiled_method, code_reserve, code_reserve + reserve_size, mapping_table_ptr,
+      vmap_table_ptr, gc_map_ptr);
+
+  const size_t thumb_offset = compiled_method->CodeDelta();
+  const uint32_t code_offset = code_ptr - base + thumb_offset;
+  *out_method = OatFile::OatMethod(base, code_offset);
+  DCHECK_EQ(out_method->GetGcMap(), gc_map_ptr);
+  DCHECK_EQ(out_method->GetMappingTable(), mapping_table_ptr);
+  DCHECK_EQ(out_method->GetVmapTable(), vmap_table_ptr);
+  DCHECK_EQ(out_method->GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
+  DCHECK_EQ(out_method->GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
+  DCHECK_EQ(out_method->GetFpSpillMask(), compiled_method->GetFpSpillMask());
+  VLOG(jit)  << "JIT added " << PrettyMethod(method) << "@" << method << " ccache_size="
+      << PrettySize(code_cache->CodeCacheSize()) << ": " << reinterpret_cast<void*>(code_ptr)
+      << "," << reinterpret_cast<void*>(code_ptr + code_size);
+  return true;
+}
+
+bool JitCompiler::MakeExecutable(CompiledMethod* compiled_method, mirror::ArtMethod* method) {
+  CHECK(method != nullptr);
+  CHECK(compiled_method != nullptr);
+  OatFile::OatMethod oat_method(nullptr, 0);
+  if (!AddToCodeCache(method, compiled_method, &oat_method)) {
+    return false;
+  }
+  // TODO: Flush instruction cache.
+  oat_method.LinkMethod(method);
+  CHECK(Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method))
+      << PrettyMethod(method);
+  return true;
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
new file mode 100644
index 0000000..0876499
--- /dev/null
+++ b/compiler/jit/jit_compiler.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 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_JIT_JIT_COMPILER_H_
+#define ART_COMPILER_JIT_JIT_COMPILER_H_
+
+#include "base/mutex.h"
+#include "compiler_callbacks.h"
+#include "compiled_method.h"
+#include "dex/verification_results.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
+#include "oat_file.h"
+
+namespace art {
+
+class InstructionSetFeatures;
+
+namespace mirror {
+class ArtMethod;
+}
+
+namespace jit {
+
+class JitCompiler {
+ public:
+  static JitCompiler* Create();
+  virtual ~JitCompiler();
+  bool CompileMethod(Thread* self, mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // This is in the compiler since the runtime doesn't have access to the compiled method
+  // structures.
+  bool AddToCodeCache(mirror::ArtMethod* method, const CompiledMethod* compiled_method,
+                      OatFile::OatMethod* out_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  CompilerCallbacks* GetCompilerCallbacks() const;
+  size_t GetTotalCompileTime() const {
+    return total_time_;
+  }
+
+ private:
+  uint64_t total_time_;
+  std::unique_ptr<CompilerOptions> compiler_options_;
+  std::unique_ptr<CumulativeLogger> cumulative_logger_;
+  std::unique_ptr<VerificationResults> verification_results_;
+  std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
+  std::unique_ptr<CompilerCallbacks> callbacks_;
+  std::unique_ptr<CompilerDriver> compiler_driver_;
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
+
+  explicit JitCompiler();
+  uint8_t* WriteMethodHeaderAndCode(
+      const CompiledMethod* compiled_method, uint8_t* reserve_begin, uint8_t* reserve_end,
+      const uint8_t* mapping_table, const uint8_t* vmap_table, const uint8_t* gc_map);
+  bool MakeExecutable(CompiledMethod* compiled_method, mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+}  // namespace jit
+
+}  // namespace art
+
+#endif  // ART_COMPILER_JIT_JIT_COMPILER_H_
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 9c0157e..8411091 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -549,7 +549,7 @@
 
 struct OatWriter::VmapTableDataAccess {
   static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
-    return &compiled_method->GetVmapTable();
+    return compiled_method->GetVmapTable();
   }
 
   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index e020d31..980611f 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -341,8 +341,8 @@
       if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) {
         return lhs->GetMappingTable() < rhs->GetMappingTable();
       }
-      if (UNLIKELY(&lhs->GetVmapTable() != &rhs->GetVmapTable())) {
-        return &lhs->GetVmapTable() < &rhs->GetVmapTable();
+      if (UNLIKELY(lhs->GetVmapTable() != rhs->GetVmapTable())) {
+        return lhs->GetVmapTable() < rhs->GetVmapTable();
       }
       if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) {
         return lhs->GetGcMap() < rhs->GetGcMap();
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index ae9974d..811a3bd 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -32,14 +32,7 @@
     if (instruction != nullptr && instruction->IsIntConstant()) {
       // Normalize ValueBound with constant instruction.
       int32_t instr_const = instruction->AsIntConstant()->GetValue();
-      if (constant >= 0 && (instr_const <= INT_MAX - constant)) {
-        // No overflow.
-        instruction_ = nullptr;
-        constant_ = instr_const + constant;
-        return;
-      }
-      if (constant < 0 && (instr_const >= INT_MIN - constant)) {
-        // No underflow.
+      if (!WouldAddOverflowOrUnderflow(instr_const, constant)) {
         instruction_ = nullptr;
         constant_ = instr_const + constant;
         return;
@@ -49,6 +42,22 @@
     constant_ = constant;
   }
 
+  // Return whether (left + right) overflows or underflows.
+  static bool WouldAddOverflowOrUnderflow(int32_t left, int32_t right) {
+    if (right == 0) {
+      return false;
+    }
+    if ((right > 0) && (left <= INT_MAX - right)) {
+      // No overflow.
+      return false;
+    }
+    if ((right < 0) && (left >= INT_MIN - right)) {
+      // No underflow.
+      return false;
+    }
+    return true;
+  }
+
   static bool IsAddOrSubAConstant(HInstruction* instruction,
                                   HInstruction** left_instruction,
                                   int* right_constant) {
@@ -463,10 +472,23 @@
   // Narrow the value range of `instruction` at the end of `basic_block` with `range`,
   // and push the narrowed value range to `successor`.
   void ApplyRangeFromComparison(HInstruction* instruction, HBasicBlock* basic_block,
-                  HBasicBlock* successor, ValueRange* range) {
+                                HBasicBlock* successor, ValueRange* range) {
     ValueRange* existing_range = LookupValueRange(instruction, basic_block);
-    ValueRange* narrowed_range = (existing_range == nullptr) ?
-        range : existing_range->Narrow(range);
+    if (existing_range == nullptr) {
+      if (range != nullptr) {
+        GetValueRangeMap(successor)->Overwrite(instruction->GetId(), range);
+      }
+      return;
+    }
+    if (existing_range->IsMonotonicValueRange()) {
+      DCHECK(instruction->IsLoopHeaderPhi());
+      // Make sure the comparison is in the loop header so each increment is
+      // checked with a comparison.
+      if (instruction->GetBlock() != basic_block) {
+        return;
+      }
+    }
+    ValueRange* narrowed_range = existing_range->Narrow(range);
     if (narrowed_range != nullptr) {
       GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
     }
@@ -705,6 +727,15 @@
     // Here we are interested in the typical triangular case of nested loops,
     // such as the inner loop 'for (int j=0; j<array.length-i; j++)' where i
     // is the index for outer loop. In this case, we know j is bounded by array.length-1.
+
+    // Try to handle (array.length - i) or (array.length + c - i) format.
+    HInstruction* left_of_left;  // left input of left.
+    int32_t right_const = 0;
+    if (ValueBound::IsAddOrSubAConstant(left, &left_of_left, &right_const)) {
+      left = left_of_left;
+    }
+    // The value of left input of the sub equals (left + right_const).
+
     if (left->IsArrayLength()) {
       HInstruction* array_length = left->AsArrayLength();
       ValueRange* right_range = LookupValueRange(right, sub->GetBlock());
@@ -715,19 +746,83 @@
           HInstruction* upper_inst = upper.GetInstruction();
           // Make sure it's the same array.
           if (ValueBound::Equal(array_length, upper_inst)) {
-            // (array.length - v) where v is in [c1, array.length + c2]
-            // gets [-c2, array.length - c1] as its value range.
-            ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
-                GetGraph()->GetArena(),
-                ValueBound(nullptr, - upper.GetConstant()),
-                ValueBound(array_length, - lower.GetConstant()));
-            GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+            int32_t c0 = right_const;
+            int32_t c1 = lower.GetConstant();
+            int32_t c2 = upper.GetConstant();
+            // (array.length + c0 - v) where v is in [c1, array.length + c2]
+            // gets [c0 - c2, array.length + c0 - c1] as its value range.
+            if (!ValueBound::WouldAddOverflowOrUnderflow(c0, -c2) &&
+                !ValueBound::WouldAddOverflowOrUnderflow(c0, -c1)) {
+              if ((c0 - c1) <= 0) {
+                // array.length + (c0 - c1) won't overflow/underflow.
+                ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
+                    GetGraph()->GetArena(),
+                    ValueBound(nullptr, right_const - upper.GetConstant()),
+                    ValueBound(array_length, right_const - lower.GetConstant()));
+                GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+              }
+            }
           }
         }
       }
     }
   }
 
+  void FindAndHandlePartialArrayLength(HBinaryOperation* instruction) {
+    DCHECK(instruction->IsDiv() || instruction->IsShr() || instruction->IsUShr());
+    HInstruction* right = instruction->GetRight();
+    int32_t right_const;
+    if (right->IsIntConstant()) {
+      right_const = right->AsIntConstant()->GetValue();
+      // Detect division by two or more.
+      if ((instruction->IsDiv() && right_const <= 1) ||
+          (instruction->IsShr() && right_const < 1) ||
+          (instruction->IsUShr() && right_const < 1)) {
+        return;
+      }
+    } else {
+      return;
+    }
+
+    // Try to handle array.length/2 or (array.length-1)/2 format.
+    HInstruction* left = instruction->GetLeft();
+    HInstruction* left_of_left;  // left input of left.
+    int32_t c = 0;
+    if (ValueBound::IsAddOrSubAConstant(left, &left_of_left, &c)) {
+      left = left_of_left;
+    }
+    // The value of left input of instruction equals (left + c).
+
+    // (array_length + 1) or smaller divided by two or more
+    // always generate a value in [INT_MIN, array_length].
+    // This is true even if array_length is INT_MAX.
+    if (left->IsArrayLength() && c <= 1) {
+      if (instruction->IsUShr() && c < 0) {
+        // Make sure for unsigned shift, left side is not negative.
+        // e.g. if array_length is 2, ((array_length - 3) >>> 2) is way bigger
+        // than array_length.
+        return;
+      }
+      ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
+          GetGraph()->GetArena(),
+          ValueBound(nullptr, INT_MIN),
+          ValueBound(left, 0));
+      GetValueRangeMap(instruction->GetBlock())->Overwrite(instruction->GetId(), range);
+    }
+  }
+
+  void VisitDiv(HDiv* div) {
+    FindAndHandlePartialArrayLength(div);
+  }
+
+  void VisitShr(HShr* shr) {
+    FindAndHandlePartialArrayLength(shr);
+  }
+
+  void VisitUShr(HUShr* ushr) {
+    FindAndHandlePartialArrayLength(ushr);
+  }
+
   void VisitNewArray(HNewArray* new_array) {
     HInstruction* len = new_array->InputAt(0);
     if (!len->IsIntConstant()) {
diff --git a/compiler/optimizing/bounds_check_elimination.h b/compiler/optimizing/bounds_check_elimination.h
index 05cb185..9e98ccf 100644
--- a/compiler/optimizing/bounds_check_elimination.h
+++ b/compiler/optimizing/bounds_check_elimination.h
@@ -23,10 +23,13 @@
 
 class BoundsCheckElimination : public HOptimization {
  public:
-  explicit BoundsCheckElimination(HGraph* graph) : HOptimization(graph, true, "BCE") {}
+  explicit BoundsCheckElimination(HGraph* graph)
+      : HOptimization(graph, true, kBoundsCheckEliminiationPassName) {}
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kBoundsCheckEliminiationPassName = "BCE";
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BoundsCheckElimination);
 };
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 66c873e..a298413 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -632,7 +632,7 @@
   ASSERT_TRUE(IsRemoved(bounds_check));
 }
 
-// int[] array = new array[10];
+// int[] array = new int[10];
 // for (int i=0; i<10; i+=increment) { array[i] = 10; }
 static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
                               HInstruction** bounds_check,
@@ -708,7 +708,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
   HInstruction* bounds_check = nullptr;
   HGraph* graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGE);
@@ -718,7 +718,7 @@
   bounds_check_elimination_after_gvn.Run();
   ASSERT_TRUE(IsRemoved(bounds_check));
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
   graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
   graph->BuildDominatorTree();
@@ -727,7 +727,7 @@
   bounds_check_elimination_with_initial_1.Run();
   ASSERT_TRUE(IsRemoved(bounds_check));
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
   graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
   graph->BuildDominatorTree();
@@ -736,7 +736,7 @@
   bounds_check_elimination_with_greater_than.Run();
   ASSERT_FALSE(IsRemoved(bounds_check));
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
   graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
   graph->BuildDominatorTree();
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 3e4a616..96196de 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -80,6 +80,8 @@
 
   bool BuildGraph(const DexFile::CodeItem& code);
 
+  static constexpr const char* kBuilderPassName = "builder";
+
  private:
   // Analyzes the dex instruction and adds HInstruction to the graph
   // to execute that instruction. Returns whether the instruction can
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index e864ae1..cda5c1a 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2478,7 +2478,7 @@
   LocationSummary* locations = not_->GetLocations();
   Location out = locations->Out();
   Location in = locations->InAt(0);
-  switch (not_->InputAt(0)->GetType()) {
+  switch (not_->GetResultType()) {
     case Primitive::kPrimInt:
       __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
       break;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 0d7864fa..729bab7 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2202,7 +2202,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
-  switch (instruction->InputAt(0)->GetType()) {
+  switch (instruction->GetResultType()) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 1101569..7b35cfd 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2575,7 +2575,7 @@
   Location in = locations->InAt(0);
   Location out = locations->Out();
   DCHECK(in.Equals(out));
-  switch (not_->InputAt(0)->GetType()) {
+  switch (not_->GetResultType()) {
     case Primitive::kPrimInt:
       __ notl(out.AsRegister<Register>());
       break;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 41a19e1..74adb31 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2514,7 +2514,7 @@
   DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
             locations->Out().AsRegister<CpuRegister>().AsRegister());
   Location out = locations->Out();
-  switch (not_->InputAt(0)->GetType()) {
+  switch (not_->GetResultType()) {
     case Primitive::kPrimInt:
       __ notl(out.AsRegister<CpuRegister>());
       break;
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index c592737..cabfa48 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -17,8 +17,10 @@
 #include "graph_visualizer.h"
 
 #include "code_generator.h"
+#include "licm.h"
 #include "nodes.h"
 #include "optimization.h"
+#include "register_allocator.h"
 #include "ssa_liveness_analysis.h"
 
 namespace art {
@@ -188,6 +190,10 @@
     output_ << " " << phi->GetRegNumber();
   }
 
+  bool IsPass(const char* name) {
+    return strcmp(pass_name_, name) == 0;
+  }
+
   void PrintInstruction(HInstruction* instruction) {
     output_ << instruction->DebugName();
     instruction->Accept(this);
@@ -211,7 +217,7 @@
       }
       output_ << "])";
     }
-    if (pass_name_ == kLivenessPassName
+    if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
         && is_after_pass_
         && instruction->GetLifetimePosition() != kNoLifetime) {
       output_ << " (liveness: " << instruction->GetLifetimePosition();
@@ -221,7 +227,7 @@
         interval.Dump(output_);
       }
       output_ << ")";
-    } else if (pass_name_ == kRegisterAllocatorPassName && is_after_pass_) {
+    } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
       LocationSummary* locations = instruction->GetLocations();
       if (locations != nullptr) {
         output_ << " ( ";
@@ -236,7 +242,7 @@
         }
       }
       output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
-    } else if (pass_name_ == kLoopInvariantCodeMotionPassName) {
+    } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)) {
       output_ << " ( loop_header:";
       HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
       if (info == nullptr) {
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index 89bba2d..cb448c8 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -270,7 +270,7 @@
     set = new (allocator_) ValueSet(allocator_);
   } else {
     HBasicBlock* dominator = block->GetDominator();
-    set = sets_.Get(dominator->GetBlockId())->Copy();
+    set = sets_.Get(dominator->GetBlockId());
     if (dominator->GetSuccessors().Size() != 1 || dominator->GetSuccessors().Get(0) != block) {
       // We have to copy if the dominator has other successors, or `block` is not a successor
       // of the dominator.
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index 57e0487..e74d969 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -27,10 +27,12 @@
 class GVNOptimization : public HOptimization {
  public:
   GVNOptimization(HGraph* graph, const SideEffectsAnalysis& side_effects)
-      : HOptimization(graph, true, "GVN"), side_effects_(side_effects) {}
+      : HOptimization(graph, true, kGlobalValueNumberingPassName), side_effects_(side_effects) {}
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kGlobalValueNumberingPassName = "GVN";
+
  private:
   const SideEffectsAnalysis& side_effects_;
 
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 8e9cf83..2b08d3d 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -35,13 +35,15 @@
            CompilerDriver* compiler_driver,
            OptimizingCompilerStats* stats,
            size_t depth = 0)
-      : HOptimization(outer_graph, true, "inliner", stats),
+      : HOptimization(outer_graph, true, kInlinerPassName, stats),
         outer_compilation_unit_(outer_compilation_unit),
         compiler_driver_(compiler_driver),
         depth_(depth) {}
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kInlinerPassName = "inliner";
+
  private:
   bool TryInline(HInvoke* invoke_instruction, uint32_t method_index, InvokeType invoke_type) const;
 
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index a7ff755..0244620 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -30,9 +30,11 @@
  public:
   InstructionSimplifier(HGraph* graph,
                         OptimizingCompilerStats* stats = nullptr,
-                        const char* name = "instruction_simplifier")
+                        const char* name = kInstructionSimplifierPassName)
     : HOptimization(graph, true, name, stats) {}
 
+  static constexpr const char* kInstructionSimplifierPassName = "instruction_simplifier";
+
   void Run() OVERRIDE;
 };
 
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 29cc8ef..dbb7cba 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -29,11 +29,13 @@
 class IntrinsicsRecognizer : public HOptimization {
  public:
   IntrinsicsRecognizer(HGraph* graph, const DexFile* dex_file, CompilerDriver* driver)
-      : HOptimization(graph, true, "intrinsics_recognition"),
+      : HOptimization(graph, true, kIntrinsicsRecognizerPassName),
         dex_file_(dex_file), driver_(driver) {}
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
+
  private:
   const DexFile* dex_file_;
   CompilerDriver* driver_;
diff --git a/compiler/optimizing/licm.h b/compiler/optimizing/licm.h
index 4812394..cb6170e 100644
--- a/compiler/optimizing/licm.h
+++ b/compiler/optimizing/licm.h
@@ -31,6 +31,8 @@
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kLoopInvariantCodeMotionPassName = "licm";
+
  private:
   const SideEffectsAnalysis& side_effects_;
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 93787b8..e51bbc3 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -893,28 +893,32 @@
     exit_block_->ReplaceWith(to);
 
     // Update all predecessors of the exit block (now the `to` block)
-    // to not `HReturn` but `HGoto` instead. Also collect the return
-    // values if any, and potentially make it a phi if there are multiple
-    // predecessors.
+    // to not `HReturn` but `HGoto` instead.
     HInstruction* return_value = nullptr;
-    for (size_t i = 0, e = to->GetPredecessors().Size(); i < e; ++i) {
-      HBasicBlock* predecessor = to->GetPredecessors().Get(i);
+    bool returns_void = to->GetPredecessors().Get(0)->GetLastInstruction()->IsReturnVoid();
+    if (to->GetPredecessors().Size() == 1) {
+      HBasicBlock* predecessor = to->GetPredecessors().Get(0);
       HInstruction* last = predecessor->GetLastInstruction();
-      if (!last->IsReturnVoid()) {
-        if (return_value != nullptr) {
-          if (!return_value->IsPhi()) {
-            HPhi* phi = new (allocator) HPhi(allocator, kNoRegNumber, 0, invoke->GetType());
-            to->AddPhi(phi);
-            phi->AddInput(return_value);
-            return_value = phi;
-          }
-          return_value->AsPhi()->AddInput(last->InputAt(0));
-        } else {
-          return_value = last->InputAt(0);
-        }
+      if (!returns_void) {
+        return_value = last->InputAt(0);
       }
       predecessor->AddInstruction(new (allocator) HGoto());
       predecessor->RemoveInstruction(last);
+    } else {
+      if (!returns_void) {
+        // There will be multiple returns.
+        return_value = new (allocator) HPhi(allocator, kNoRegNumber, 0, invoke->GetType());
+        to->AddPhi(return_value->AsPhi());
+      }
+      for (size_t i = 0, e = to->GetPredecessors().Size(); i < e; ++i) {
+        HBasicBlock* predecessor = to->GetPredecessors().Get(i);
+        HInstruction* last = predecessor->GetLastInstruction();
+        if (!returns_void) {
+          return_value->AsPhi()->AddInput(last->InputAt(0));
+        }
+        predecessor->AddInstruction(new (allocator) HGoto());
+        predecessor->RemoveInstruction(last);
+      }
     }
 
     if (return_value != nullptr) {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index de448cc..7e07564 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1039,6 +1039,8 @@
   virtual bool CanThrow() const { return false; }
   bool HasSideEffects() const { return side_effects_.HasSideEffects(); }
 
+  virtual bool ActAsNullConstant() const { return false; }
+
   // Does not apply for all instructions, but having this at top level greatly
   // simplifies the null check elimination.
   virtual bool CanBeNull() const {
@@ -1049,10 +1051,14 @@
   virtual bool CanDoImplicitNullCheck() const { return false; }
 
   void SetReferenceTypeInfo(ReferenceTypeInfo reference_type_info) {
+    DCHECK_EQ(GetType(), Primitive::kPrimNot);
     reference_type_info_ = reference_type_info;
   }
 
-  ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; }
+  ReferenceTypeInfo GetReferenceTypeInfo() const {
+    DCHECK_EQ(GetType(), Primitive::kPrimNot);
+    return reference_type_info_;
+  }
 
   void AddUseAt(HInstruction* user, size_t index) {
     DCHECK(user != nullptr);
@@ -1838,6 +1844,8 @@
 
   size_t ComputeHashCode() const OVERRIDE { return 0; }
 
+  bool ActAsNullConstant() const OVERRIDE { return true; }
+
   DECLARE_INSTRUCTION(NullConstant);
 
  private:
@@ -1852,11 +1860,16 @@
 
   int32_t GetValue() const { return value_; }
 
-  virtual bool InstructionDataEquals(HInstruction* other) const {
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
     return other->AsIntConstant()->value_ == value_;
   }
 
-  virtual size_t ComputeHashCode() const { return GetValue(); }
+  size_t ComputeHashCode() const OVERRIDE { return GetValue(); }
+
+  // TODO: Null is represented by the `0` constant. In most cases we replace it
+  // with a HNullConstant but we don't do it when comparing (a != null). This
+  // method is an workaround until we fix the above.
+  bool ActAsNullConstant() const OVERRIDE { return value_ == 0; }
 
   DECLARE_INSTRUCTION(IntConstant);
 
@@ -3063,6 +3076,7 @@
   HBoundType(HInstruction* input, ReferenceTypeInfo bound_type)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         bound_type_(bound_type) {
+    DCHECK_EQ(input->GetType(), Primitive::kPrimNot);
     SetRawInputAt(0, input);
   }
 
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index af39e09..8b20281 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -22,12 +22,6 @@
 
 namespace art {
 
-static const char* kBuilderPassName = "builder";
-static const char* kSsaBuilderPassName = "ssa_builder";
-static const char* kLivenessPassName = "liveness";
-static const char* kRegisterAllocatorPassName = "register";
-static const char* kLoopInvariantCodeMotionPassName = "licm";
-
 /**
  * Abstraction to implement an optimization pass.
  */
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 2fef8c7..eb98424 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -56,7 +56,7 @@
  */
 class CodeVectorAllocator FINAL : public CodeAllocator {
  public:
-  CodeVectorAllocator() {}
+  CodeVectorAllocator() : size_(0) {}
 
   virtual uint8_t* Allocate(size_t size) {
     size_ = size;
@@ -361,11 +361,11 @@
   PrepareForRegisterAllocation(graph).Run();
   SsaLivenessAnalysis liveness(*graph, codegen);
   {
-    PassInfo pass_info(kLivenessPassName, pass_info_printer);
+    PassInfo pass_info(SsaLivenessAnalysis::kLivenessPassName, pass_info_printer);
     liveness.Analyze();
   }
   {
-    PassInfo pass_info(kRegisterAllocatorPassName, pass_info_printer);
+    PassInfo pass_info(RegisterAllocator::kRegisterAllocatorPassName, pass_info_printer);
     RegisterAllocator(graph->GetArena(), codegen, liveness).AllocateRegisters();
   }
 
@@ -495,7 +495,7 @@
   VLOG(compiler) << "Building " << method_name;
 
   {
-    PassInfo pass_info(kBuilderPassName, &pass_info_printer);
+    PassInfo pass_info(HGraphBuilder::kBuilderPassName, &pass_info_printer);
     if (!builder.BuildGraph(*code_item)) {
       CHECK(!shouldCompile) << "Could not build graph in optimizing compiler";
       return nullptr;
@@ -508,7 +508,7 @@
     VLOG(compiler) << "Optimizing " << method_name;
 
     {
-      PassInfo pass_info(kSsaBuilderPassName, &pass_info_printer);
+      PassInfo pass_info(SsaBuilder::kSsaBuilderPassName, &pass_info_printer);
       if (!graph->TryBuildingSsa()) {
         // We could not transform the graph to SSA, bailout.
         LOG(INFO) << "Skipping compilation of " << method_name << ": it contains a non natural loop";
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 76b8d7e..479b87f 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -23,8 +23,6 @@
 
 namespace art {
 
-// TODO: handle: a !=/== null.
-
 void ReferenceTypePropagation::Run() {
   // To properly propagate type info we need to visit in the dominator-based order.
   // Reverse post order guarantees a node's dominators are visited first.
@@ -55,9 +53,46 @@
   }
 
   // Add extra nodes to bound types.
+  BoundTypeForIfNotNull(block);
   BoundTypeForIfInstanceOf(block);
 }
 
+void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
+  HInstruction* lastInstruction = block->GetLastInstruction();
+  if (!lastInstruction->IsIf()) {
+    return;
+  }
+  HInstruction* ifInput = lastInstruction->InputAt(0);
+  if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
+    return;
+  }
+  HInstruction* input0 = ifInput->InputAt(0);
+  HInstruction* input1 = ifInput->InputAt(1);
+  HInstruction* obj;
+
+  if ((input0->GetType() == Primitive::kPrimNot) && input1->ActAsNullConstant()) {
+    obj = input0;
+  } else if ((input1->GetType() == Primitive::kPrimNot) && input0->ActAsNullConstant()) {
+    obj = input1;
+  } else {
+    return;
+  }
+
+  HBoundType* bound_type =
+      new (graph_->GetArena()) HBoundType(obj, ReferenceTypeInfo::CreateTop(false));
+
+  block->InsertInstructionBefore(bound_type, lastInstruction);
+  HBasicBlock* notNullBlock = ifInput->IsNotEqual()
+      ? lastInstruction->AsIf()->IfTrueSuccessor()
+      : lastInstruction->AsIf()->IfFalseSuccessor();
+  for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
+    HInstruction* user = it.Current()->GetUser();
+    if (notNullBlock->Dominates(user->GetBlock())) {
+      user->ReplaceInput(bound_type, it.Current()->GetIndex());
+    }
+  }
+}
+
 // Detects if `block` is the True block for the pattern
 // `if (x instanceof ClassX) { }`
 // If that's the case insert an HBoundType instruction to bound the type of `x`
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index e346dbf..733e18e 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -34,7 +34,7 @@
                            const DexFile& dex_file,
                            const DexCompilationUnit& dex_compilation_unit,
                            StackHandleScopeCollection* handles)
-    : HOptimization(graph, true, "reference_type_propagation"),
+    : HOptimization(graph, true, kReferenceTypePropagationPassName),
       dex_file_(dex_file),
       dex_compilation_unit_(dex_compilation_unit),
       handles_(handles),
@@ -42,6 +42,8 @@
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kReferenceTypePropagationPassName = "reference_type_propagation";
+
  private:
   void VisitNewInstance(HNewInstance* new_instance);
   void VisitLoadClass(HLoadClass* load_class);
@@ -51,6 +53,7 @@
   void UpdateBoundType(HBoundType* bound_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdatePhi(HPhi* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void BoundTypeForIfNotNull(HBasicBlock* block);
   void BoundTypeForIfInstanceOf(HBasicBlock* block);
 
   void ProcessWorklist();
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index ff2f106..579f069 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -81,6 +81,8 @@
         + double_spill_slots_.Size();
   }
 
+  static constexpr const char* kRegisterAllocatorPassName = "register";
+
  private:
   // Main methods of the allocator.
   void LinearScan();
diff --git a/compiler/optimizing/side_effects_analysis.h b/compiler/optimizing/side_effects_analysis.h
index f1c98ac..415d10c 100644
--- a/compiler/optimizing/side_effects_analysis.h
+++ b/compiler/optimizing/side_effects_analysis.h
@@ -25,7 +25,7 @@
 class SideEffectsAnalysis : public HOptimization {
  public:
   explicit SideEffectsAnalysis(HGraph* graph)
-      : HOptimization(graph, true, "SideEffects"),
+      : HOptimization(graph, true, kSideEffectsAnalysisPassName),
         graph_(graph),
         block_effects_(graph->GetArena(), graph->GetBlocks().Size(), SideEffects::None()),
         loop_effects_(graph->GetArena(), graph->GetBlocks().Size(), SideEffects::None()) {}
@@ -38,6 +38,8 @@
 
   bool HasRun() const { return has_run_; }
 
+  static constexpr const char* kSideEffectsAnalysisPassName = "SideEffects";
+
  private:
   void UpdateLoopEffects(HLoopInformation* info, SideEffects effects);
 
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 148e959..f50da46 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -60,6 +60,8 @@
 
   static HInstruction* GetReferenceTypeEquivalent(HInstruction* instruction);
 
+  static constexpr const char* kSsaBuilderPassName = "ssa_builder";
+
  private:
   // Locals for the current block being visited.
   HEnvironment* current_locals_;
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 0e68a61..45b433f 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -345,19 +345,19 @@
     LiveRange* my_range = first_range_;
     LiveRange* other_range = other->first_range_;
     do {
-      if (my_range->IntersectsWith(*other_range)) {
-        return std::max(my_range->GetStart(), other_range->GetStart());
-      } else if (my_range->IsBefore(*other_range)) {
+      if (my_range->IsBefore(*other_range)) {
         my_range = my_range->GetNext();
         if (my_range == nullptr) {
           return kNoLifetime;
         }
-      } else {
-        DCHECK(other_range->IsBefore(*my_range));
+      } else if (other_range->IsBefore(*my_range)) {
         other_range = other_range->GetNext();
         if (other_range == nullptr) {
           return kNoLifetime;
         }
+      } else {
+        DCHECK(my_range->IntersectsWith(*other_range));
+        return std::max(my_range->GetStart(), other_range->GetStart());
       }
     } while (true);
   }
@@ -816,6 +816,8 @@
     return number_of_ssa_values_;
   }
 
+  static constexpr const char* kLivenessPassName = "liveness";
+
  private:
   // Linearize the graph so that:
   // (1): a block is always after its dominator,
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index 88a5279..c4b63ab 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -29,7 +29,7 @@
 class SsaDeadPhiElimination : public HOptimization {
  public:
   explicit SsaDeadPhiElimination(HGraph* graph)
-      : HOptimization(graph, true, "dead_phi_elimination"),
+      : HOptimization(graph, true, kSsaDeadPhiEliminationPassName),
         worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
   void Run() OVERRIDE;
@@ -37,6 +37,8 @@
   void MarkDeadPhis();
   void EliminateDeadPhis();
 
+  static constexpr const char* kSsaDeadPhiEliminationPassName = "dead_phi_elimination";
+
  private:
   GrowableArray<HPhi*> worklist_;
 
@@ -54,11 +56,13 @@
 class SsaRedundantPhiElimination : public HOptimization {
  public:
   explicit SsaRedundantPhiElimination(HGraph* graph)
-      : HOptimization(graph, true, "redundant_phi_elimination"),
+      : HOptimization(graph, true, kSsaRedundantPhiEliminationPassName),
         worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
   void Run() OVERRIDE;
 
+  static constexpr const char* kSsaRedundantPhiEliminationPassName = "redundant_phi_elimination";
+
  private:
   GrowableArray<HPhi*> worklist_;
 
diff --git a/runtime/Android.mk b/runtime/Android.mk
index c647cc2..ab346e3 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -88,6 +88,9 @@
   jdwp/jdwp_socket.cc \
   jdwp/object_registry.cc \
   jni_env_ext.cc \
+  jit/jit.cc \
+  jit/jit_code_cache.cc \
+  jit/jit_instrumentation.cc \
   jni_internal.cc \
   jobject_comparator.cc \
   mem_map.cc \
@@ -298,6 +301,7 @@
   base/unix_file/fd_file.h \
   dex_file.h \
   dex_instruction.h \
+  dex_instruction_utils.h \
   gc_root.h \
   gc/allocator/rosalloc.h \
   gc/collector/gc_type.h \
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 6acc2a7..0d41a8f 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -278,6 +278,7 @@
           "memory");  // clobber all
     // TODO: Should we clobber the other registers?
 #else
+    UNUSED(arg0, arg1, arg2, code, referrer);
     LOG(WARNING) << "Was asked to invoke for an architecture I do not understand.";
     result = 0;
 #endif
@@ -503,6 +504,7 @@
           "memory");  // clobber all
     // TODO: Should we clobber the other registers?
 #else
+    UNUSED(arg0, arg1, arg2, code, referrer, hidden);
     LOG(WARNING) << "Was asked to invoke for an architecture I do not understand.";
     result = 0;
 #endif
@@ -792,6 +794,7 @@
 
   // Test done.
 #else
+  UNUSED(test);
   LOG(INFO) << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1326,6 +1329,7 @@
     EXPECT_EQ(values[i], static_cast<uint8_t>(res)) << "Iteration " << i;
   }
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping set_boolean_static as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_boolean_static as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1353,6 +1357,7 @@
     EXPECT_EQ(values[i], static_cast<int8_t>(res)) << "Iteration " << i;
   }
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping set_byte_static as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_byte_static as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1388,6 +1393,7 @@
     EXPECT_EQ(res, static_cast<uint8_t>(res2));
   }
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping set_boolean_instance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_boolean_instance as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1420,6 +1426,7 @@
     EXPECT_EQ(res, static_cast<int8_t>(res2));
   }
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping set_byte_instance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_byte_instance as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1449,6 +1456,7 @@
     EXPECT_EQ(values[i], static_cast<uint16_t>(res)) << "Iteration " << i;
   }
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping set_char_static as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_char_static as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1477,6 +1485,7 @@
     EXPECT_EQ(static_cast<int16_t>(res), values[i]) << "Iteration " << i;
   }
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping set_short_static as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_short_static as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1510,6 +1519,7 @@
     EXPECT_EQ(res, static_cast<uint16_t>(res2));
   }
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping set_char_instance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_char_instance as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1542,6 +1552,7 @@
     EXPECT_EQ(res, static_cast<int16_t>(res2));
   }
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping set_short_instance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set_short_instance as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1571,6 +1582,7 @@
     EXPECT_EQ(res, values[i]) << "Iteration " << i;
   }
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping set32static as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set32static as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1607,6 +1619,7 @@
     EXPECT_EQ(res, static_cast<int32_t>(res2));
   }
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping set32instance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set32instance as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1648,6 +1661,7 @@
 
   set_and_check_static((*f)->GetDexFieldIndex(), nullptr, self, referrer, test);
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping setObjstatic as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping setObjstatic as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1692,6 +1706,7 @@
 
   set_and_check_instance(f, obj->Get(), nullptr, self, referrer, test);
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping setObjinstance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping setObjinstance as I don't know how to do that on " << kRuntimeISA << std::endl;
diff --git a/runtime/base/arena_containers.h b/runtime/base/arena_containers.h
index 162eb16..ceff6e8 100644
--- a/runtime/base/arena_containers.h
+++ b/runtime/base/arena_containers.h
@@ -66,8 +66,8 @@
 class ArenaAllocatorAdapterKindImpl<false> {
  public:
   // Not tracking allocations, ignore the supplied kind and arbitrarily provide kArenaAllocSTL.
-  explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind) { UNUSED(kind); }
-  ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl& other) = default;
+  explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind ATTRIBUTE_UNUSED) {}
+  ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl&) = default;
   ArenaAllocKind Kind() { return kArenaAllocSTL; }
 };
 
@@ -75,7 +75,7 @@
 class ArenaAllocatorAdapterKindImpl {
  public:
   explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind) : kind_(kind) { }
-  ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl& other) = default;
+  ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl&) = default;
   ArenaAllocKind Kind() { return kind_; }
 
  private:
@@ -109,8 +109,8 @@
         ArenaAllocatorAdapterKind(other),
         arena_allocator_(other.arena_allocator_) {
   }
-  ArenaAllocatorAdapter(const ArenaAllocatorAdapter& other) = default;
-  ArenaAllocatorAdapter& operator=(const ArenaAllocatorAdapter& other) = default;
+  ArenaAllocatorAdapter(const ArenaAllocatorAdapter&) = default;
+  ArenaAllocatorAdapter& operator=(const ArenaAllocatorAdapter&) = default;
   ~ArenaAllocatorAdapter() = default;
 
  private:
@@ -147,8 +147,8 @@
         ArenaAllocatorAdapterKind(other),
         arena_allocator_(other.arena_allocator_) {
   }
-  ArenaAllocatorAdapter(const ArenaAllocatorAdapter& other) = default;
-  ArenaAllocatorAdapter& operator=(const ArenaAllocatorAdapter& other) = default;
+  ArenaAllocatorAdapter(const ArenaAllocatorAdapter&) = default;
+  ArenaAllocatorAdapter& operator=(const ArenaAllocatorAdapter&) = default;
   ~ArenaAllocatorAdapter() = default;
 
   size_type max_size() const {
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index cc1a4a1..3d007ba 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -42,6 +42,7 @@
   bool gc;
   bool heap;
   bool jdwp;
+  bool jit;
   bool jni;
   bool monitor;
   bool profiler;
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 745b209..45d2347 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -67,6 +67,7 @@
   kReferenceQueueWeakReferencesLock,
   kReferenceQueueClearedReferencesLock,
   kReferenceProcessorLock,
+  kJitCodeCacheLock,
   kRosAllocGlobalLock,
   kRosAllocBracketLock,
   kRosAllocBulkFreeLock,
diff --git a/runtime/base/scoped_arena_containers.h b/runtime/base/scoped_arena_containers.h
index 664a909..df79085 100644
--- a/runtime/base/scoped_arena_containers.h
+++ b/runtime/base/scoped_arena_containers.h
@@ -85,8 +85,8 @@
         ArenaAllocatorAdapterKind(other),
         arena_stack_(other.arena_stack_) {
   }
-  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter& other) = default;
-  ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter& other) = default;
+  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter&) = default;
+  ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter&) = default;
   ~ScopedArenaAllocatorAdapter() = default;
 
  private:
@@ -128,8 +128,8 @@
         ArenaAllocatorAdapterKind(other),
         arena_stack_(other.arena_stack_) {
   }
-  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter& other) = default;
-  ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter& other) = default;
+  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter&) = default;
+  ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter&) = default;
   ~ScopedArenaAllocatorAdapter() = default;
 
   size_type max_size() const {
diff --git a/runtime/base/variant_map.h b/runtime/base/variant_map.h
index c9718fc..8655a9e 100644
--- a/runtime/base/variant_map.h
+++ b/runtime/base/variant_map.h
@@ -120,8 +120,8 @@
 
    protected:
     // Avoid the object slicing problem; use Clone() instead.
-    VariantMapKeyRaw(const VariantMapKeyRaw& other) = default;
-    VariantMapKeyRaw(VariantMapKeyRaw&& other) = default;
+    VariantMapKeyRaw(const VariantMapKeyRaw&) = default;
+    VariantMapKeyRaw(VariantMapKeyRaw&&) = default;
 
    private:
     size_t key_counter_;  // Runtime type ID. Unique each time a new type is reified.
@@ -174,8 +174,8 @@
     deleter(reinterpret_cast<TValue*>(value));
   }
 
-  VariantMapKey(const VariantMapKey& other) = default;
-  VariantMapKey(VariantMapKey&& other) = default;
+  VariantMapKey(const VariantMapKey&) = default;
+  VariantMapKey(VariantMapKey&&) = default;
 
   template <typename Base, template <typename TV> class TKey> friend struct VariantMap;
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ee66b49..f28253a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -43,6 +43,8 @@
 #include "handle_scope.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
 #include "leb128.h"
 #include "oat.h"
 #include "oat_file.h"
@@ -91,15 +93,14 @@
   // a NoClassDefFoundError (v2 2.17.5).  The exception to this rule is if we
   // failed in verification, in which case v2 5.4.1 says we need to re-throw
   // the previous error.
-  Runtime* runtime = Runtime::Current();
-  bool is_compiler = runtime->IsCompiler();
-  if (!is_compiler) {  // Give info if this occurs at runtime.
+  Runtime* const runtime = Runtime::Current();
+  if (!runtime->IsAotCompiler()) {  // Give info if this occurs at runtime.
     LOG(INFO) << "Rejecting re-init on previously-failed class " << PrettyClass(c);
   }
 
   CHECK(c->IsErroneous()) << PrettyClass(c) << " " << c->GetStatus();
   Thread* self = Thread::Current();
-  if (is_compiler) {
+  if (runtime->IsAotCompiler()) {
     // At compile time, accurate errors and NCDFE are disabled to speed compilation.
     mirror::Throwable* pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError();
     self->SetException(ThrowLocation(), pre_allocated);
@@ -428,7 +429,7 @@
   // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
   // we do not need friend classes or a publicly exposed setter.
   quick_generic_jni_trampoline_ = GetQuickGenericJniStub();
-  if (!runtime->IsCompiler()) {
+  if (!runtime->IsAotCompiler()) {
     // We need to set up the generic trampolines since we don't have an image.
     quick_resolution_trampoline_ = GetQuickResolutionStub();
     quick_imt_conflict_trampoline_ = GetQuickImtConflictStub();
@@ -1008,10 +1009,15 @@
 
   // Failed, bail.
   if (open_oat_file.get() == nullptr) {
-    std::string error_msg;
     // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress.
-    DexFile::Open(dex_location, dex_location, &error_msg, dex_files);
-    error_msgs->push_back(error_msg);
+    if (Runtime::Current()->IsDexFileFallbackEnabled()) {
+      std::string error_msg;
+      if (!DexFile::Open(dex_location, dex_location, &error_msg, dex_files)) {
+        error_msgs->push_back(error_msg);
+      }
+    } else {
+      error_msgs->push_back("Fallback mode disabled, skipping dex files.");
+    }
     return false;
   }
 
@@ -1032,8 +1038,7 @@
                                                                const char* oat_location,
                                                                std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, nullptr,
-                                            !Runtime::Current()->IsCompiler(),
-                                            error_msg));
+                                                  !Runtime::Current()->IsAotCompiler(), error_msg));
   if (oat_file.get() == nullptr) {
     *error_msg = StringPrintf("Failed to find existing oat file at %s: %s", oat_location,
                               error_msg->c_str());
@@ -1104,8 +1109,8 @@
     return nullptr;
   }
   std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, nullptr,
-                                            !Runtime::Current()->IsCompiler(),
-                                            &error_msg));
+                                                  !Runtime::Current()->IsAotCompiler(),
+                                                  &error_msg));
   if (oat_file.get() == nullptr) {
     std::string compound_msg = StringPrintf("\nFailed to open generated oat file '%s': %s",
                                             oat_location, error_msg.c_str());
@@ -1345,7 +1350,7 @@
   *already_opened = false;
   const Runtime* runtime = Runtime::Current();
   CHECK(runtime != nullptr);
-  bool executable = !runtime->IsCompiler();
+  bool executable = !runtime->IsAotCompiler();
 
   std::string odex_error_msg;
   bool should_patch_system = false;
@@ -1513,7 +1518,7 @@
   bool success = Exec(argv, error_msg);
   if (success) {
     std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, nullptr, nullptr,
-                                                  !runtime->IsCompiler(), error_msg));
+                                                  !runtime->IsAotCompiler(), error_msg));
     bool checksum_verified = false;
     if (output.get() != nullptr && CheckOatFile(runtime, output.get(), isa, &checksum_verified,
                                                 error_msg)) {
@@ -1527,7 +1532,7 @@
                                 "but was unable to open output file '%s': %s",
                                 input_oat.c_str(), output_oat.c_str(), error_msg->c_str());
     }
-  } else if (!runtime->IsCompiler()) {
+  } else if (!runtime->IsAotCompiler()) {
     // patchoat failed which means we probably don't have enough room to place the output oat file,
     // instead of failing we should just run the interpreter from the dex files in the input oat.
     LOG(WARNING) << "Patching of oat file '" << input_oat << "' failed. Attempting to use oat file "
@@ -1614,22 +1619,20 @@
   if (oat_file != nullptr) {
     return oat_file;
   }
-
-  return OatFile::Open(oat_location, oat_location, nullptr, nullptr, !Runtime::Current()->IsCompiler(),
-                       error_msg);
+  return OatFile::Open(oat_location, oat_location, nullptr, nullptr,
+                       !Runtime::Current()->IsAotCompiler(), error_msg);
 }
 
 void ClassLinker::InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg) {
   ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
   DCHECK(obj != nullptr);
   DCHECK(class_linker != nullptr);
-  size_t pointer_size = class_linker->image_pointer_size_;
-
   if (obj->IsArtMethod()) {
     mirror::ArtMethod* method = obj->AsArtMethod();
     if (!method->IsNative()) {
+      const size_t pointer_size = class_linker->image_pointer_size_;
       method->SetEntryPointFromInterpreterPtrSize(artInterpreterToInterpreterBridge, pointer_size);
-      if (method != Runtime::Current()->GetResolutionMethod()) {
+      if (!method->IsRuntimeMethod() && method != Runtime::Current()->GetResolutionMethod()) {
         method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
                                                           pointer_size);
       }
@@ -1698,8 +1701,8 @@
   // bitmap walk.
   mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod));
   size_t art_method_object_size = mirror::ArtMethod::GetJavaLangReflectArtMethod()->GetObjectSize();
-  if (!Runtime::Current()->IsCompiler()) {
-    // Compiler supports having an image with a different pointer size than the runtime. This
+  if (!Runtime::Current()->IsAotCompiler()) {
+    // Aot compiler supports having an image with a different pointer size than the runtime. This
     // happens on the host for compile 32 bit tests since we use a 64 bit libart compiler. We may
     // also use 32 bit dex2oat on a system with 64 bit apps.
     CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(sizeof(void*)))
@@ -1714,7 +1717,7 @@
 
   // Set entry point to interpreter if in InterpretOnly mode.
   Runtime* runtime = Runtime::Current();
-  if (!runtime->IsCompiler() && runtime->GetInstrumentation()->InterpretOnly()) {
+  if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) {
     heap->VisitObjects(InitFromImageInterpretOnlyCallback, this);
   }
 
@@ -2517,31 +2520,44 @@
     return GetQuickProxyInvokeHandler();
   }
   bool found;
-  OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
-  const void* result = nullptr;
-  if (found) {
-    result = oat_method.GetQuickCode();
-  }
-
-  if (result == nullptr) {
-    if (method->IsNative()) {
-      // No code and native? Use generic trampoline.
-      result = GetQuickGenericJniStub();
-    } else {
-      // No code? You must mean to go into the interpreter.
-      result = GetQuickToInterpreterBridge();
+  jit::Jit* const jit = Runtime::Current()->GetJit();
+  if (jit != nullptr) {
+    auto* code = jit->GetCodeCache()->GetCodeFor(method);
+    if (code != nullptr) {
+      return code;
     }
   }
-  return result;
+  OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
+  if (found) {
+    auto* code = oat_method.GetQuickCode();
+    if (code != nullptr) {
+      return code;
+    }
+  }
+  if (method->IsNative()) {
+    // No code and native? Use generic trampoline.
+    return GetQuickGenericJniStub();
+  }
+  return GetQuickToInterpreterBridge();
 }
 
 const void* ClassLinker::GetOatMethodQuickCodeFor(mirror::ArtMethod* method) {
   if (method->IsNative() || method->IsAbstract() || method->IsProxyMethod()) {
     return nullptr;
   }
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  if (jit != nullptr) {
+    auto* code = jit->GetCodeCache()->GetCodeFor(method);
+    if (code != nullptr) {
+      return code;
+    }
+  }
   bool found;
   OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
-  return found ? oat_method.GetQuickCode() : nullptr;
+  if (found) {
+    return oat_method.GetQuickCode();
+  }
+  return nullptr;
 }
 
 const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
@@ -2577,7 +2593,7 @@
   }
   Runtime* runtime = Runtime::Current();
   if (!runtime->IsStarted() || runtime->UseCompileTimeClassPath()) {
-    if (runtime->IsCompiler() || runtime->GetHeap()->HasImageSpace()) {
+    if (runtime->IsAotCompiler() || runtime->GetHeap()->HasImageSpace()) {
       return;  // OAT file unavailable.
     }
   }
@@ -2630,7 +2646,7 @@
                            const OatFile::OatClass* oat_class,
                            uint32_t class_def_method_index) {
   Runtime* runtime = Runtime::Current();
-  if (runtime->IsCompiler()) {
+  if (runtime->IsAotCompiler()) {
     // The following code only applies to a non-compiler runtime.
     return;
   }
@@ -3469,7 +3485,7 @@
     EnsurePreverifiedMethods(klass);
     return;
   }
-  if (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler()) {
+  if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) {
     return;
   }
 
@@ -3485,7 +3501,7 @@
   } else {
     CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
         << PrettyClass(klass.Get());
-    CHECK(!Runtime::Current()->IsCompiler());
+    CHECK(!Runtime::Current()->IsAotCompiler());
     klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self);
   }
 
@@ -3521,7 +3537,7 @@
         self->GetException(nullptr)->SetCause(cause.Get());
       }
       ClassReference ref(klass->GetDexCache()->GetDexFile(), klass->GetDexClassDefIndex());
-      if (Runtime::Current()->IsCompiler()) {
+      if (Runtime::Current()->IsAotCompiler()) {
         Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref);
       }
       klass->SetStatus(mirror::Class::kStatusError, self);
@@ -3546,7 +3562,7 @@
   std::string error_msg;
   if (!preverified) {
     verifier_failure = verifier::MethodVerifier::VerifyClass(self, klass.Get(),
-                                                             Runtime::Current()->IsCompiler(),
+                                                             Runtime::Current()->IsAotCompiler(),
                                                              &error_msg);
   }
   if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
@@ -3574,7 +3590,7 @@
       // Soft failures at compile time should be retried at runtime. Soft
       // failures at runtime will be handled by slow paths in the generated
       // code. Set status accordingly.
-      if (Runtime::Current()->IsCompiler()) {
+      if (Runtime::Current()->IsAotCompiler()) {
         klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
       } else {
         klass->SetStatus(mirror::Class::kStatusVerified, self);
@@ -3615,7 +3631,7 @@
   // we are not compiling the image or if the class we're verifying is not part of
   // the app.  In other words, we will only check for preverification of bootclasspath
   // classes.
-  if (Runtime::Current()->IsCompiler()) {
+  if (Runtime::Current()->IsAotCompiler()) {
     // Are we compiling the bootclasspath?
     if (!Runtime::Current()->UseCompileTimeClassPath()) {
       return false;
@@ -3641,7 +3657,7 @@
   // image (that we just failed loading), and the verifier can't be run on quickened opcodes when
   // the runtime isn't started. On the other hand, app classes can be re-verified even if they are
   // already pre-opted, as then the runtime is started.
-  if (!Runtime::Current()->IsCompiler() &&
+  if (!Runtime::Current()->IsAotCompiler() &&
       !Runtime::Current()->GetHeap()->HasImageSpace() &&
       klass->GetClassLoader() != nullptr) {
     return false;
@@ -4089,7 +4105,7 @@
           CHECK(self->IsExceptionPending());
           VlogClassInitializationFailure(klass);
         } else {
-          CHECK(Runtime::Current()->IsCompiler());
+          CHECK(Runtime::Current()->IsAotCompiler());
           CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
         }
         return false;
@@ -4270,7 +4286,8 @@
     if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
       continue;
     }
-    if (klass->GetStatus() == mirror::Class::kStatusVerified && Runtime::Current()->IsCompiler()) {
+    if (klass->GetStatus() == mirror::Class::kStatusVerified &&
+        Runtime::Current()->IsAotCompiler()) {
       // Compile time initialization failed.
       return false;
     }
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index a3d3b47..c0dd197 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -287,6 +287,13 @@
     Dbg::PostException(throw_location, catch_method, catch_dex_pc, exception_object);
   }
 
+  // We only care about how many backward branches were executed in the Jit.
+  void BackwardBranch(Thread* /*thread*/, mirror::ArtMethod* method, int32_t dex_pc_offset)
+      OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    LOG(ERROR) << "Unexpected backward branch event in debugger " << PrettyMethod(method)
+               << " " << dex_pc_offset;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(DebugInstrumentationListener);
 } gDebugInstrumentationListener;
@@ -605,7 +612,7 @@
 }
 
 void Dbg::ClearWaitForEventThread() {
-  gJdwpState->ClearWaitForEventThread();
+  gJdwpState->ReleaseJdwpTokenForEvent();
 }
 
 void Dbg::Connected() {
@@ -3644,6 +3651,11 @@
         thread_list->Resume(targetThread, true);
       }
 
+      // The target thread is resumed but needs the JDWP token we're holding.
+      // We release it now and will acquire it again when the invocation is
+      // complete and the target thread suspends itself.
+      gJdwpState->ReleaseJdwpTokenForCommand();
+
       // Wait for the request to finish executing.
       while (req->invoke_needed) {
         req->cond.Wait(self);
@@ -3653,6 +3665,10 @@
 
     /* wait for thread to re-suspend itself */
     SuspendThread(thread_id, false /* request_suspension */);
+
+    // Now the thread is suspended again, we can re-acquire the JDWP token.
+    gJdwpState->AcquireJdwpTokenForCommand();
+
     self->TransitionFromSuspendedToRunnable();
   }
 
@@ -3660,7 +3676,7 @@
    * Suspend the threads.  We waited for the target thread to suspend
    * itself, so all we need to do is suspend the others.
    *
-   * The suspendAllThreads() call will double-suspend the event thread,
+   * The SuspendAllForDebugger() call will double-suspend the event thread,
    * so we want to resume the target thread once to keep the books straight.
    */
   if ((options & JDWP::INVOKE_SINGLE_THREADED) == 0) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index e121a08..c8ede48 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -1028,6 +1028,13 @@
   // from an oat file, e.g., directly from an apk.
   const OatFile* oat_file_;
 };
+
+struct DexFileReference {
+  DexFileReference(const DexFile* file, uint32_t idx) : dex_file(file), index(idx) { }
+  const DexFile* dex_file;
+  uint32_t index;
+};
+
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file);
 
 // Iterate over a dex file's ProtoId's paramters
diff --git a/compiler/utils/dex_instruction_utils.h b/runtime/dex_instruction_utils.h
similarity index 82%
rename from compiler/utils/dex_instruction_utils.h
rename to runtime/dex_instruction_utils.h
index bb2c592..1a671c5 100644
--- a/compiler/utils/dex_instruction_utils.h
+++ b/runtime/dex_instruction_utils.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_
-#define ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_
+#ifndef ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_
+#define ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_
 
 #include "dex_instruction.h"
 
@@ -58,6 +58,11 @@
       opcode != Instruction::RETURN_VOID_BARRIER;
 }
 
+constexpr bool IsInstructionQuickInvoke(Instruction::Code opcode) {
+  return opcode == Instruction::INVOKE_VIRTUAL_QUICK ||
+      opcode == Instruction::INVOKE_VIRTUAL_RANGE_QUICK;
+}
+
 constexpr bool IsInstructionInvokeStatic(Instruction::Code opcode) {
   return opcode == Instruction::INVOKE_STATIC || opcode == Instruction::INVOKE_STATIC_RANGE;
 }
@@ -102,6 +107,11 @@
   return Instruction::IGET <= code && code <= Instruction::IPUT_SHORT;
 }
 
+constexpr bool IsInstructionIGetQuickOrIPutQuick(Instruction::Code code) {
+  return (code >= Instruction::IGET_QUICK && code <= Instruction::IPUT_OBJECT_QUICK) ||
+      (code >= Instruction::IPUT_BOOLEAN_QUICK && code <= Instruction::IGET_SHORT_QUICK);
+}
+
 constexpr bool IsInstructionSGetOrSPut(Instruction::Code code) {
   return Instruction::SGET <= code && code <= Instruction::SPUT_SHORT;
 }
@@ -181,6 +191,29 @@
   return (code >= Instruction::IPUT) ? IPutMemAccessType(code) : IGetMemAccessType(code);
 }
 
+static inline DexMemAccessType IGetQuickOrIPutQuickMemAccessType(Instruction::Code code) {
+  DCHECK(IsInstructionIGetQuickOrIPutQuick(code));
+  switch (code) {
+    case Instruction::IGET_QUICK: case Instruction::IPUT_QUICK:
+      return kDexMemAccessWord;
+    case Instruction::IGET_WIDE_QUICK: case Instruction::IPUT_WIDE_QUICK:
+      return kDexMemAccessWide;
+    case Instruction::IGET_OBJECT_QUICK: case Instruction::IPUT_OBJECT_QUICK:
+      return kDexMemAccessObject;
+    case Instruction::IGET_BOOLEAN_QUICK: case Instruction::IPUT_BOOLEAN_QUICK:
+      return kDexMemAccessBoolean;
+    case Instruction::IGET_BYTE_QUICK: case Instruction::IPUT_BYTE_QUICK:
+      return kDexMemAccessByte;
+    case Instruction::IGET_CHAR_QUICK: case Instruction::IPUT_CHAR_QUICK:
+      return kDexMemAccessChar;
+    case Instruction::IGET_SHORT_QUICK: case Instruction::IPUT_SHORT_QUICK:
+      return kDexMemAccessShort;
+    default:
+      LOG(FATAL) << code;
+      UNREACHABLE();
+  }
+}
+
 constexpr DexMemAccessType SGetOrSPutMemAccessType(Instruction::Code code) {
 #if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
   DCHECK(IsInstructionSGetOrSPut(opcode));
@@ -197,4 +230,4 @@
 
 }  // namespace art
 
-#endif  // ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_
+#endif  // ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 419d555..9e159c2 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -655,7 +655,7 @@
 }
 
 bool Heap::IsCompilingBoot() const {
-  if (!Runtime::Current()->IsCompiler()) {
+  if (!Runtime::Current()->IsAotCompiler()) {
     return false;
   }
   for (const auto& space : continuous_spaces_) {
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index d873e6d..14f770d 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -788,7 +788,7 @@
 
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
                                     image_header.GetOatFileBegin(),
-                                    !Runtime::Current()->IsCompiler(), error_msg);
+                                    !Runtime::Current()->IsAotCompiler(), error_msg);
   if (oat_file == NULL) {
     *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
                               oat_filename.c_str(), GetName(), error_msg->c_str());
diff --git a/runtime/gc_root.h b/runtime/gc_root.h
index 7e0be64..c5feda5 100644
--- a/runtime/gc_root.h
+++ b/runtime/gc_root.h
@@ -71,7 +71,7 @@
 typedef void (RootCallback)(mirror::Object** root, void* arg, const RootInfo& root_info);
 
 template<class MirrorType>
-class PACKED(4) GcRoot {
+class GcRoot {
  public:
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   ALWAYS_INLINE MirrorType* Read() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 7f7870a..576a604 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -197,7 +197,7 @@
 // Contains multiple entries but only one active one, this helps us detect use after free errors
 // since the serial stored in the indirect ref wont match.
 static const size_t kIRTPrevCount = kIsDebugBuild ? 7 : 3;
-class PACKED(4) IrtEntry {
+class IrtEntry {
  public:
   void Add(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ++serial_;
@@ -218,6 +218,8 @@
   uint32_t serial_;
   GcRoot<mirror::Object> references_[kIRTPrevCount];
 };
+static_assert(sizeof(IrtEntry) == (1 + kIRTPrevCount) * sizeof(uintptr_t),
+              "Unexpected sizeof(IrtEntry)");
 
 class IrtIterator {
  public:
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 90115c3..a054462 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -31,6 +31,8 @@
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc_root-inl.h"
 #include "interpreter/interpreter.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache.h"
@@ -92,6 +94,16 @@
 
 static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  Runtime* const runtime = Runtime::Current();
+  jit::Jit* jit = runtime->GetJit();
+  if (jit != nullptr) {
+    const void* old_code_ptr = method->GetEntryPointFromQuickCompiledCode();
+    jit::JitCodeCache* code_cache = jit->GetCodeCache();
+    if (code_cache->ContainsCodePtr(old_code_ptr)) {
+      // Save the old compiled code since we need it to implement ClassLinker::GetQuickOatCodeFor.
+      code_cache->SaveCompiledCode(method, old_code_ptr);
+    }
+  }
   method->SetEntryPointFromQuickCompiledCode(quick_code);
   if (!method->IsResolutionMethod()) {
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -120,7 +132,8 @@
   }
   const void* new_quick_code;
   bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Runtime* const runtime = Runtime::Current();
+  ClassLinker* const class_linker = runtime->GetClassLinker();
   bool is_class_initialized = method->GetDeclaringClass()->IsInitialized();
   if (uninstall) {
     if ((forced_interpret_only_ || IsDeoptimized(method)) && !method->IsNative()) {
@@ -143,7 +156,6 @@
           new_quick_code = GetQuickInstrumentationEntryPoint();
         } else {
           new_quick_code = class_linker->GetQuickOatCodeFor(method);
-          DCHECK(!class_linker->IsQuickToInterpreterBridge(new_quick_code));
         }
       } else {
         new_quick_code = GetQuickResolutionStub();
@@ -397,6 +409,10 @@
     method_unwind_listeners_.push_back(listener);
     have_method_unwind_listeners_ = true;
   }
+  if ((events & kBackwardBranch) != 0) {
+    backward_branch_listeners_.push_back(listener);
+    have_backward_branch_listeners_ = true;
+  }
   if ((events & kDexPcMoved) != 0) {
     std::list<InstrumentationListener*>* modified;
     if (have_dex_pc_listeners_) {
@@ -904,6 +920,13 @@
   }
 }
 
+void Instrumentation::BackwardBranchImpl(Thread* thread, mirror::ArtMethod* method,
+                                         int32_t offset) const {
+  for (InstrumentationListener* listener : backward_branch_listeners_) {
+    listener->BackwardBranch(thread, method, offset);
+  }
+}
+
 void Instrumentation::FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
                                          mirror::ArtMethod* method, uint32_t dex_pc,
                                          mirror::ArtField* field) const {
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index cea0388..b667a40 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -94,6 +94,10 @@
                                mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
                                mirror::Throwable* exception_object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
+  // Call-back for when we get a backward branch.
+  virtual void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t dex_pc_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
 };
 
 // Instrumentation is a catch-all for when extra information is required from the runtime. The
@@ -103,13 +107,14 @@
 class Instrumentation {
  public:
   enum InstrumentationEvent {
-    kMethodEntered   = 1,  // 1 << 0
-    kMethodExited    = 2,  // 1 << 1
-    kMethodUnwind    = 4,  // 1 << 2
-    kDexPcMoved      = 8,  // 1 << 3
-    kFieldRead       = 16,  // 1 << 4,
-    kFieldWritten    = 32,  // 1 << 5
-    kExceptionCaught = 64,  // 1 << 6
+    kMethodEntered = 0x1,
+    kMethodExited = 0x2,
+    kMethodUnwind = 0x4,
+    kDexPcMoved = 0x8,
+    kFieldRead = 0x10,
+    kFieldWritten = 0x20,
+    kExceptionCaught = 0x40,
+    kBackwardBranch = 0x80,
   };
 
   Instrumentation();
@@ -244,6 +249,10 @@
     return have_exception_caught_listeners_;
   }
 
+  bool HasBackwardBranchListeners() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return have_backward_branch_listeners_;
+  }
+
   bool IsActive() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return have_dex_pc_listeners_ || have_method_entry_listeners_ || have_method_exit_listeners_ ||
         have_field_read_listeners_ || have_field_write_listeners_ ||
@@ -284,6 +293,14 @@
     }
   }
 
+  // Inform listeners that a backward branch has been taken (only supported by the interpreter).
+  void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t offset) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (UNLIKELY(HasBackwardBranchListeners())) {
+      BackwardBranchImpl(thread, method, offset);
+    }
+  }
+
   // Inform listeners that we read a field (only supported by the interpreter).
   void FieldReadEvent(Thread* thread, mirror::Object* this_object,
                       mirror::ArtMethod* method, uint32_t dex_pc,
@@ -361,6 +378,8 @@
   void DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
                            mirror::ArtMethod* method, uint32_t dex_pc) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void BackwardBranchImpl(Thread* thread, mirror::ArtMethod* method, int32_t offset) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
                            mirror::ArtMethod* method, uint32_t dex_pc,
                            mirror::ArtField* field) const
@@ -429,10 +448,14 @@
   // Do we have any exception caught listeners? Short-cut to avoid taking the instrumentation_lock_.
   bool have_exception_caught_listeners_ GUARDED_BY(Locks::mutator_lock_);
 
+  // Do we have any backward branch listeners? Short-cut to avoid taking the instrumentation_lock_.
+  bool have_backward_branch_listeners_ GUARDED_BY(Locks::mutator_lock_);
+
   // The event listeners, written to with the mutator_lock_ exclusively held.
   std::list<InstrumentationListener*> method_entry_listeners_ GUARDED_BY(Locks::mutator_lock_);
   std::list<InstrumentationListener*> method_exit_listeners_ GUARDED_BY(Locks::mutator_lock_);
   std::list<InstrumentationListener*> method_unwind_listeners_ GUARDED_BY(Locks::mutator_lock_);
+  std::list<InstrumentationListener*> backward_branch_listeners_ GUARDED_BY(Locks::mutator_lock_);
   std::shared_ptr<std::list<InstrumentationListener*>> dex_pc_listeners_
       GUARDED_BY(Locks::mutator_lock_);
   std::shared_ptr<std::list<InstrumentationListener*>> field_read_listeners_
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index e4b3247..37324ea 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -54,6 +54,12 @@
 #define UPDATE_HANDLER_TABLE() \
   currentHandlersTable = handlersTable[Runtime::Current()->GetInstrumentation()->GetInterpreterHandlerTable()]
 
+#define BACKWARD_BRANCH_INSTRUMENTATION(offset) \
+  do { \
+    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); \
+    instrumentation->BackwardBranch(self, shadow_frame.GetMethod(), offset); \
+  } while (false)
+
 #define UNREACHABLE_CODE_CHECK()                \
   do {                                          \
     if (kIsDebugBuild) {                        \
@@ -135,7 +141,7 @@
     }
   };
 
-  const bool do_assignability_check = do_access_check;
+  constexpr bool do_assignability_check = do_access_check;
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
     return JValue();
@@ -608,6 +614,7 @@
   HANDLE_INSTRUCTION_START(GOTO) {
     int8_t offset = inst->VRegA_10t(inst_data);
     if (IsBackwardBranch(offset)) {
+      BACKWARD_BRANCH_INSTRUMENTATION(offset);
       if (UNLIKELY(self->TestAllFlags())) {
         self->CheckSuspend();
         UPDATE_HANDLER_TABLE();
@@ -620,6 +627,7 @@
   HANDLE_INSTRUCTION_START(GOTO_16) {
     int16_t offset = inst->VRegA_20t();
     if (IsBackwardBranch(offset)) {
+      BACKWARD_BRANCH_INSTRUMENTATION(offset);
       if (UNLIKELY(self->TestAllFlags())) {
         self->CheckSuspend();
         UPDATE_HANDLER_TABLE();
@@ -632,6 +640,7 @@
   HANDLE_INSTRUCTION_START(GOTO_32) {
     int32_t offset = inst->VRegA_30t();
     if (IsBackwardBranch(offset)) {
+      BACKWARD_BRANCH_INSTRUMENTATION(offset);
       if (UNLIKELY(self->TestAllFlags())) {
         self->CheckSuspend();
         UPDATE_HANDLER_TABLE();
@@ -644,6 +653,7 @@
   HANDLE_INSTRUCTION_START(PACKED_SWITCH) {
     int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
     if (IsBackwardBranch(offset)) {
+      BACKWARD_BRANCH_INSTRUMENTATION(offset);
       if (UNLIKELY(self->TestAllFlags())) {
         self->CheckSuspend();
         UPDATE_HANDLER_TABLE();
@@ -656,6 +666,7 @@
   HANDLE_INSTRUCTION_START(SPARSE_SWITCH) {
     int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
     if (IsBackwardBranch(offset)) {
+      BACKWARD_BRANCH_INSTRUMENTATION(offset);
       if (UNLIKELY(self->TestAllFlags())) {
         self->CheckSuspend();
         UPDATE_HANDLER_TABLE();
@@ -758,6 +769,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) == shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
       int16_t offset = inst->VRegC_22t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -774,6 +786,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) != shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
       int16_t offset = inst->VRegC_22t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -790,6 +803,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) < shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
       int16_t offset = inst->VRegC_22t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -806,6 +820,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >= shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
       int16_t offset = inst->VRegC_22t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -822,6 +837,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) > shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
       int16_t offset = inst->VRegC_22t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -838,6 +854,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <= shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
       int16_t offset = inst->VRegC_22t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -854,6 +871,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
       int16_t offset = inst->VRegB_21t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -870,6 +888,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
       int16_t offset = inst->VRegB_21t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -886,6 +905,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
       int16_t offset = inst->VRegB_21t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -902,6 +922,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
       int16_t offset = inst->VRegB_21t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -918,6 +939,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
       int16_t offset = inst->VRegB_21t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
@@ -934,6 +956,7 @@
     if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
       int16_t offset = inst->VRegB_21t();
       if (IsBackwardBranch(offset)) {
+        BACKWARD_BRANCH_INSTRUMENTATION(offset);
         if (UNLIKELY(self->TestAllFlags())) {
           self->CheckSuspend();
           UPDATE_HANDLER_TABLE();
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index ea7c192..08332d3 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -337,7 +337,8 @@
       thread_group = args->group;
     }
 
-    if (!runtime->AttachCurrentThread(thread_name, as_daemon, thread_group, !runtime->IsCompiler())) {
+    if (!runtime->AttachCurrentThread(thread_name, as_daemon, thread_group,
+                                      !runtime->IsAotCompiler())) {
       *p_env = nullptr;
       return JNI_ERR;
     } else {
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 9f37998..e16221c 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -149,29 +149,19 @@
 
   void ExitAfterReplying(int exit_status);
 
-  /*
-   * When we hit a debugger event that requires suspension, it's important
-   * that we wait for the thread to suspend itself before processing any
-   * additional requests.  (Otherwise, if the debugger immediately sends a
-   * "resume thread" command, the resume might arrive before the thread has
-   * suspended itself.)
-   *
-   * The thread should call the "set" function before sending the event to
-   * the debugger.  The main JDWP handler loop calls "get" before processing
-   * an event, and will wait for thread suspension if it's set.  Once the
-   * thread has suspended itself, the JDWP handler calls "clear" and
-   * continues processing the current event.  This works in the suspend-all
-   * case because the event thread doesn't suspend itself until everything
-   * else has suspended.
-   *
-   * It's possible that multiple threads could encounter thread-suspending
-   * events at the same time, so we grab a mutex in the "set" call, and
-   * release it in the "clear" call.
-   */
-  // ObjectId GetWaitForEventThread();
-  void SetWaitForEventThread(ObjectId threadId)
-      LOCKS_EXCLUDED(event_thread_lock_, process_request_lock_);
-  void ClearWaitForEventThread() LOCKS_EXCLUDED(event_thread_lock_);
+  // Acquires/releases the JDWP synchronization token for the debugger
+  // thread (command handler) so no event thread posts an event while
+  // it processes a command. This must be called only from the debugger
+  // thread.
+  void AcquireJdwpTokenForCommand() LOCKS_EXCLUDED(jdwp_token_lock_);
+  void ReleaseJdwpTokenForCommand() LOCKS_EXCLUDED(jdwp_token_lock_);
+
+  // Acquires/releases the JDWP synchronization token for the event thread
+  // so no other thread (debugger thread or event thread) interleaves with
+  // it when posting an event. This must NOT be called from the debugger
+  // thread, only event thread.
+  void AcquireJdwpTokenForEvent(ObjectId threadId) LOCKS_EXCLUDED(jdwp_token_lock_);
+  void ReleaseJdwpTokenForEvent() LOCKS_EXCLUDED(jdwp_token_lock_);
 
   /*
    * These notify the debug code that something interesting has happened.  This
@@ -330,9 +320,37 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SendBufferedRequest(uint32_t type, const std::vector<iovec>& iov);
 
-  void StartProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
-  void EndProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
-  void WaitForProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+  /*
+   * When we hit a debugger event that requires suspension, it's important
+   * that we wait for the thread to suspend itself before processing any
+   * additional requests. Otherwise, if the debugger immediately sends a
+   * "resume thread" command, the resume might arrive before the thread has
+   * suspended itself.
+   *
+   * It's also important no event thread suspends while we process a command
+   * from the debugger. Otherwise we could post an event ("thread death")
+   * before sending the reply of the command being processed ("resume") and
+   * cause bad synchronization with the debugger.
+   *
+   * The thread wanting "exclusive" access to the JDWP world must call the
+   * SetWaitForJdwpToken method before processing a command from the
+   * debugger or sending an event to the debugger.
+   * Once the command is processed or the event thread has posted its event,
+   * it must call the ClearWaitForJdwpToken method to allow another thread
+   * to do JDWP stuff.
+   *
+   * Therefore the main JDWP handler loop will wait for the event thread
+   * suspension before processing the next command. Once the event thread
+   * has suspended itself and cleared the token, the JDWP handler continues
+   * processing commands. This works in the suspend-all case because the
+   * event thread doesn't suspend itself until everything else has suspended.
+   *
+   * It's possible that multiple threads could encounter thread-suspending
+   * events at the same time, so we grab a mutex in the SetWaitForJdwpToken
+   * call, and release it in the ClearWaitForJdwpToken call.
+   */
+  void SetWaitForJdwpToken(ObjectId threadId) LOCKS_EXCLUDED(jdwp_token_lock_);
+  void ClearWaitForJdwpToken() LOCKS_EXCLUDED(jdwp_token_lock_);
 
  public:  // TODO: fix privacy
   const JdwpOptions* options_;
@@ -368,24 +386,21 @@
 
   // Linked list of events requested by the debugger (breakpoints, class prep, etc).
   Mutex event_list_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER ACQUIRED_BEFORE(Locks::breakpoint_lock_);
-
   JdwpEvent* event_list_ GUARDED_BY(event_list_lock_);
   size_t event_list_size_ GUARDED_BY(event_list_lock_);  // Number of elements in event_list_.
 
-  // Used to synchronize suspension of the event thread (to avoid receiving "resume"
-  // events before the thread has finished suspending itself).
-  Mutex event_thread_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  ConditionVariable event_thread_cond_ GUARDED_BY(event_thread_lock_);
-  ObjectId event_thread_id_;
-
-  // Used to synchronize request processing and event sending (to avoid sending an event before
-  // sending the reply of a command being processed).
-  Mutex process_request_lock_ ACQUIRED_AFTER(event_thread_lock_);
-  ConditionVariable process_request_cond_ GUARDED_BY(process_request_lock_);
-  bool processing_request_ GUARDED_BY(process_request_lock_);
+  // Used to synchronize JDWP command handler thread and event threads so only one
+  // thread does JDWP stuff at a time. This prevent from interleaving command handling
+  // and event notification. Otherwise we could receive a "resume" command for an
+  // event thread that is not suspended yet, or post a "thread death" or event "VM death"
+  // event before sending the reply of the "resume" command that caused it.
+  Mutex jdwp_token_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  ConditionVariable jdwp_token_cond_ GUARDED_BY(jdwp_token_lock_);
+  ObjectId jdwp_token_owner_thread_id_;
 
   bool ddm_is_active_;
 
+  // Used for VirtualMachine.Exit command handling.
   bool should_exit_;
   int exit_status_;
 };
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index a8eaa26..b71f6cd 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -612,7 +612,7 @@
     }
 
     /* grab this before posting/suspending again */
-    SetWaitForEventThread(thread_self_id);
+    AcquireJdwpTokenForEvent(thread_self_id);
 
     /* leave pReq->invoke_needed_ raised so we can check reentrancy */
     Dbg::ExecuteMethod(pReq);
@@ -630,7 +630,7 @@
   JDWP::ObjectId thread_self_id = Dbg::GetThreadSelfId();
   self->TransitionFromRunnableToSuspended(kWaitingForDebuggerSend);
   if (suspend_policy != SP_NONE) {
-    SetWaitForEventThread(threadId);
+    AcquireJdwpTokenForEvent(threadId);
   }
   EventFinish(pReq);
   SuspendByPolicy(suspend_policy, thread_self_id);
@@ -649,63 +649,82 @@
   return pReq->invoke_needed;
 }
 
+void JdwpState::AcquireJdwpTokenForCommand() {
+  CHECK_EQ(Thread::Current(), GetDebugThread()) << "Expected debugger thread";
+  SetWaitForJdwpToken(debug_thread_id_);
+}
+
+void JdwpState::ReleaseJdwpTokenForCommand() {
+  CHECK_EQ(Thread::Current(), GetDebugThread()) << "Expected debugger thread";
+  ClearWaitForJdwpToken();
+}
+
+void JdwpState::AcquireJdwpTokenForEvent(ObjectId threadId) {
+  CHECK_NE(Thread::Current(), GetDebugThread()) << "Expected event thread";
+  CHECK_NE(debug_thread_id_, threadId) << "Not expected debug thread";
+  SetWaitForJdwpToken(threadId);
+}
+
+void JdwpState::ReleaseJdwpTokenForEvent() {
+  CHECK_NE(Thread::Current(), GetDebugThread()) << "Expected event thread";
+  ClearWaitForJdwpToken();
+}
+
 /*
  * We need the JDWP thread to hold off on doing stuff while we post an
  * event and then suspend ourselves.
  *
- * Call this with a threadId of zero if you just want to wait for the
- * current thread operation to complete.
- *
  * This could go to sleep waiting for another thread, so it's important
  * that the thread be marked as VMWAIT before calling here.
  */
-void JdwpState::SetWaitForEventThread(ObjectId threadId) {
+void JdwpState::SetWaitForJdwpToken(ObjectId threadId) {
   bool waited = false;
+  Thread* const self = Thread::Current();
+  CHECK_NE(threadId, 0u);
+  CHECK_NE(self->GetState(), kRunnable);
+  Locks::mutator_lock_->AssertNotHeld(self);
 
   /* this is held for very brief periods; contention is unlikely */
-  Thread* self = Thread::Current();
-  MutexLock mu(self, event_thread_lock_);
+  MutexLock mu(self, jdwp_token_lock_);
+
+  CHECK_NE(jdwp_token_owner_thread_id_, threadId) << "Thread is already holding event thread lock";
 
   /*
    * If another thread is already doing stuff, wait for it.  This can
    * go to sleep indefinitely.
    */
-  while (event_thread_id_ != 0) {
+  while (jdwp_token_owner_thread_id_ != 0) {
     VLOG(jdwp) << StringPrintf("event in progress (%#" PRIx64 "), %#" PRIx64 " sleeping",
-                               event_thread_id_, threadId);
+                               jdwp_token_owner_thread_id_, threadId);
     waited = true;
-    event_thread_cond_.Wait(self);
+    jdwp_token_cond_.Wait(self);
   }
 
-  if (waited || threadId != 0) {
+  if (waited || threadId != debug_thread_id_) {
     VLOG(jdwp) << StringPrintf("event token grabbed (%#" PRIx64 ")", threadId);
   }
-  if (threadId != 0) {
-    event_thread_id_ = threadId;
-  }
+  jdwp_token_owner_thread_id_ = threadId;
 }
 
 /*
  * Clear the threadId and signal anybody waiting.
  */
-void JdwpState::ClearWaitForEventThread() {
+void JdwpState::ClearWaitForJdwpToken() {
   /*
    * Grab the mutex.  Don't try to go in/out of VMWAIT mode, as this
-   * function is called by dvmSuspendSelf(), and the transition back
+   * function is called by Dbg::SuspendSelf(), and the transition back
    * to RUNNING would confuse it.
    */
-  Thread* self = Thread::Current();
-  MutexLock mu(self, event_thread_lock_);
+  Thread* const self = Thread::Current();
+  MutexLock mu(self, jdwp_token_lock_);
 
-  CHECK_NE(event_thread_id_, 0U);
-  VLOG(jdwp) << StringPrintf("cleared event token (%#" PRIx64 ")", event_thread_id_);
+  CHECK_NE(jdwp_token_owner_thread_id_, 0U);
+  VLOG(jdwp) << StringPrintf("cleared event token (%#" PRIx64 ")", jdwp_token_owner_thread_id_);
 
-  event_thread_id_ = 0;
-
-  event_thread_cond_.Signal(self);
+  jdwp_token_owner_thread_id_ = 0;
+  jdwp_token_cond_.Signal(self);
 }
 
-
 /*
  * Prep an event.  Allocates storage for the message and leaves space for
  * the header.
@@ -730,11 +749,6 @@
   Set1(buf + 9, kJdwpEventCommandSet);
   Set1(buf + 10, kJdwpCompositeCommand);
 
-  // Prevents from interleaving commands and events. Otherwise we could end up in sending an event
-  // before sending the reply of the command being processed and would lead to bad synchronization
-  // between the debugger and the debuggee.
-  WaitForProcessingRequest();
-
   SendRequest(pReq);
 
   expandBufFree(pReq);
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index a1d2a6c..0ce4de7 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -1633,27 +1633,15 @@
 
   /*
    * If a debugger event has fired in another thread, wait until the
-   * initiating thread has suspended itself before processing messages
+   * initiating thread has suspended itself before processing commands
    * from the debugger.  Otherwise we (the JDWP thread) could be told to
    * resume the thread before it has suspended.
    *
-   * We call with an argument of zero to wait for the current event
-   * thread to finish, and then clear the block.  Depending on the thread
-   * suspend policy, this may allow events in other threads to fire,
-   * but those events have no bearing on what the debugger has sent us
-   * in the current request->
-   *
    * Note that we MUST clear the event token before waking the event
    * thread up, or risk waiting for the thread to suspend after we've
    * told it to resume.
    */
-  SetWaitForEventThread(0);
-
-  /*
-   * We do not want events to be sent while we process a request-> Indicate the JDWP thread starts
-   * to process a request so other threads wait for it to finish before sending an event.
-   */
-  StartProcessingRequest();
+  AcquireJdwpTokenForCommand();
 
   /*
    * Tell the VM that we're running and shouldn't be interrupted by GC.
@@ -1719,50 +1707,6 @@
   return replyLength;
 }
 
-/*
- * Indicates a request is about to be processed. If a thread wants to send an event in the meantime,
- * it will need to wait until we processed this request (see EndProcessingRequest).
- */
-void JdwpState::StartProcessingRequest() {
-  Thread* self = Thread::Current();
-  CHECK_EQ(self, GetDebugThread()) << "Requests are only processed by debug thread";
-  MutexLock mu(self, process_request_lock_);
-  CHECK_EQ(processing_request_, false);
-  processing_request_ = true;
-}
-
-/*
- * Indicates a request has been processed (and we sent its reply). All threads waiting for us (see
- * WaitForProcessingRequest) are waken up so they can send events again.
- */
-void JdwpState::EndProcessingRequest() {
-  Thread* self = Thread::Current();
-  CHECK_EQ(self, GetDebugThread()) << "Requests are only processed by debug thread";
-  MutexLock mu(self, process_request_lock_);
-  CHECK_EQ(processing_request_, true);
-  processing_request_ = false;
-  process_request_cond_.Broadcast(self);
-}
-
-/*
- * Waits for any request being processed so we do not send an event in the meantime.
- */
-void JdwpState::WaitForProcessingRequest() {
-  Thread* self = Thread::Current();
-  CHECK_NE(self, GetDebugThread()) << "Events should not be posted by debug thread";
-  MutexLock mu(self, process_request_lock_);
-  bool waited = false;
-  while (processing_request_) {
-    VLOG(jdwp) << StringPrintf("wait for processing request");
-    waited = true;
-    process_request_cond_.Wait(self);
-  }
-  if (waited) {
-    VLOG(jdwp) << StringPrintf("finished waiting for processing request");
-  }
-  CHECK_EQ(processing_request_, false);
-}
-
 }  // namespace JDWP
 
 }  // namespace art
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index b04aa6e..b6fedd9 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -220,12 +220,9 @@
       event_list_lock_("JDWP event list lock", kJdwpEventListLock),
       event_list_(nullptr),
       event_list_size_(0),
-      event_thread_lock_("JDWP event thread lock"),
-      event_thread_cond_("JDWP event thread condition variable", event_thread_lock_),
-      event_thread_id_(0),
-      process_request_lock_("JDWP process request lock"),
-      process_request_cond_("JDWP process request condition variable", process_request_lock_),
-      processing_request_(false),
+      jdwp_token_lock_("JDWP token lock"),
+      jdwp_token_cond_("JDWP token condition variable", jdwp_token_lock_),
+      jdwp_token_owner_thread_id_(0),
       ddm_is_active_(false),
       should_exit_(false),
       exit_status_(0) {
@@ -331,7 +328,7 @@
    * Should not have one of these in progress.  If the debugger went away
    * mid-request, though, we could see this.
    */
-  if (event_thread_id_ != 0) {
+  if (jdwp_token_owner_thread_id_ != 0) {
     LOG(WARNING) << "Resetting state while event in progress";
     DCHECK(false);
   }
@@ -382,10 +379,9 @@
   ssize_t cc = netStateBase->WritePacket(pReply, replyLength);
 
   /*
-   * We processed this request and sent its reply. Notify other threads waiting for us they can now
-   * send events.
+   * We processed this request and sent its reply so we can release the JDWP token.
    */
-  EndProcessingRequest();
+  ReleaseJdwpTokenForCommand();
 
   if (cc != static_cast<ssize_t>(replyLength)) {
     PLOG(ERROR) << "Failed sending reply to debugger";
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index e415c3d..99a005d 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -49,6 +49,8 @@
   }
 
   Thread* const self = Thread::Current();
+  self->AssertNoPendingException();
+
   StackHandleScope<1> hs(self);
   Handle<mirror::Object> obj_h(hs.NewHandle(o));
 
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
new file mode 100644
index 0000000..539c181
--- /dev/null
+++ b/runtime/jit/jit.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright 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 "jit.h"
+
+#include <dlfcn.h>
+
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
+#include "jit_code_cache.h"
+#include "jit_instrumentation.h"
+#include "mirror/art_method-inl.h"
+#include "runtime.h"
+#include "runtime_options.h"
+#include "thread_list.h"
+#include "utils.h"
+
+namespace art {
+namespace jit {
+
+JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& options) {
+  if (!options.GetOrDefault(RuntimeArgumentMap::UseJIT)) {
+    return nullptr;
+  }
+  auto* jit_options = new JitOptions;
+  jit_options->code_cache_capacity_ =
+      options.GetOrDefault(RuntimeArgumentMap::JITCodeCacheCapacity);
+  jit_options->compile_threshold_ =
+      options.GetOrDefault(RuntimeArgumentMap::JITCompileThreshold);
+  return jit_options;
+}
+
+Jit::Jit()
+    : jit_library_handle_(nullptr), jit_compiler_handle_(nullptr), jit_load_(nullptr),
+      jit_compile_method_(nullptr) {
+}
+
+Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
+  std::unique_ptr<Jit> jit(new Jit);
+  if (!jit->LoadCompiler(error_msg)) {
+    return nullptr;
+  }
+  jit->code_cache_.reset(JitCodeCache::Create(options->GetCodeCacheCapacity(), error_msg));
+  if (jit->GetCodeCache() == nullptr) {
+    return nullptr;
+  }
+  LOG(INFO) << "JIT created with code_cache_capacity="
+      << PrettySize(options->GetCodeCacheCapacity())
+      << " compile_threshold=" << options->GetCompileThreshold();
+  return jit.release();
+}
+
+bool Jit::LoadCompiler(std::string* error_msg) {
+  jit_library_handle_ = dlopen(
+      kIsDebugBuild ? "libartd-compiler.so" : "libart-compiler.so", RTLD_NOW);
+  if (jit_library_handle_ == nullptr) {
+    std::ostringstream oss;
+    oss << "JIT could not load libart-compiler.so: " << dlerror();
+    *error_msg = oss.str();
+    return false;
+  }
+  jit_load_ = reinterpret_cast<void* (*)(CompilerCallbacks**)>(
+      dlsym(jit_library_handle_, "jit_load"));
+  if (jit_load_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't find jit_load entry point";
+    return false;
+  }
+  jit_unload_ = reinterpret_cast<void (*)(void*)>(
+      dlsym(jit_library_handle_, "jit_unload"));
+  if (jit_unload_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't find jit_unload entry point";
+    return false;
+  }
+  jit_compile_method_ = reinterpret_cast<bool (*)(void*, mirror::ArtMethod*, Thread*)>(
+      dlsym(jit_library_handle_, "jit_compile_method"));
+  if (jit_compile_method_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't find jit_compile_method entry point";
+    return false;
+  }
+  CompilerCallbacks* callbacks = nullptr;
+  VLOG(jit) << "Calling JitLoad interpreter_only="
+      << Runtime::Current()->GetInstrumentation()->InterpretOnly();
+  jit_compiler_handle_ = (jit_load_)(&callbacks);
+  if (jit_compiler_handle_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't load compiler";
+    return false;
+  }
+  if (callbacks == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT compiler callbacks were not set";
+    jit_compiler_handle_ = nullptr;
+    return false;
+  }
+  compiler_callbacks_ = callbacks;
+  return true;
+}
+
+bool Jit::CompileMethod(mirror::ArtMethod* method, Thread* self) {
+  DCHECK(!method->IsRuntimeMethod());
+  const bool result = jit_compile_method_(jit_compiler_handle_, method, self);
+  if (result) {
+    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+  }
+  return result;
+}
+
+void Jit::CreateThreadPool() {
+  CHECK(instrumentation_cache_.get() != nullptr);
+  instrumentation_cache_->CreateThreadPool();
+}
+
+void Jit::DeleteThreadPool() {
+  if (instrumentation_cache_.get() != nullptr) {
+    instrumentation_cache_->DeleteThreadPool();
+  }
+}
+
+Jit::~Jit() {
+  DeleteThreadPool();
+  if (jit_compiler_handle_ != nullptr) {
+    jit_unload_(jit_compiler_handle_);
+  }
+  if (jit_library_handle_ != nullptr) {
+    dlclose(jit_library_handle_);
+  }
+}
+
+void Jit::CreateInstrumentationCache(size_t compile_threshold) {
+  CHECK_GT(compile_threshold, 0U);
+  Runtime* const runtime = Runtime::Current();
+  runtime->GetThreadList()->SuspendAll();
+  // Add Jit interpreter instrumentation, tells the interpreter when to notify the jit to compile
+  // something.
+  instrumentation_cache_.reset(new jit::JitInstrumentationCache(compile_threshold));
+  runtime->GetInstrumentation()->AddListener(
+      new jit::JitInstrumentationListener(instrumentation_cache_.get()),
+      instrumentation::Instrumentation::kMethodEntered |
+      instrumentation::Instrumentation::kBackwardBranch);
+  runtime->GetThreadList()->ResumeAll();
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
new file mode 100644
index 0000000..b80015f
--- /dev/null
+++ b/runtime/jit/jit.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 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_JIT_JIT_H_
+#define ART_RUNTIME_JIT_JIT_H_
+
+#include <unordered_map>
+
+#include "instrumentation.h"
+
+#include "atomic.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc_root.h"
+#include "jni.h"
+#include "object_callbacks.h"
+#include "thread_pool.h"
+
+namespace art {
+
+class CompilerCallbacks;
+struct RuntimeArgumentMap;
+
+namespace jit {
+
+class JitCodeCache;
+class JitInstrumentationCache;
+class JitOptions;
+
+class Jit {
+ public:
+  static constexpr bool kStressMode = kIsDebugBuild;
+  static constexpr size_t kDefaultCompileThreshold = kStressMode ? 1 : 1000;
+
+  virtual ~Jit();
+  static Jit* Create(JitOptions* options, std::string* error_msg);
+  bool CompileMethod(mirror::ArtMethod* method, Thread* self)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void CreateInstrumentationCache(size_t compile_threshold);
+  void CreateThreadPool();
+  CompilerCallbacks* GetCompilerCallbacks() {
+    return compiler_callbacks_;
+  }
+  const JitCodeCache* GetCodeCache() const {
+    return code_cache_.get();
+  }
+  JitCodeCache* GetCodeCache() {
+    return code_cache_.get();
+  }
+  void DeleteThreadPool();
+
+ private:
+  Jit();
+  bool LoadCompiler(std::string* error_msg);
+
+  // JIT compiler
+  void* jit_library_handle_;
+  void* jit_compiler_handle_;
+  void* (*jit_load_)(CompilerCallbacks**);
+  void (*jit_unload_)(void*);
+  bool (*jit_compile_method_)(void*, mirror::ArtMethod*, Thread*);
+
+  std::unique_ptr<jit::JitInstrumentationCache> instrumentation_cache_;
+  std::unique_ptr<jit::JitCodeCache> code_cache_;
+  CompilerCallbacks* compiler_callbacks_;  // Owned by the jit compiler.
+};
+
+class JitOptions {
+ public:
+  static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options);
+  size_t GetCompileThreshold() const {
+    return compile_threshold_;
+  }
+  size_t GetCodeCacheCapacity() const {
+    return code_cache_capacity_;
+  }
+
+ private:
+  size_t code_cache_capacity_;
+  size_t compile_threshold_;
+
+  JitOptions() : code_cache_capacity_(0), compile_threshold_(0) {
+  }
+};
+
+}  // namespace jit
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_JIT_H_
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
new file mode 100644
index 0000000..8d4965e
--- /dev/null
+++ b/runtime/jit/jit_code_cache.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright 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 "jit_code_cache.h"
+
+#include <sstream>
+
+#include "mem_map.h"
+#include "mirror/art_method-inl.h"
+#include "oat_file-inl.h"
+
+namespace art {
+namespace jit {
+
+JitCodeCache* JitCodeCache::Create(size_t capacity, std::string* error_msg) {
+  CHECK_GT(capacity, 0U);
+  CHECK_LT(capacity, kMaxCapacity);
+  std::string error_str;
+  // Map name specific for android_os_Debug.cpp accounting.
+  MemMap* map = MemMap::MapAnonymous("jit-code-cache", nullptr, capacity,
+                                     PROT_READ | PROT_WRITE | PROT_EXEC, false, &error_str);
+  if (map == nullptr) {
+    std::ostringstream oss;
+    oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity;
+    *error_msg = oss.str();
+    return nullptr;
+  }
+  return new JitCodeCache(map);
+}
+
+JitCodeCache::JitCodeCache(MemMap* mem_map)
+    : lock_("Jit code cache", kJitCodeCacheLock), num_methods_(0) {
+  VLOG(jit) << "Created jit code cache size=" << PrettySize(mem_map->Size());
+  mem_map_.reset(mem_map);
+  uint8_t* divider = mem_map->Begin() + RoundUp(mem_map->Size() / 4, kPageSize);
+  // Data cache is 1 / 4 of the map. TODO: Make this variable?
+  // Put data at the start.
+  data_cache_ptr_ = mem_map->Begin();
+  data_cache_end_ = divider;
+  data_cache_begin_ = data_cache_ptr_;
+  mprotect(data_cache_ptr_, data_cache_end_ - data_cache_begin_, PROT_READ | PROT_WRITE);
+  // Code cache after.
+  code_cache_begin_ = divider;
+  code_cache_ptr_ = divider;
+  code_cache_end_ = mem_map->End();
+}
+
+bool JitCodeCache::ContainsMethod(mirror::ArtMethod* method) const {
+  return ContainsCodePtr(method->GetEntryPointFromQuickCompiledCode());
+}
+
+bool JitCodeCache::ContainsCodePtr(const void* ptr) const {
+  return ptr >= code_cache_begin_ && ptr < code_cache_end_;
+}
+
+void JitCodeCache::FlushInstructionCache() {
+  UNIMPLEMENTED(FATAL);
+  // TODO: Investigate if we need to do this.
+  // __clear_cache(reinterpret_cast<char*>(code_cache_begin_), static_cast<int>(CodeCacheSize()));
+}
+
+uint8_t* JitCodeCache::ReserveCode(Thread* self, size_t size) {
+  MutexLock mu(self, lock_);
+  if (size > CodeCacheRemain()) {
+    return nullptr;
+  }
+  code_cache_ptr_ += size;
+  return code_cache_ptr_ - size;
+}
+
+uint8_t* JitCodeCache::AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end) {
+  MutexLock mu(self, lock_);
+  const size_t size = end - begin;
+  if (size > DataCacheRemain()) {
+    return nullptr;  // Out of space in the data cache.
+  }
+  std::copy(begin, end, data_cache_ptr_);
+  data_cache_ptr_ += size;
+  return data_cache_ptr_ - size;
+}
+
+const void* JitCodeCache::GetCodeFor(mirror::ArtMethod* method) {
+  const void* code = method->GetEntryPointFromQuickCompiledCode();
+  if (ContainsCodePtr(code)) {
+    return code;
+  }
+  MutexLock mu(Thread::Current(), lock_);
+  auto it = method_code_map_.find(method);
+  if (it != method_code_map_.end()) {
+    return it->second;
+  }
+  return nullptr;
+}
+
+void JitCodeCache::SaveCompiledCode(mirror::ArtMethod* method, const void* old_code_ptr) {
+  DCHECK_EQ(method->GetEntryPointFromQuickCompiledCode(), old_code_ptr);
+  DCHECK(ContainsCodePtr(old_code_ptr)) << PrettyMethod(method) << " old_code_ptr="
+      << old_code_ptr;
+  MutexLock mu(Thread::Current(), lock_);
+  auto it = method_code_map_.find(method);
+  if (it != method_code_map_.end()) {
+    return;
+  }
+  method_code_map_.Put(method, old_code_ptr);
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
new file mode 100644
index 0000000..aa8c717
--- /dev/null
+++ b/runtime/jit/jit_code_cache.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 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_JIT_JIT_CODE_CACHE_H_
+#define ART_RUNTIME_JIT_JIT_CODE_CACHE_H_
+
+#include "instrumentation.h"
+
+#include "atomic.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc_root.h"
+#include "jni.h"
+#include "oat_file.h"
+#include "object_callbacks.h"
+#include "safe_map.h"
+#include "thread_pool.h"
+
+namespace art {
+
+class CompiledMethod;
+class CompilerCallbacks;
+
+namespace mirror {
+class ArtMethod;
+}  // namespcae mirror
+
+namespace jit {
+
+class JitInstrumentationCache;
+
+class JitCodeCache {
+ public:
+  static constexpr size_t kMaxCapacity = 1 * GB;
+  static constexpr size_t kDefaultCapacity = 2 * MB;
+
+  static JitCodeCache* Create(size_t capacity, std::string* error_msg);
+
+  const uint8_t* CodeCachePtr() const {
+    return code_cache_ptr_;
+  }
+  size_t CodeCacheSize() const {
+    return code_cache_ptr_ - code_cache_begin_;
+  }
+  size_t CodeCacheRemain() const {
+    return code_cache_end_ - code_cache_ptr_;
+  }
+  size_t DataCacheSize() const {
+    return data_cache_ptr_ - data_cache_begin_;
+  }
+  size_t DataCacheRemain() const {
+    return data_cache_end_ - data_cache_ptr_;
+  }
+  size_t NumMethods() const {
+    return num_methods_;
+  }
+
+  bool ContainsMethod(mirror::ArtMethod* method) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool ContainsCodePtr(const void* ptr) const;
+
+  uint8_t* ReserveCode(Thread* self, size_t size) LOCKS_EXCLUDED(lock_);
+
+  uint8_t* AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end)
+      LOCKS_EXCLUDED(lock_);
+
+  // Get code for a method, returns null if it is not in the jit cache.
+  const void* GetCodeFor(mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+  void SaveCompiledCode(mirror::ArtMethod* method, const void* old_code_ptr)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+ private:
+  // Takes ownership of code_mem_map.
+  explicit JitCodeCache(MemMap* code_mem_map);
+  void FlushInstructionCache();
+
+  Mutex lock_;
+  // Mem map which holds code and data. We do this since we need to have 32 bit offsets from method
+  // headers in code cache which point to things in the data cache. If the maps are more than 4GB
+  // apart, having multiple maps wouldn't work.
+  std::unique_ptr<MemMap> mem_map_;
+  // Code cache section.
+  uint8_t* code_cache_ptr_;
+  const uint8_t* code_cache_begin_;
+  const uint8_t* code_cache_end_;
+  // Data cache section.
+  uint8_t* data_cache_ptr_;
+  const uint8_t* data_cache_begin_;
+  const uint8_t* data_cache_end_;
+  size_t num_methods_;
+  // TODO: This relies on methods not moving.
+  // This map holds code for methods if they were deoptimized by the instrumentation stubs. This is
+  // required since we have to implement ClassLinker::GetQuickOatCodeFor for walking stacks.
+  SafeMap<mirror::ArtMethod*, const void*> method_code_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(JitCodeCache);
+};
+
+
+}  // namespace jit
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_JIT_CODE_CACHE_H_
diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc
new file mode 100644
index 0000000..160e678
--- /dev/null
+++ b/runtime/jit/jit_instrumentation.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright 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 "jit_instrumentation.h"
+
+#include "jit.h"
+#include "jit_code_cache.h"
+#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace jit {
+
+class JitCompileTask : public Task {
+ public:
+  explicit JitCompileTask(mirror::ArtMethod* method, JitInstrumentationCache* cache)
+      : method_(method), cache_(cache) {
+  }
+
+  virtual void Run(Thread* self) OVERRIDE {
+    ScopedObjectAccess soa(self);
+    VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_);
+    if (Runtime::Current()->GetJit()->CompileMethod(method_, self)) {
+      cache_->SignalCompiled(self, method_);
+    } else {
+      VLOG(jit) << "Failed to compile method " << PrettyMethod(method_);
+    }
+  }
+
+  virtual void Finalize() OVERRIDE {
+    delete this;
+  }
+
+ private:
+  mirror::ArtMethod* const method_;
+  JitInstrumentationCache* const cache_;
+};
+
+JitInstrumentationCache::JitInstrumentationCache(size_t hot_method_threshold)
+    : lock_("jit instrumentation lock"), hot_method_threshold_(hot_method_threshold) {
+}
+
+void JitInstrumentationCache::CreateThreadPool() {
+  thread_pool_.reset(new ThreadPool("Jit thread pool", 1));
+}
+
+void JitInstrumentationCache::DeleteThreadPool() {
+  thread_pool_.reset();
+}
+
+void JitInstrumentationCache::SignalCompiled(Thread* self, mirror::ArtMethod* method) {
+  ScopedObjectAccessUnchecked soa(self);
+  jmethodID method_id = soa.EncodeMethod(method);
+  MutexLock mu(self, lock_);
+  auto it = samples_.find(method_id);
+  if (it != samples_.end()) {
+    samples_.erase(it);
+  }
+}
+
+void JitInstrumentationCache::AddSamples(Thread* self, mirror::ArtMethod* method, size_t count) {
+  ScopedObjectAccessUnchecked soa(self);
+  // Since we don't have on-stack replacement, some methods can remain in the interpreter longer
+  // than we want resulting in samples even after the method is compiled.
+  if (method->IsClassInitializer() ||
+      Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method)) {
+    return;
+  }
+  jmethodID method_id = soa.EncodeMethod(method);
+  bool is_hot = false;
+  {
+    MutexLock mu(self, lock_);
+    size_t sample_count = 0;
+    auto it = samples_.find(method_id);
+    if (it != samples_.end()) {
+      it->second += count;
+      sample_count = it->second;
+    } else {
+      sample_count = count;
+      samples_.insert(std::make_pair(method_id, count));
+    }
+    // If we have enough samples, mark as hot and request Jit compilation.
+    if (sample_count >= hot_method_threshold_ && sample_count - count < hot_method_threshold_) {
+      is_hot = true;
+    }
+  }
+  if (is_hot) {
+    if (thread_pool_.get() != nullptr) {
+      thread_pool_->AddTask(self, new JitCompileTask(method->GetInterfaceMethodIfProxy(), this));
+      thread_pool_->StartWorkers(self);
+    } else {
+      VLOG(jit) << "Compiling hot method " << PrettyMethod(method);
+      Runtime::Current()->GetJit()->CompileMethod(method->GetInterfaceMethodIfProxy(), self);
+    }
+  }
+}
+
+JitInstrumentationListener::JitInstrumentationListener(JitInstrumentationCache* cache)
+    : instrumentation_cache_(cache) {
+  CHECK(instrumentation_cache_ != nullptr);
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h
new file mode 100644
index 0000000..9576f4b
--- /dev/null
+++ b/runtime/jit/jit_instrumentation.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 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_JIT_JIT_INSTRUMENTATION_H_
+#define ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_
+
+#include <unordered_map>
+
+#include "instrumentation.h"
+
+#include "atomic.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc_root.h"
+#include "jni.h"
+#include "object_callbacks.h"
+#include "thread_pool.h"
+
+namespace art {
+namespace mirror {
+  class ArtField;
+  class ArtMethod;
+  class Class;
+  class Object;
+  class Throwable;
+}  // namespace mirror
+union JValue;
+class Thread;
+class ThrowLocation;
+
+namespace jit {
+
+// Keeps track of which methods are hot.
+class JitInstrumentationCache {
+ public:
+  explicit JitInstrumentationCache(size_t hot_method_threshold);
+  void AddSamples(Thread* self, mirror::ArtMethod* method, size_t samples)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SignalCompiled(Thread* self, mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void CreateThreadPool();
+  void DeleteThreadPool();
+
+ private:
+  Mutex lock_;
+  std::unordered_map<jmethodID, size_t> samples_;
+  size_t hot_method_threshold_;
+  std::unique_ptr<ThreadPool> thread_pool_;
+};
+
+class JitInstrumentationListener : public instrumentation::InstrumentationListener {
+ public:
+  explicit JitInstrumentationListener(JitInstrumentationCache* cache);
+
+  virtual void MethodEntered(Thread* thread, mirror::Object* /*this_object*/,
+                             mirror::ArtMethod* method, uint32_t /*dex_pc*/)
+      OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    instrumentation_cache_->AddSamples(thread, method, 1);
+  }
+  virtual void MethodExited(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                            mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
+                            const JValue& /*return_value*/)
+      OVERRIDE { }
+  virtual void MethodUnwind(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                            mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/) OVERRIDE { }
+  virtual void FieldRead(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                         mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
+                         mirror::ArtField* /*field*/) OVERRIDE { }
+  virtual void FieldWritten(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                            mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
+                            mirror::ArtField* /*field*/, const JValue& /*field_value*/)
+      OVERRIDE { }
+  virtual void ExceptionCaught(Thread* /*thread*/, const ThrowLocation& /*throw_location*/,
+                               mirror::ArtMethod* /*catch_method*/, uint32_t /*catch_dex_pc*/,
+                               mirror::Throwable* /*exception_object*/) OVERRIDE { }
+
+  virtual void DexPcMoved(Thread* /*self*/, mirror::Object* /*this_object*/,
+                          mirror::ArtMethod* /*method*/, uint32_t /*new_dex_pc*/) OVERRIDE { }
+
+  // We only care about how many dex instructions were executed in the Jit.
+  virtual void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t dex_pc_offset)
+      OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CHECK_LE(dex_pc_offset, 0);
+    instrumentation_cache_->AddSamples(thread, method, 1);
+  }
+
+ private:
+  JitInstrumentationCache* const instrumentation_cache_;
+};
+
+}  // namespace jit
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index 5a4ebd1..3cea4a1 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -44,7 +44,7 @@
 
 void ArtField::SetOffset(MemberOffset num_bytes) {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  if (kIsDebugBuild && Runtime::Current()->IsCompiler() &&
+  if (kIsDebugBuild && Runtime::Current()->IsAotCompiler() &&
       !Runtime::Current()->UseCompileTimeClassPath()) {
     Primitive::Type type = GetTypeAsPrimitiveType();
     if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 7d31148..c27c6e9 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -147,7 +147,10 @@
 
 inline uint32_t ArtMethod::GetCodeSize() {
   DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
-  const void* code = EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode());
+  return GetCodeSize(EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode()));
+}
+
+inline uint32_t ArtMethod::GetCodeSize(const void* code) {
   if (code == nullptr) {
     return 0u;
   }
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index b2016dc..26f6f34 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -27,6 +27,8 @@
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
 #include "interpreter/interpreter.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
 #include "jni_internal.h"
 #include "mapping_table.h"
 #include "object_array-inl.h"
@@ -229,6 +231,7 @@
   if (abort_on_failure) {
       LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
              << "(PC " << reinterpret_cast<void*>(pc) << ", entry_point=" << entry_point
+             << " current entry_point=" << GetQuickOatEntryPoint(sizeof(void*))
              << ") in " << PrettyMethod(this);
   }
   return DexFile::kDexNoIndex;
@@ -329,6 +332,13 @@
       class_linker->IsQuickResolutionStub(code)) {
     return;
   }
+  // If we are the JIT then we may have just compiled the method after the
+  // IsQuickToInterpreterBridge check.
+  jit::Jit* const jit = Runtime::Current()->GetJit();
+  if (jit != nullptr &&
+      jit->GetCodeCache()->ContainsCodePtr(reinterpret_cast<const void*>(code))) {
+    return;
+  }
   /*
    * During a stack walk, a return PC may point past-the-end of the code
    * in the case that the last instruction is a call that isn't expected to
@@ -336,11 +346,12 @@
    *
    * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
    */
-  CHECK(PcIsWithinQuickCode(pc))
+  CHECK(PcIsWithinQuickCode(reinterpret_cast<uintptr_t>(code), pc))
       << PrettyMethod(this)
       << " pc=" << std::hex << pc
       << " code=" << code
-      << " size=" << GetCodeSize();
+      << " size=" << GetCodeSize(
+          EntryPointToCodePointer(reinterpret_cast<const void*>(code)));
 }
 
 bool ArtMethod::IsEntrypointInterpreter() {
@@ -410,7 +421,8 @@
       }
 
       // Ensure that we won't be accidentally calling quick compiled code when -Xint.
-      if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()) {
+      if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
+        DCHECK(!runtime->UseJit());
         CHECK(IsEntrypointInterpreter())
             << "Don't call compiled code when -Xint " << PrettyMethod(this);
       }
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f33ca94..d878f25 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -305,18 +305,8 @@
   // quick entrypoint. This code isn't robust for instrumentation, etc. and is only used for
   // debug purposes.
   bool PcIsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode());
-    if (code == 0) {
-      return pc == 0;
-    }
-    /*
-     * During a stack walk, a return PC may point past-the-end of the code
-     * in the case that the last instruction is a call that isn't expected to
-     * return.  Thus, we check <= code + GetCodeSize().
-     *
-     * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
-     */
-    return code <= pc && pc <= code + GetCodeSize();
+    return PcIsWithinQuickCode(
+        reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode()), pc);
   }
 
   void AssertPcIsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -622,6 +612,24 @@
     return offset;
   }
 
+  // Code points to the start of the quick code.
+  static uint32_t GetCodeSize(const void* code);
+
+  static bool PcIsWithinQuickCode(uintptr_t code, uintptr_t pc) {
+    if (code == 0) {
+      return pc == 0;
+    }
+    /*
+     * During a stack walk, a return PC may point past-the-end of the code
+     * in the case that the last instruction is a call that isn't expected to
+     * return.  Thus, we check <= code + GetCodeSize().
+     *
+     * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
+     */
+    return code <= pc && pc <= code + GetCodeSize(
+        EntryPointToCodePointer(reinterpret_cast<const void*>(code)));
+  }
+
   friend struct art::ArtMethodOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(ArtMethod);
 };
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ae09c6d..739d62c 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -577,12 +577,12 @@
   }
   if (oat_file_->IsExecutable() ||
       Runtime::Current() == nullptr ||        // This case applies for oatdump.
-      Runtime::Current()->IsCompiler()) {
+      Runtime::Current()->IsAotCompiler()) {
     return OatMethod(oat_file_->Begin(), oat_method_offsets->code_offset_);
-  } else {
-    // We aren't allowed to use the compiled code. We just force it down the interpreted version.
-    return OatMethod(oat_file_->Begin(), 0);
   }
+  // We aren't allowed to use the compiled code. We just force it down the interpreted / jit
+  // version.
+  return OatMethod(oat_file_->Begin(), 0);
 }
 
 void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 6ae3c3e..5e68439 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -147,8 +147,8 @@
       return reinterpret_cast<T>(begin_ + offset);
     }
 
-    const uint8_t* const begin_;
-    const uint32_t code_offset_;
+    const uint8_t* begin_;
+    uint32_t code_offset_;
 
     friend class OatClass;
   };
diff --git a/runtime/object_lock.cc b/runtime/object_lock.cc
index f7accc0..749fb5d 100644
--- a/runtime/object_lock.cc
+++ b/runtime/object_lock.cc
@@ -47,6 +47,7 @@
   obj_->NotifyAll(self_);
 }
 
+template class ObjectLock<mirror::ArtMethod>;
 template class ObjectLock<mirror::Class>;
 template class ObjectLock<mirror::Object>;
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 99369ca..9d87ed7 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -146,6 +146,15 @@
       .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"})
           .WithValues({true, false})
           .IntoKey(M::EnableHSpaceCompactForOOM)
+      .Define({"-Xjit", "-Xnojit"})
+          .WithValues({true, false})
+          .IntoKey(M::UseJIT)
+      .Define("-Xjitcodecachesize:_")
+          .WithType<MemoryKiB>()
+          .IntoKey(M::JITCodeCacheCapacity)
+      .Define("-Xjitthreshold:_")
+          .WithType<unsigned int>()
+          .IntoKey(M::JITCompileThreshold)
       .Define("-XX:HspaceCompactForOOMMinIntervalMs=_")  // in ms
           .WithType<MillisecondsToNanoseconds>()  // store as ns
           .IntoKey(M::HSpaceCompactForOOMMinIntervalsMs)
@@ -241,12 +250,14 @@
       .Define("-Xzygote-max-failed-boots=_")
           .WithType<unsigned int>()
           .IntoKey(M::ZygoteMaxFailedBoots)
+      .Define("-Xno-dex-file-fallback")
+          .IntoKey(M::NoDexFileFallback)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
           "-Xdexopt:_", "-Xnoquithandler", "-Xjnigreflimit:_", "-Xgenregmap", "-Xnogenregmap",
           "-Xverifyopt:_", "-Xcheckdexsum", "-Xincludeselectedop", "-Xjitop:_",
-          "-Xincludeselectedmethod", "-Xjitthreshold:_", "-Xjitcodecachesize:_",
+          "-Xincludeselectedmethod", "-Xjitthreshold:_",
           "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:_", "-Xjitoffset:_",
           "-Xjitconfig:_", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile",
           "-Xjitdisableopt", "-Xjitsuspendpoll", "-XX:mainThreadStackSize=_"})
@@ -351,19 +362,20 @@
 
 bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized,
                           RuntimeArgumentMap* runtime_options) {
-//  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
-//  gLogVerbosity.compiler = true;  // TODO: don't check this in!
-//  gLogVerbosity.gc = true;  // TODO: don't check this in!
-//  gLogVerbosity.heap = true;  // TODO: don't check this in!
-//  gLogVerbosity.jdwp = true;  // TODO: don't check this in!
-//  gLogVerbosity.jni = true;  // TODO: don't check this in!
-//  gLogVerbosity.monitor = true;  // TODO: don't check this in!
-//  gLogVerbosity.profiler = true;  // TODO: don't check this in!
-//  gLogVerbosity.signals = true;  // TODO: don't check this in!
-//  gLogVerbosity.startup = true;  // TODO: don't check this in!
-//  gLogVerbosity.third_party_jni = true;  // TODO: don't check this in!
-//  gLogVerbosity.threads = true;  // TODO: don't check this in!
-//  gLogVerbosity.verifier = true;  // TODO: don't check this in!
+  //  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
+  //  gLogVerbosity.compiler = true;  // TODO: don't check this in!
+  //  gLogVerbosity.gc = true;  // TODO: don't check this in!
+  //  gLogVerbosity.heap = true;  // TODO: don't check this in!
+  //  gLogVerbosity.jdwp = true;  // TODO: don't check this in!
+  //  gLogVerbosity.jit = true;  // TODO: don't check this in!
+  //  gLogVerbosity.jni = true;  // TODO: don't check this in!
+  //  gLogVerbosity.monitor = true;  // TODO: don't check this in!
+  //  gLogVerbosity.profiler = true;  // TODO: don't check this in!
+  //  gLogVerbosity.signals = true;  // TODO: don't check this in!
+  //  gLogVerbosity.startup = true;  // TODO: don't check this in!
+  //  gLogVerbosity.third_party_jni = true;  // TODO: don't check this in!
+  //  gLogVerbosity.threads = true;  // TODO: don't check this in!
+  //  gLogVerbosity.verifier = true;  // TODO: don't check this in!
 
   for (size_t i = 0; i < options.size(); ++i) {
     if (true && options[0].first == "-Xzygote") {
@@ -558,7 +570,7 @@
   UsageMessage(stream, "The following standard options are supported:\n");
   UsageMessage(stream, "  -classpath classpath (-cp classpath)\n");
   UsageMessage(stream, "  -Dproperty=value\n");
-  UsageMessage(stream, "  -verbose:tag ('gc', 'jni', or 'class')\n");
+  UsageMessage(stream, "  -verbose:tag ('gc', 'jit', 'jni', or 'class')\n");
   UsageMessage(stream, "  -showversion\n");
   UsageMessage(stream, "  -help\n");
   UsageMessage(stream, "  -agentlib:jdwp=options\n");
@@ -588,6 +600,8 @@
   UsageMessage(stream, "  -XX:ForegroundHeapGrowthMultiplier=doublevalue\n");
   UsageMessage(stream, "  -XX:LowMemoryMode\n");
   UsageMessage(stream, "  -Xprofile:{threadcpuclock,wallclock,dualclock}\n");
+  UsageMessage(stream, "  -Xjitcodecachesize:N\n");
+  UsageMessage(stream, "  -Xjitthreshold:integervalue\n");
   UsageMessage(stream, "\n");
 
   UsageMessage(stream, "The following unique to ART options are supported:\n");
@@ -628,9 +642,13 @@
   UsageMessage(stream, "  -Xcompiler-option dex2oat-option\n");
   UsageMessage(stream, "  -Ximage-compiler-option dex2oat-option\n");
   UsageMessage(stream, "  -Xpatchoat:filename\n");
+  UsageMessage(stream, "  -Xjit\n");
+  UsageMessage(stream, "  -Xnojit\n");
   UsageMessage(stream, "  -X[no]relocate\n");
   UsageMessage(stream, "  -X[no]dex2oat (Whether to invoke dex2oat on the application)\n");
   UsageMessage(stream, "  -X[no]image-dex2oat (Whether to create and use a boot image)\n");
+  UsageMessage(stream, "  -Xno-dex-file-fallback "
+                       "(Don't fall back to dex files without oat files)\n");
   UsageMessage(stream, "\n");
 
   UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
@@ -655,8 +673,6 @@
   UsageMessage(stream, "  -Xincludeselectedop\n");
   UsageMessage(stream, "  -Xjitop:hexopvalue[-endvalue][,hexopvalue[-endvalue]]*\n");
   UsageMessage(stream, "  -Xincludeselectedmethod\n");
-  UsageMessage(stream, "  -Xjitthreshold:integervalue\n");
-  UsageMessage(stream, "  -Xjitcodecachesize:decimalvalueofkbytes\n");
   UsageMessage(stream, "  -Xjitblocking\n");
   UsageMessage(stream, "  -Xjitmethod:signature[,signature]* (eg Ljava/lang/String\\;replace)\n");
   UsageMessage(stream, "  -Xjitclass:classname[,classname]*\n");
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index c3bdcb1..db372c3 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -161,7 +161,7 @@
 
 
   CHECK(runtime->AttachCurrentThread("Profiler", true, runtime->GetSystemThreadGroup(),
-                                      !runtime->IsCompiler()));
+                                      !runtime->IsAotCompiler()));
 
   Thread* self = Thread::Current();
 
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index d65b2d5..44e2844 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -77,7 +77,9 @@
                                              InlineMethod* method) {
   DCHECK(verifier != nullptr);
   DCHECK_EQ(Runtime::Current()->IsCompiler(), method != nullptr);
-  DCHECK_EQ(verifier->CanLoadClasses(), method != nullptr);
+  if (!Runtime::Current()->UseJit()) {
+    DCHECK_EQ(verifier->CanLoadClasses(), method != nullptr);
+  }
   // We currently support only plain return or 2-instruction methods.
 
   const DexFile::CodeItem* code_item = verifier->CodeItem();
@@ -110,6 +112,10 @@
     case Instruction::IGET_CHAR:
     case Instruction::IGET_SHORT:
     case Instruction::IGET_WIDE:
+    // TODO: Add handling for JIT.
+    // case Instruction::IGET_QUICK:
+    // case Instruction::IGET_WIDE_QUICK:
+    // case Instruction::IGET_OBJECT_QUICK:
       return AnalyseIGetMethod(verifier, method);
     case Instruction::IPUT:
     case Instruction::IPUT_OBJECT:
@@ -118,6 +124,10 @@
     case Instruction::IPUT_CHAR:
     case Instruction::IPUT_SHORT:
     case Instruction::IPUT_WIDE:
+      // TODO: Add handling for JIT.
+    // case Instruction::IPUT_QUICK:
+    // case Instruction::IPUT_WIDE_QUICK:
+    // case Instruction::IPUT_OBJECT_QUICK:
       return AnalyseIPutMethod(verifier, method);
     default:
       return false;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f38f65e..8c5827c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -65,6 +65,8 @@
 #include "image.h"
 #include "instrumentation.h"
 #include "intern_table.h"
+#include "interpreter/interpreter.h"
+#include "jit/jit.h"
 #include "jni_internal.h"
 #include "mirror/array.h"
 #include "mirror/art_field-inl.h"
@@ -169,6 +171,7 @@
       dump_gc_performance_on_shutdown_(false),
       preinitialization_transaction_(nullptr),
       verify_(false),
+      allow_dex_file_fallback_(true),
       target_sdk_version_(0),
       implicit_null_checks_(false),
       implicit_so_checks_(false),
@@ -190,7 +193,8 @@
   }
 
   Thread* self = Thread::Current();
-  if (self == nullptr) {
+  const bool attach_shutdown_thread = self == nullptr;
+  if (attach_shutdown_thread) {
     CHECK(AttachCurrentThread("Shutdown thread", false, nullptr, false));
     self = Thread::Current();
   } else {
@@ -212,8 +216,10 @@
     self->GetJniEnv()->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
                                             WellKnownClasses::java_lang_Daemons_stop);
   }
-  DetachCurrentThread();
-  self = nullptr;
+  if (attach_shutdown_thread) {
+    DetachCurrentThread();
+    self = nullptr;
+  }
 
   // Shut down background profiler before the runtime exits.
   if (profiler_started_) {
@@ -225,6 +231,12 @@
   // Make sure to let the GC complete if it is running.
   heap_->WaitForGcToComplete(gc::kGcCauseBackground, self);
   heap_->DeleteThreadPool();
+  if (jit_.get() != nullptr) {
+    VLOG(jit) << "Deleting jit thread pool";
+    // Delete thread pool before the thread list since we don't want to wait forever on the
+    // JIT compiler threads.
+    jit_->DeleteThreadPool();
+  }
 
   // Make sure our internal threads are dead before we start tearing down things they're using.
   Dbg::StopJdwp();
@@ -233,6 +245,13 @@
   // Make sure all other non-daemon threads have terminated, and all daemon threads are suspended.
   delete thread_list_;
 
+  // Delete the JIT after thread list to ensure that there is no remaining threads which could be
+  // accessing the instrumentation when we delete it.
+  if (jit_.get() != nullptr) {
+    VLOG(jit) << "Deleting jit";
+    jit_.reset(nullptr);
+  }
+
   // Shutdown the fault manager if it was initialized.
   fault_manager.Shutdown();
 
@@ -380,7 +399,9 @@
   InitLogging(NULL);  // Calls Locks::Init() as a side effect.
   instance_ = new Runtime;
   if (!instance_->Init(options, ignore_unrecognized)) {
-    delete instance_;
+    // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
+    // leak memory, instead. Fix the destructor. b/19100793.
+    // delete instance_;
     instance_ = NULL;
     return false;
   }
@@ -455,17 +476,24 @@
 
   started_ = true;
 
-  // Use !IsCompiler so that we get test coverage, tests are never the zygote.
-  if (!IsCompiler()) {
+  // Use !IsAotCompiler so that we get test coverage, tests are never the zygote.
+  if (!IsAotCompiler()) {
     ScopedObjectAccess soa(self);
     gc::space::ImageSpace* image_space = heap_->GetImageSpace();
     if (image_space != nullptr) {
-      Runtime::Current()->GetInternTable()->AddImageStringsToTable(image_space);
-      Runtime::Current()->GetClassLinker()->MoveImageClassesToClassTable();
+      GetInternTable()->AddImageStringsToTable(image_space);
+      GetClassLinker()->MoveImageClassesToClassTable();
     }
   }
 
-  if (!IsImageDex2OatEnabled() || !Runtime::Current()->GetHeap()->HasImageSpace()) {
+  // If we are the zygote then we need to wait until after forking to create the code cache due to
+  // SELinux restrictions on r/w/x memory regions.
+  if (!IsZygote() && jit_.get() != nullptr) {
+    jit_->CreateInstrumentationCache(jit_options_->GetCompileThreshold());
+    jit_->CreateThreadPool();
+  }
+
+  if (!IsImageDex2OatEnabled() || !GetHeap()->HasImageSpace()) {
     ScopedObjectAccess soa(self);
     StackHandleScope<1> hs(soa.Self());
     auto klass(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
@@ -584,8 +612,14 @@
     }
   }
 
-  // Create the thread pool.
+  // Create the thread pools.
   heap_->CreateThreadPool();
+  if (jit_options_.get() != nullptr && jit_.get() == nullptr) {
+    // Create the JIT if the flag is set and we haven't already create it (happens for run-tests).
+    CreateJit();
+    jit_->CreateInstrumentationCache(jit_options_->GetCompileThreshold());
+    jit_->CreateThreadPool();
+  }
 
   StartSignalCatcher();
 
@@ -762,6 +796,7 @@
   intern_table_ = new InternTable;
 
   verify_ = runtime_options.GetOrDefault(Opt::Verify);
+  allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
 
   if (runtime_options.GetOrDefault(Opt::Interpret)) {
     GetInstrumentation()->ForceInterpretOnly();
@@ -800,12 +835,28 @@
                        runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
                        runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
 
+  if (heap_->GetImageSpace() == nullptr && !allow_dex_file_fallback_) {
+    LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
+    return false;
+  }
+
   dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);
 
   if (runtime_options.Exists(Opt::JdwpOptions)) {
     Dbg::ConfigureJdwp(runtime_options.GetOrDefault(Opt::JdwpOptions));
   }
 
+  if (!IsCompiler()) {
+    // If we are already the compiler at this point, we must be dex2oat. Don't create the jit in
+    // this case.
+    // If runtime_options doesn't have UseJIT set to true then CreateFromRuntimeArguments returns
+    // nullptr and we don't create the jit.
+    jit_options_.reset(jit::JitOptions::CreateFromRuntimeArguments(runtime_options));
+  }
+  if (!IsZygote() && jit_options_.get() != nullptr) {
+    CreateJit();
+  }
+
   BlockSignals();
   InitPlatformSignalHandlers();
 
@@ -1054,26 +1105,26 @@
       env->NewGlobalRef(env->GetStaticObjectField(
           WellKnownClasses::java_lang_ThreadGroup,
           WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup));
-  CHECK(main_thread_group_ != NULL || IsCompiler());
+  CHECK(main_thread_group_ != NULL || IsAotCompiler());
   system_thread_group_ =
       env->NewGlobalRef(env->GetStaticObjectField(
           WellKnownClasses::java_lang_ThreadGroup,
           WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup));
-  CHECK(system_thread_group_ != NULL || IsCompiler());
+  CHECK(system_thread_group_ != NULL || IsAotCompiler());
 }
 
 jobject Runtime::GetMainThreadGroup() const {
-  CHECK(main_thread_group_ != NULL || IsCompiler());
+  CHECK(main_thread_group_ != NULL || IsAotCompiler());
   return main_thread_group_;
 }
 
 jobject Runtime::GetSystemThreadGroup() const {
-  CHECK(system_thread_group_ != NULL || IsCompiler());
+  CHECK(system_thread_group_ != NULL || IsAotCompiler());
   return system_thread_group_;
 }
 
 jobject Runtime::GetSystemClassLoader() const {
-  CHECK(system_class_loader_ != NULL || IsCompiler());
+  CHECK(system_class_loader_ != NULL || IsAotCompiler());
   return system_class_loader_;
 }
 
@@ -1329,7 +1380,7 @@
   // TODO: use a special method for imt conflict method saves.
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
   // When compiling, the code pointer will get set later when the image is loaded.
-  if (runtime->IsCompiler()) {
+  if (runtime->IsAotCompiler()) {
     size_t pointer_size = GetInstructionSetPointerSize(instruction_set_);
     method->SetEntryPointFromQuickCompiledCodePtrSize(nullptr, pointer_size);
   } else {
@@ -1338,6 +1389,10 @@
   return method.Get();
 }
 
+void Runtime::SetImtConflictMethod(mirror::ArtMethod* method) {
+  imt_conflict_method_ = GcRoot<mirror::ArtMethod>(method);
+}
+
 mirror::ArtMethod* Runtime::CreateResolutionMethod() {
   Thread* self = Thread::Current();
   Runtime* runtime = Runtime::Current();
@@ -1348,7 +1403,7 @@
   // TODO: use a special method for resolution method saves
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
   // When compiling, the code pointer will get set later when the image is loaded.
-  if (runtime->IsCompiler()) {
+  if (runtime->IsAotCompiler()) {
     size_t pointer_size = GetInstructionSetPointerSize(instruction_set_);
     method->SetEntryPointFromQuickCompiledCodePtrSize(nullptr, pointer_size);
   } else {
@@ -1479,14 +1534,14 @@
 
 // Transaction support.
 void Runtime::EnterTransactionMode(Transaction* transaction) {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(transaction != nullptr);
   DCHECK(!IsActiveTransaction());
   preinitialization_transaction_ = transaction;
 }
 
 void Runtime::ExitTransactionMode() {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_ = nullptr;
 }
@@ -1546,51 +1601,51 @@
 
 void Runtime::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset,
                                  uint32_t value, bool is_volatile) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordWriteField32(obj, field_offset, value, is_volatile);
 }
 
 void Runtime::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset,
                                  uint64_t value, bool is_volatile) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordWriteField64(obj, field_offset, value, is_volatile);
 }
 
 void Runtime::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
                                         mirror::Object* value, bool is_volatile) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordWriteFieldReference(obj, field_offset, value, is_volatile);
 }
 
 void Runtime::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordWriteArray(array, index, value);
 }
 
 void Runtime::RecordStrongStringInsertion(mirror::String* s) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordStrongStringInsertion(s);
 }
 
 void Runtime::RecordWeakStringInsertion(mirror::String* s) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordWeakStringInsertion(s);
 }
 
 void Runtime::RecordStrongStringRemoval(mirror::String* s) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordStrongStringRemoval(s);
 }
 
 void Runtime::RecordWeakStringRemoval(mirror::String* s) const {
-  DCHECK(IsCompiler());
+  DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
   preinitialization_transaction_->RecordWeakStringRemoval(s);
 }
@@ -1622,4 +1677,16 @@
 void Runtime::UpdateProfilerState(int state) {
   VLOG(profiler) << "Profiler state updated to " << state;
 }
+
+void Runtime::CreateJit() {
+  CHECK(jit_options_.get() != nullptr);
+  std::string error_msg;
+  jit_.reset(jit::Jit::Create(jit_options_.get(), &error_msg));
+  if (jit_.get() != nullptr) {
+    compiler_callbacks_ = jit_->GetCompilerCallbacks();
+  } else {
+    LOG(WARNING) << "Failed to create JIT " << error_msg;
+  }
+}
+
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index fb9ca40..5078b7f 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -48,6 +48,12 @@
     class GarbageCollector;
   }  // namespace collector
 }  // namespace gc
+
+namespace jit {
+  class Jit;
+  class JitOptions;
+}  // namespace jit
+
 namespace mirror {
   class ArtMethod;
   class ClassLoader;
@@ -95,12 +101,18 @@
   static bool Create(const RuntimeOptions& options, bool ignore_unrecognized)
       SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_);
 
+  // IsAotCompiler for compilers that don't have a running runtime. Only dex2oat currently.
+  bool IsAotCompiler() const {
+    return !UseJit() && IsCompiler();
+  }
+
+  // IsCompiler is any runtime which has a running compiler, either dex2oat or JIT.
   bool IsCompiler() const {
     return compiler_callbacks_ != nullptr;
   }
 
   bool CanRelocate() const {
-    return !IsCompiler() || compiler_callbacks_->IsRelocationPossible();
+    return !IsAotCompiler() || compiler_callbacks_->IsRelocationPossible();
   }
 
   bool ShouldRelocate() const {
@@ -339,9 +351,7 @@
     return !imt_conflict_method_.IsNull();
   }
 
-  void SetImtConflictMethod(mirror::ArtMethod* method) {
-    imt_conflict_method_ = GcRoot<mirror::ArtMethod>(method);
-  }
+  void SetImtConflictMethod(mirror::ArtMethod* method);
   void SetImtUnimplementedMethod(mirror::ArtMethod* method) {
     imt_unimplemented_method_ = GcRoot<mirror::ArtMethod>(method);
   }
@@ -421,6 +431,14 @@
     kUnload,
     kInitialize
   };
+
+  jit::Jit* GetJit() {
+    return jit_.get();
+  }
+  bool UseJit() const {
+    return jit_.get() != nullptr;
+  }
+
   void PreZygoteFork();
   bool InitZygote();
   void DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa);
@@ -505,6 +523,10 @@
     return verify_;
   }
 
+  bool IsDexFileFallbackEnabled() const {
+    return allow_dex_file_fallback_;
+  }
+
   bool RunningOnValgrind() const {
     return running_on_valgrind_;
   }
@@ -521,6 +543,8 @@
     return zygote_max_failed_boots_;
   }
 
+  void CreateJit();
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -600,6 +624,9 @@
 
   JavaVMExt* java_vm_;
 
+  std::unique_ptr<jit::Jit> jit_;
+  std::unique_ptr<jit::JitOptions> jit_options_;
+
   // Fault message, printed when we get a SIGSEGV.
   Mutex fault_message_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::string fault_message_ GUARDED_BY(fault_message_lock_);
@@ -668,6 +695,10 @@
   // If false, verification is disabled. True by default.
   bool verify_;
 
+  // If true, the runtime may use dex files directly with the interpreter if an oat file is not
+  // available/usable.
+  bool allow_dex_file_fallback_;
+
   // Specifies target SDK version to allow workarounds for certain API levels.
   int32_t target_sdk_version_;
 
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 71a0152..d072ffa 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -63,6 +63,9 @@
 RUNTIME_OPTIONS_KEY (Unit,                LowMemoryMode)
 RUNTIME_OPTIONS_KEY (bool,                UseTLAB,                        false)
 RUNTIME_OPTIONS_KEY (bool,                EnableHSpaceCompactForOOM,      true)
+RUNTIME_OPTIONS_KEY (bool,                UseJIT,      false)
+RUNTIME_OPTIONS_KEY (unsigned int,        JITCompileThreshold, jit::Jit::kDefaultCompileThreshold)
+RUNTIME_OPTIONS_KEY (MemoryKiB,           JITCodeCacheCapacity, jit::JitCodeCache::kDefaultCapacity)
 RUNTIME_OPTIONS_KEY (MillisecondsToNanoseconds, \
                                           HSpaceCompactForOOMMinIntervalsMs,\
                                                                           MsToNs(100 * 1000))  // 100s
@@ -115,6 +118,6 @@
                                                                           // Runtime::Abort.
 RUNTIME_OPTIONS_KEY (void (*)(),          HookAbort,                      nullptr)
 RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           1)
-
+RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
 
 #undef RUNTIME_OPTIONS_KEY
diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h
index ebd52d7..7e59000 100644
--- a/runtime/runtime_options.h
+++ b/runtime/runtime_options.h
@@ -26,6 +26,8 @@
 #include "runtime/base/logging.h"
 #include "cmdline/unit.h"
 #include "jdwp/jdwp.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "profiler_options.h"
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index e377542..26bf655 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -180,7 +180,7 @@
 
   Runtime* runtime = Runtime::Current();
   CHECK(runtime->AttachCurrentThread("Signal Catcher", true, runtime->GetSystemThreadGroup(),
-                                     !runtime->IsCompiler()));
+                                     !runtime->IsAotCompiler()));
 
   Thread* self = Thread::Current();
   DCHECK_NE(self->GetState(), kRunnable);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 3b48f49..79d0066 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -541,7 +541,7 @@
   // Set stack_end_ to the bottom of the stack saving space of stack overflows
 
   Runtime* runtime = Runtime::Current();
-  bool implicit_stack_check = !runtime->ExplicitStackOverflowChecks() && !runtime->IsCompiler();
+  bool implicit_stack_check = !runtime->ExplicitStackOverflowChecks() && !runtime->IsAotCompiler();
   ResetDefaultStackEnd();
 
   // Install the protected region if we are doing implicit overflow checks.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index d0f014a..83c5ffb 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -1107,9 +1107,11 @@
     Locks::thread_list_lock_->ExclusiveLock(self);
     bool removed = true;
     if (!Contains(self)) {
+      std::string thread_name;
+      self->GetThreadName(thread_name);
       std::ostringstream os;
       DumpNativeStack(os, GetTid(), "  native: ", nullptr);
-      LOG(ERROR) << "Request to unregister unattached thread\n" << os.str();
+      LOG(ERROR) << "Request to unregister unattached thread " << thread_name << "\n" << os.str();
     } else {
       Locks::thread_suspend_count_lock_->ExclusiveLock(self);
       if (!self->IsSuspended()) {
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 0950abeb..93b3877 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -298,7 +298,7 @@
   intptr_t interval_us = reinterpret_cast<intptr_t>(arg);
   CHECK_GE(interval_us, 0);
   CHECK(runtime->AttachCurrentThread("Sampling Profiler", true, runtime->GetSystemThreadGroup(),
-                                     !runtime->IsCompiler()));
+                                     !runtime->IsAotCompiler()));
 
   while (true) {
     usleep(interval_us);
@@ -627,6 +627,12 @@
   LOG(ERROR) << "Unexpected exception caught event in tracing";
 }
 
+void Trace::BackwardBranch(Thread* /*thread*/, mirror::ArtMethod* method,
+                           int32_t /*dex_pc_offset*/)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  LOG(ERROR) << "Unexpected backward branch event in tracing" << PrettyMethod(method);
+}
+
 void Trace::ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff) {
   if (UseThreadCpuClock()) {
     uint64_t clock_base = thread->GetTraceClockBase();
diff --git a/runtime/trace.h b/runtime/trace.h
index ead1c29..9ba30d5 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -99,7 +99,8 @@
                        mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
                        mirror::Throwable* exception_object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
-
+  void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t dex_pc_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
   // Reuse an old stack trace if it exists, otherwise allocate a new one.
   static std::vector<mirror::ArtMethod*>* AllocStackTrace();
   // Clear and store an old stack trace for later use.
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index 7e2e0a6..e26f955 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -32,7 +32,7 @@
 
 Transaction::Transaction()
   : log_lock_("transaction log lock", kTransactionLogLock), aborted_(false) {
-  CHECK(Runtime::Current()->IsCompiler());
+  CHECK(Runtime::Current()->IsAotCompiler());
 }
 
 Transaction::~Transaction() {
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 2123753..6afc373 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1315,9 +1315,9 @@
           os << "+" << it->func_offset;
         }
         try_addr2line = true;
-      } else if (current_method != nullptr &&
-                 Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
-                 current_method->PcIsWithinQuickCode(it->pc)) {
+      } else if (
+          current_method != nullptr && Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
+          current_method->PcIsWithinQuickCode(it->pc)) {
         const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode();
         os << JniLongName(current_method) << "+"
            << (it->pc - reinterpret_cast<uintptr_t>(start_of_code));
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 474a066d..87a29ed 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -24,6 +24,7 @@
 #include "compiler_callbacks.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
+#include "dex_instruction_utils.h"
 #include "dex_instruction_visitor.h"
 #include "gc/accounting/card_table-inl.h"
 #include "indenter.h"
@@ -111,6 +112,20 @@
   reg_line->MarkAllRegistersAsConflicts(verifier);
 }
 
+MethodVerifier::FailureKind MethodVerifier::VerifyMethod(
+    mirror::ArtMethod* method, bool allow_soft_failures, std::string* error ATTRIBUTE_UNUSED) {
+  Thread* self = Thread::Current();
+  StackHandleScope<3> hs(self);
+  mirror::Class* klass = method->GetDeclaringClass();
+  auto h_dex_cache(hs.NewHandle(klass->GetDexCache()));
+  auto h_class_loader(hs.NewHandle(klass->GetClassLoader()));
+  auto h_method = hs.NewHandle(method);
+  return VerifyMethod(self, method->GetDexMethodIndex(), method->GetDexFile(), h_dex_cache,
+                      h_class_loader, klass->GetClassDef(), method->GetCodeItem(), h_method,
+                      method->GetAccessFlags(), allow_soft_failures, false);
+}
+
+
 MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
                                                         mirror::Class* klass,
                                                         bool allow_soft_failures,
@@ -136,7 +151,7 @@
   }
   if (early_failure) {
     *error = "Verifier rejected class " + PrettyDescriptor(klass) + failure_message;
-    if (Runtime::Current()->IsCompiler()) {
+    if (Runtime::Current()->IsAotCompiler()) {
       ClassReference ref(&dex_file, klass->GetDexClassDefIndex());
       Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref);
     }
@@ -544,7 +559,7 @@
     case VERIFY_ERROR_ACCESS_METHOD:
     case VERIFY_ERROR_INSTANTIATION:
     case VERIFY_ERROR_CLASS_CHANGE:
-      if (Runtime::Current()->IsCompiler() || !can_load_classes_) {
+      if (Runtime::Current()->IsAotCompiler() || !can_load_classes_) {
         // If we're optimistically running verification at compile time, turn NO_xxx, ACCESS_xxx,
         // class change and instantiation errors into soft verification errors so that we re-verify
         // at runtime. We may fail to find or to agree on access because of not yet available class
@@ -568,7 +583,7 @@
       // Hard verification failures at compile time will still fail at runtime, so the class is
       // marked as rejected to prevent it from being compiled.
     case VERIFY_ERROR_BAD_CLASS_HARD: {
-      if (Runtime::Current()->IsCompiler()) {
+      if (Runtime::Current()->IsAotCompiler()) {
         ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def_));
         Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref);
       }
@@ -844,7 +859,7 @@
       result = false;
       break;
   }
-  if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsCompiler() && !verify_to_dump_) {
+  if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsAotCompiler() && !verify_to_dump_) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "opcode only expected at runtime " << inst->Name();
     result = false;
   }
@@ -2812,8 +2827,8 @@
   }
 
   if (have_pending_hard_failure_) {
-    if (Runtime::Current()->IsCompiler()) {
-      /* When compiling, check that the last failure is a hard failure */
+    if (Runtime::Current()->IsAotCompiler()) {
+      /* When AOT compiling, check that the last failure is a hard failure */
       CHECK_EQ(failures_[failures_.size() - 1], VERIFY_ERROR_BAD_CLASS_HARD);
     }
     /* immediate failure, reject class */
@@ -3941,28 +3956,16 @@
 
 mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
                                                       RegisterLine* reg_line) {
-  DCHECK(inst->Opcode() == Instruction::IGET_QUICK ||
-         inst->Opcode() == Instruction::IGET_WIDE_QUICK ||
-         inst->Opcode() == Instruction::IGET_OBJECT_QUICK ||
-         inst->Opcode() == Instruction::IGET_BOOLEAN_QUICK ||
-         inst->Opcode() == Instruction::IGET_BYTE_QUICK ||
-         inst->Opcode() == Instruction::IGET_CHAR_QUICK ||
-         inst->Opcode() == Instruction::IGET_SHORT_QUICK ||
-         inst->Opcode() == Instruction::IPUT_QUICK ||
-         inst->Opcode() == Instruction::IPUT_WIDE_QUICK ||
-         inst->Opcode() == Instruction::IPUT_OBJECT_QUICK ||
-         inst->Opcode() == Instruction::IPUT_BOOLEAN_QUICK ||
-         inst->Opcode() == Instruction::IPUT_BYTE_QUICK ||
-         inst->Opcode() == Instruction::IPUT_CHAR_QUICK ||
-         inst->Opcode() == Instruction::IPUT_SHORT_QUICK);
+  DCHECK(IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) << inst->Opcode();
   const RegType& object_type = reg_line->GetRegisterType(this, inst->VRegB_22c());
   if (!object_type.HasClass()) {
     VLOG(verifier) << "Failed to get mirror::Class* from '" << object_type << "'";
     return nullptr;
   }
   uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c());
-  mirror::ArtField* f = mirror::ArtField::FindInstanceFieldWithOffset(object_type.GetClass(),
-                                                                      field_offset);
+  mirror::ArtField* const f = mirror::ArtField::FindInstanceFieldWithOffset(object_type.GetClass(),
+                                                                            field_offset);
+  DCHECK_EQ(f->GetOffset().Uint32Value(), field_offset);
   if (f == nullptr) {
     VLOG(verifier) << "Failed to find instance field at offset '" << field_offset
                    << "' from '" << PrettyDescriptor(object_type.GetClass()) << "'";
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index b83e647..bdd6259 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -156,6 +156,9 @@
                                              uint32_t method_access_flags)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  static FailureKind VerifyMethod(mirror::ArtMethod* method, bool allow_soft_failures,
+                                  std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   uint8_t EncodePcToReferenceMapData() const;
 
   uint32_t DexFileVersion() const {
@@ -239,10 +242,14 @@
   bool HasFailures() const;
   const RegType& ResolveCheckedClass(uint32_t class_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
-                                           RegisterLine* reg_line,
+  // Returns the method of a quick invoke or nullptr if it cannot be found.
+  mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line,
                                            bool is_range)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Returns the access field of a quick field access (iget/iput-quick) or nullptr
+  // if it cannot be found.
+  mirror::ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Is the method being verified a constructor?
   bool IsConstructor() const {
@@ -532,11 +539,6 @@
                            bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Returns the access field of a quick field access (iget/iput-quick) or nullptr
-  // if it cannot be found.
-  mirror::ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   template <FieldAccessType kAccType>
   void VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type, bool is_primitive)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/test/004-SignalTest/signaltest.cc b/test/004-SignalTest/signaltest.cc
index 31371f6..876d27e 100644
--- a/test/004-SignalTest/signaltest.cc
+++ b/test/004-SignalTest/signaltest.cc
@@ -65,6 +65,8 @@
 #elif defined(__i386__) || defined(__x86_64__)
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   uc->CTX_EIP += 3;
+#else
+  UNUSED(context);
 #endif
 }
 
diff --git a/test/116-nodex2oat/run b/test/116-nodex2oat/run
index 9e5c7dd..2cdb3f7 100755
--- a/test/116-nodex2oat/run
+++ b/test/116-nodex2oat/run
@@ -24,7 +24,7 @@
   exit 1
 fi
 
-# Make sure we can run without an oat file,
+# Make sure we can run without an oat file.
 echo "Run -Xnodex2oat"
 ${RUN} ${flags} --runtime-option -Xnodex2oat
 
diff --git a/test/118-noimage-dex2oat/check b/test/118-noimage-dex2oat/check
new file mode 100755
index 0000000..57111bc
--- /dev/null
+++ b/test/118-noimage-dex2oat/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# 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.
+
+# Strip the process pids and line numbers from exact error messages.
+sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+
+diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/118-noimage-dex2oat/expected.txt b/test/118-noimage-dex2oat/expected.txt
index bcb695d..0103e89 100644
--- a/test/118-noimage-dex2oat/expected.txt
+++ b/test/118-noimage-dex2oat/expected.txt
@@ -1,6 +1,8 @@
 Run -Xnoimage-dex2oat
 Has image is false, is image dex2oat enabled is false, is BOOTCLASSPATH on disk is false.
 testB18485243 PASS
+Run -Xnoimage-dex2oat -Xno-dex-file-fallback
+Failed to initialize runtime (check log for details)
 Run -Ximage-dex2oat
 Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
 testB18485243 PASS
diff --git a/test/118-noimage-dex2oat/run b/test/118-noimage-dex2oat/run
index 2037797..4b1d0ce 100644
--- a/test/118-noimage-dex2oat/run
+++ b/test/118-noimage-dex2oat/run
@@ -46,10 +46,14 @@
 bpath_arg="--runtime-option -Xbootclasspath:${bpath}"
 
 
-# Make sure we can run without an oat file,
+# Make sure we can run without an oat file.
 echo "Run -Xnoimage-dex2oat"
 ${RUN} ${flags} ${bpath_arg} --runtime-option -Xnoimage-dex2oat --runtime-option -Xnodex2oat
 
+# Make sure we cannot run without an oat file without fallback.
+echo "Run -Xnoimage-dex2oat -Xno-dex-file-fallback"
+${RUN} ${flags} ${bpath_arg} --runtime-option -Xnoimage-dex2oat --runtime-option -Xnodex2oat --runtime-option -Xno-dex-file-fallback
+
 # Make sure we can run with the oat file.
 echo "Run -Ximage-dex2oat"
 ${RUN} ${flags} ${bpath_arg} --runtime-option -Ximage-dex2oat
diff --git a/test/119-noimage-patchoat/check b/test/119-noimage-patchoat/check
new file mode 100755
index 0000000..57111bc
--- /dev/null
+++ b/test/119-noimage-patchoat/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# 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.
+
+# Strip the process pids and line numbers from exact error messages.
+sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+
+diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/119-noimage-patchoat/expected.txt b/test/119-noimage-patchoat/expected.txt
index e864268..ed13662 100644
--- a/test/119-noimage-patchoat/expected.txt
+++ b/test/119-noimage-patchoat/expected.txt
@@ -1,5 +1,7 @@
 Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false
 Has image is false, is image dex2oat enabled is false.
+Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false -Xno-dex-file-fallback
+Failed to initialize runtime (check log for details)
 Run -Ximage-dex2oat
 Has image is true, is image dex2oat enabled is true.
 Run default
diff --git a/test/119-noimage-patchoat/run b/test/119-noimage-patchoat/run
index c409cbb..02a64f8 100644
--- a/test/119-noimage-patchoat/run
+++ b/test/119-noimage-patchoat/run
@@ -29,10 +29,14 @@
   false_bin="/system/bin/false"
 fi
 
-# Make sure we can run without an image file,
+# Make sure we can run without an image file.
 echo "Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false"
 ${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat --runtime-option -Xpatchoat:${false_bin}
 
+# Make sure we cannot run without an image file without fallback.
+echo "Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false -Xno-dex-file-fallback"
+${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat --runtime-option -Xpatchoat:${false_bin} --runtime-option -Xno-dex-file-fallback
+
 # Make sure we can run with the image file.
 echo "Run -Ximage-dex2oat"
 ${RUN} ${flags} ${BPATH} --runtime-option -Ximage-dex2oat
diff --git a/test/134-nodex2oat-nofallback/check b/test/134-nodex2oat-nofallback/check
new file mode 100755
index 0000000..d929c8f
--- /dev/null
+++ b/test/134-nodex2oat-nofallback/check
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# 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.
+
+# The head of the log.
+HEAD=$(head -n 1 "$2")
+EXPECTED_HEAD="Unable to locate class 'Main'"
+
+# Content somewhere inside the output.
+grep 'Suppressed: java.io.IOException: Fallback mode disabled, skipping dex files.' "$2" >/dev/null
+MSG_FOUND=$?
+
+if [[ "$HEAD" != "$EXPECTED_HEAD" || $MSG_FOUND -ne 0 ]] ; then
+  # Print out the log and return with error.
+  cat "$2"
+  exit 1
+fi
+
+# Success.
+exit 0
\ No newline at end of file
diff --git a/test/134-nodex2oat-nofallback/expected.txt b/test/134-nodex2oat-nofallback/expected.txt
new file mode 100644
index 0000000..9b6c846
--- /dev/null
+++ b/test/134-nodex2oat-nofallback/expected.txt
@@ -0,0 +1,64 @@
+# This file isn't used, but gives an example of the output we expect.
+Unable to locate class 'Main'
+java.lang.ClassNotFoundException: Didn't find class "Main" on path: DexPathList[[zip file "/tmp/user/test-12345/134-nodex2oat-nofallback.jar"],nativeLibraryDirectories=[/ssd2/aosp-master3/out/host/linux-x86/lib]]
+       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
+       at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
+       at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
+       Suppressed: java.io.IOException: Fallback mode disabled, skipping dex files.
+               at dalvik.system.DexFile.openDexFileNative(Native Method)
+               at dalvik.system.DexFile.openDexFile(DexFile.java:295)
+               at dalvik.system.DexFile.<init>(DexFile.java:80)
+               at dalvik.system.DexFile.<init>(DexFile.java:59)
+               at dalvik.system.DexPathList.loadDexFile(DexPathList.java:262)
+               at dalvik.system.DexPathList.makeDexElements(DexPathList.java:231)
+               at dalvik.system.DexPathList.<init>(DexPathList.java:109)
+               at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
+               at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:38)
+               at java.lang.ClassLoader.createSystemClassLoader(ClassLoader.java:128)
+               at java.lang.ClassLoader.access$000(ClassLoader.java:65)
+               at java.lang.ClassLoader$SystemClassLoader.<clinit>(ClassLoader.java:81)
+               at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:137)
+       Caused by: java.io.IOException: Failed to open oat file from dex location '/tmp/user/test-12345/134-nodex2oat-nofallback.jar'
+               ... 13 more
+       Caused by: java.io.IOException: Failed to open oat file from /tmp/user/test-12345/x86/134-nodex2oat-nofallback.odex (error Failed to open oat filename for reading: No such file or directory) (no dalvik_cache availible) and relocation failed.
+               ... 13 more
+       Caused by: java.io.IOException 
+               ... 13 more
+       Suppressed: java.lang.ClassNotFoundException: Main
+               at java.lang.Class.classForName(Native Method)
+               at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
+               at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
+               at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
+               ... 1 more
+       Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
+java.lang.ClassNotFoundException: Didn't find class "Main" on path: DexPathList[[zip file "/tmp/user/test-12345/134-nodex2oat-nofallback.jar"],nativeLibraryDirectories=[/ssd2/aosp-master3/out/host/linux-x86/lib]]
+       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
+       at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
+       at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
+       Suppressed: java.io.IOException: Fallback mode disabled, skipping dex files.
+               at dalvik.system.DexFile.openDexFileNative(Native Method)
+               at dalvik.system.DexFile.openDexFile(DexFile.java:295)
+               at dalvik.system.DexFile.<init>(DexFile.java:80)
+               at dalvik.system.DexFile.<init>(DexFile.java:59)
+               at dalvik.system.DexPathList.loadDexFile(DexPathList.java:262)
+               at dalvik.system.DexPathList.makeDexElements(DexPathList.java:231)
+               at dalvik.system.DexPathList.<init>(DexPathList.java:109)
+               at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
+               at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:38)
+               at java.lang.ClassLoader.createSystemClassLoader(ClassLoader.java:128)
+               at java.lang.ClassLoader.access$000(ClassLoader.java:65)
+               at java.lang.ClassLoader$SystemClassLoader.<clinit>(ClassLoader.java:81)
+               at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:137)
+       Caused by: java.io.IOException: Failed to open oat file from dex location '/tmp/user/test-12345/134-nodex2oat-nofallback.jar'
+               ... 13 more
+       Caused by: java.io.IOException: Failed to open oat file from /tmp/user/test-12345/x86/134-nodex2oat-nofallback.odex (error Failed to open oat filename for reading: No such file or directory) (no dalvik_cache availible) and relocation failed.
+               ... 13 more
+       Caused by: java.io.IOException: 
+               ... 13 more
+       Suppressed: java.lang.ClassNotFoundException: Main
+               at java.lang.Class.classForName(Native Method)
+               at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
+               at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
+               at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
+               ... 1 more
+       Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
diff --git a/test/134-nodex2oat-nofallback/info.txt b/test/134-nodex2oat-nofallback/info.txt
new file mode 100644
index 0000000..3004729
--- /dev/null
+++ b/test/134-nodex2oat-nofallback/info.txt
@@ -0,0 +1,2 @@
+Test that disables dex2oat'ing the application, and disable fallback. This is derived from test
+116. It needs it separate test as it needs a custom check script.
\ No newline at end of file
diff --git a/test/134-nodex2oat-nofallback/run b/test/134-nodex2oat-nofallback/run
new file mode 100755
index 0000000..38b4adb
--- /dev/null
+++ b/test/134-nodex2oat-nofallback/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# 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.
+
+flags="${@}"
+
+# Make sure we cannot run without an oat file without fallback.
+${RUN} ${flags} --runtime-option -Xnodex2oat --runtime-option -Xno-dex-file-fallback
diff --git a/test/134-nodex2oat-nofallback/src/Main.java b/test/134-nodex2oat-nofallback/src/Main.java
new file mode 100644
index 0000000..37ac9d5
--- /dev/null
+++ b/test/134-nodex2oat-nofallback/src/Main.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    System.out.println(
+        "Has oat is " + hasOat() + ", is dex2oat enabled is " + isDex2OatEnabled() + ".");
+
+    if (hasOat() && !isDex2OatEnabled()) {
+      throw new Error("Application with dex2oat disabled runs with an oat file");
+    } else if (!hasOat() && isDex2OatEnabled()) {
+      throw new Error("Application with dex2oat enabled runs without an oat file");
+    }
+  }
+
+  static {
+    System.loadLibrary("arttest");
+  }
+
+  private native static boolean hasOat();
+
+  private native static boolean isDex2OatEnabled();
+}
diff --git a/test/444-checker-nce/src/Main.java b/test/444-checker-nce/src/Main.java
index 9fb9c46..656c791 100644
--- a/test/444-checker-nce/src/Main.java
+++ b/test/444-checker-nce/src/Main.java
@@ -214,6 +214,30 @@
     return m;
   }
 
+  // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (before)
+  // CHECK:         NullCheck
+
+  // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (after)
+  // CHECK-NOT:     NullCheck
+  public Main scopeIfNotNullRemove(Main m) {
+    if (m != null) {
+      return m.g();
+    }
+    return m;
+  }
+
+  // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (before)
+  // CHECK:         NullCheck
+
+  // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (after)
+  // CHECK:         NullCheck
+  public Main scopeIfKeep(Main m) {
+    if (m == null) {
+      m = new Main();
+    }
+    return m.g();
+  }
+
   public Main() {}
   public Main(int dummy) {}
 
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 5a0e13b..ad4092b 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -46,6 +46,7 @@
     return primeCount;
   }
 
+
   // CHECK-START: void Main.narrow(int[], int) BCE (before)
   // CHECK: BoundsCheck
   // CHECK: ArraySet
@@ -61,8 +62,12 @@
   // CHECK: ArraySet
   // CHECK: BoundsCheck
   // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
 
-  static void narrow(int array[], int offset) {
+  static void narrow(int[] array, int offset) {
     if (offset < 0) {
       return;
     }
@@ -87,10 +92,386 @@
         // eliminate this bounds check.
         array[biased_offset2] = 1;
       }
+
+      // offset_sub1 won't underflow since offset is no less than 0.
+      int offset_sub1 = offset - Integer.MAX_VALUE;
+      if (offset_sub1 >= 0) {
+        array[offset_sub1] = 1;  // Bounds check can be eliminated.
+      }
+
+      // offset_sub2 can underflow.
+      int offset_sub2 = offset_sub1 - Integer.MAX_VALUE;
+      if (offset_sub2 >= 0) {
+        array[offset_sub2] = 1;  // Bounds check can't be eliminated.
+      }
     }
   }
 
+
+  // CHECK-START: void Main.constantIndexing(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.constantIndexing(int[]) BCE (after)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  static void constantIndexing(int[] array) {
+    array[5] = 1;
+    array[4] = 1;
+    array[6] = 1;
+  }
+
+
+  // CHECK-START: void Main.loopPattern1(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.loopPattern1(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void loopPattern1(int[] array) {
+    for (int i = 0; i < array.length; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = 1; i < array.length; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = 1; i < array.length - 1; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = -1; i < array.length; i++) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = 0; i <= array.length; i++) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = 0; i < array.length; i += 2) {
+      // We don't have any assumption on max array length yet.
+      // Bounds check can't be eliminated due to overflow concern.
+      array[i] = 1;
+    }
+
+    for (int i = 1; i < array.length; i += 2) {
+      // Bounds check can be eliminated since i is odd so the last
+      // i that's less than array.length is at most (Integer.MAX_VALUE - 2).
+      array[i] = 1;
+    }
+  }
+
+
+  // CHECK-START: void Main.loopPattern2(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.loopPattern2(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void loopPattern2(int[] array) {
+    for (int i = array.length - 1; i >= 0; i--) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = array.length; i > 0; i--) {
+      array[i - 1] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = array.length - 1; i > 0; i--) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = array.length; i >= 0; i--) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = array.length; i >= 0; i--) {
+      array[i - 1] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = array.length; i > 0; i -= 20) {
+      // For i >= 0, (i - 20 - 1) is guaranteed not to underflow.
+      array[i - 1] = 1;  // Bounds check can be eliminated.
+    }
+  }
+
+
+  // CHECK-START: void Main.loopPattern3(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.loopPattern3(int[]) BCE (after)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  static void loopPattern3(int[] array) {
+    java.util.Random random = new java.util.Random();
+    for (int i = 0; ; i++) {
+      if (random.nextInt() % 1000 == 0 && i < array.length) {
+        // Can't eliminate the bound check since not every i++ is
+        // matched with a array length check, so there is some chance that i
+        // overflows and is negative.
+        array[i] = 1;
+      }
+    }
+  }
+
+
+  // CHECK-START: void Main.constantNewArray() BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.constantNewArray() BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  static void constantNewArray() {
+    int[] array = new int[10];
+    for (int i = 0; i < 10; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = 0; i <= 10; i++) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    array[0] = 1;  // Bounds check can be eliminated.
+    array[9] = 1;  // Bounds check can be eliminated.
+    array[10] = 1; // Bounds check can't be eliminated.
+  }
+
+  // CHECK-START: void Main.pyramid1(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.pyramid1(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
+  static void pyramid1(int[] array) {
+    for (int i = 0; i < (array.length + 1) / 2; i++) {
+      array[i] = i;
+      array[array.length - 1 - i] = i;
+    }
+  }
+
+
+  // CHECK-START: void Main.pyramid2(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.pyramid2(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
+  static void pyramid2(int[] array) {
+    for (int i = 0; i < (array.length + 1) >> 1; i++) {
+      array[i] = i;
+      array[array.length - 1 - i] = i;
+    }
+  }
+
+
+  // CHECK-START: void Main.pyramid3(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.pyramid3(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
+  static void pyramid3(int[] array) {
+    for (int i = 0; i < (array.length + 1) >>> 1; i++) {
+      array[i] = i;
+      array[array.length - 1 - i] = i;
+    }
+  }
+
+
+  // TODO: bce on the array accesses in this method.
+  static boolean isPyramid(int[] array) {
+    int i = 0;
+    int j = array.length - 1;
+    while (i <= j) {
+      if (array[i] != i) {
+        return false;
+      }
+      if (array[j] != i) {
+        return false;
+      }
+      i++; j--;
+    }
+    return true;
+  }
+
+
+  // CHECK-START: void Main.bubbleSort(int[]) GVN (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.bubbleSort(int[]) GVN (after)
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.bubbleSort(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void bubbleSort(int[] array) {
+    for (int i = 0; i < array.length - 1; i++) {
+      for (int j = 0; j < array.length - i - 1; j++) {
+        if (array[j] > array[j + 1]) {
+          int temp = array[j + 1];
+          array[j + 1] = array[j];
+          array[j] = temp;
+        }
+      }
+    }
+  }
+
+
   public static void main(String[] args) {
     sieve(20);
+
+    int[] array = {5, 2, 3, 7, 0, 1, 6, 4};
+    bubbleSort(array);
+    for (int i = 0; i < 8; i++) {
+      if (array[i] != i) {
+        System.out.println("bubble sort failed!");
+      }
+    }
+
+    array = new int[7];
+    pyramid1(array);
+    if (!isPyramid(array)) {
+      System.out.println("pyramid1 failed!");
+    }
+
+    array = new int[8];
+    pyramid2(array);
+    if (!isPyramid(array)) {
+      System.out.println("pyramid2 failed!");
+    }
+
+    java.util.Arrays.fill(array, -1);
+    pyramid3(array);
+    if (!isPyramid(array)) {
+      System.out.println("pyramid3 failed!");
+    }
   }
 }
diff --git a/test/452-multiple-returns2/expected.txt b/test/452-multiple-returns2/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/452-multiple-returns2/expected.txt
diff --git a/test/452-multiple-returns2/info.txt b/test/452-multiple-returns2/info.txt
new file mode 100644
index 0000000..cdd354b
--- /dev/null
+++ b/test/452-multiple-returns2/info.txt
@@ -0,0 +1,2 @@
+Tests inlining of a pattern not generated by DX: multiple
+returns in a single method.
diff --git a/test/452-multiple-returns2/smali/MultipleReturns.smali b/test/452-multiple-returns2/smali/MultipleReturns.smali
new file mode 100644
index 0000000..ff2b9b0
--- /dev/null
+++ b/test/452-multiple-returns2/smali/MultipleReturns.smali
@@ -0,0 +1,40 @@
+# Copyright (C) 2015 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.
+
+.class public LMultipleReturns;
+
+.super Ljava/lang/Object;
+
+.method public static caller()I
+   .registers 1
+   invoke-static {},  LMultipleReturns;->$opt$CalleeReturnInt()I
+   move-result v0
+   return v0
+.end method
+
+.method public static $opt$CalleeReturnInt()I
+   .registers 2
+   const/4 v0, 0x0
+   const/4 v1, 0x1
+   if-eq v1, v0, :else
+   if-eq v1, v0, :else2
+   const/4 v0, 0x4
+   :else2
+   return v0
+   :else
+   if-eq v1, v0, :else3
+   const/4 v1, 0x3
+   :else3
+   return v1
+.end method
diff --git a/test/452-multiple-returns2/src/Main.java b/test/452-multiple-returns2/src/Main.java
new file mode 100644
index 0000000..8904c45
--- /dev/null
+++ b/test/452-multiple-returns2/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("MultipleReturns");
+    Method m = c.getMethod("caller");
+    int result = (Integer)m.invoke(null);
+    if (result != 4) {
+      throw new Error("Expected 4, got " + result);
+    }
+  }
+}
diff --git a/test/453-not-byte/expected.txt b/test/453-not-byte/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/453-not-byte/expected.txt
diff --git a/test/453-not-byte/info.txt b/test/453-not-byte/info.txt
new file mode 100644
index 0000000..2c7f793
--- /dev/null
+++ b/test/453-not-byte/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing, which was expecting int only on a not-int instruction.
+
diff --git a/test/453-not-byte/smali/NotByte.smali b/test/453-not-byte/smali/NotByte.smali
new file mode 100644
index 0000000..9165729
--- /dev/null
+++ b/test/453-not-byte/smali/NotByte.smali
@@ -0,0 +1,23 @@
+# Copyright (C) 2015 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.
+
+.class public LNotByte;
+
+.super Ljava/lang/Object;
+
+.method public static notByte(B)I
+   .registers 1
+   not-int v0, v0
+   return v0
+.end method
diff --git a/test/453-not-byte/src/Main.java b/test/453-not-byte/src/Main.java
new file mode 100644
index 0000000..f055743
--- /dev/null
+++ b/test/453-not-byte/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("NotByte");
+    Method m = c.getMethod("notByte", byte.class);
+    int result = (Integer)m.invoke(null, (byte)42);
+    if (result != -43) {
+      throw new Error("Expected -43, got " + result);
+    }
+  }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index c8e0ec5..41c8da6 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -84,6 +84,9 @@
 ifeq ($(ART_TEST_INTERPRETER),true)
   COMPILER_TYPES += interpreter
 endif
+ifeq ($(ART_TEST_JIT),true)
+  COMPILER_TYPES += jit
+endif
 ifeq ($(ART_TEST_OPTIMIZING),true)
   COMPILER_TYPES += optimizing
 endif
@@ -181,7 +184,8 @@
 # Note 116-nodex2oat is not broken per-se it just doesn't (and isn't meant to) work with --prebuild.
 TEST_ART_BROKEN_PREBUILD_RUN_TESTS := \
   116-nodex2oat \
-  118-noimage-dex2oat
+  118-noimage-dex2oat \
+  134-nodex2oat-nofallback
 
 ifneq (,$(filter prebuild,$(PREBUILD_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),prebuild, \
@@ -496,7 +500,12 @@
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
         run_test_options += --quick
       else
-        $$(error found $(4) expected $(COMPILER_TYPES))
+        ifeq ($(4),jit)
+          test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
+          run_test_options += --jit
+        else
+          $$(error found $(4) expected $(COMPILER_TYPES))
+        endif
       endif
     endif
   endif
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index f64756b..ee40ee8 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -26,6 +26,7 @@
 HAVE_IMAGE="y"
 HOST="n"
 INTERPRETER="n"
+JIT="n"
 INVOKE_WITH=""
 ISA=x86
 LIBRARY_DIRECTORY="lib"
@@ -127,6 +128,9 @@
     elif [ "x$1" = "x--interpreter" ]; then
         INTERPRETER="y"
         shift
+    elif [ "x$1" = "x--jit" ]; then
+        JIT="y"
+        shift
     elif [ "x$1" = "x--jvm" ]; then
         USE_JVM="y"
         shift
@@ -260,6 +264,16 @@
     fi
 fi
 
+if [ "$JIT" = "y" ]; then
+    INT_OPTS="-Xjit"
+    if [ "$VERIFY" = "y" ] ; then
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
+    else
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
+      DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
+    fi
+fi
+
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
 
 if [ "$RELOCATE" = "y" ]; then
diff --git a/test/run-all-tests b/test/run-all-tests
index 318a0de..d0b3cf9 100755
--- a/test/run-all-tests
+++ b/test/run-all-tests
@@ -53,6 +53,9 @@
     elif [ "x$1" = "x--interpreter" ]; then
         run_args="${run_args} --interpreter"
         shift
+    elif [ "x$1" = "x--jit" ]; then
+        run_args="${run_args} --jit"
+        shift
     elif [ "x$1" = "x--no-verify" ]; then
         run_args="${run_args} --no-verify"
         shift
@@ -126,7 +129,7 @@
         echo "  $prog [options]  Run all tests with the given options."
         echo "  Options are all passed to run-test; refer to that for " \
              "further documentation:"
-        echo "    --debug --dev --host --interpreter --jvm --no-optimize"
+        echo "    --debug --dev --host --interpreter --jit --jvm --no-optimize"
         echo "    --no-verify -O --update --valgrind --zygote --64 --relocate"
         echo "    --prebuild --always-clean --gcstress --gcverify --trace"
         echo "    --no-patchoat --no-dex2oat"
diff --git a/test/run-test b/test/run-test
index 8c47663..8bc4151 100755
--- a/test/run-test
+++ b/test/run-test
@@ -193,6 +193,9 @@
         run_args="${run_args} --interpreter"
         image_suffix="-interpreter"
         shift
+    elif [ "x$1" = "x--jit" ]; then
+        run_args="${run_args} --jit"
+        shift
     elif [ "x$1" = "x--optimizing" ]; then
         run_args="${run_args} -Xcompiler-option --compiler-backend=Optimizing"
         image_suffix="-optimizing"
@@ -430,6 +433,7 @@
         echo "    --gdb                 Run under gdb; incompatible with some tests."
         echo "    --build-only          Build test files only (off by default)."
         echo "    --interpreter         Enable interpreter only mode (off by default)."
+        echo "    --jit                 Enable jit (off by default)."
         echo "    --optimizing          Enable optimizing compiler (off by default)."
         echo "    --quick               Use Quick compiler (default)."
         echo "    --no-verify           Turn off verification (on by default)."
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 92d2202..9c1976f 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -34,10 +34,47 @@
   modes: [device],
   names: ["libcore.java.util.TimeZoneTest#testDisplayNames",
           "libcore.java.util.TimeZoneTest#test_useDaylightTime_Taiwan",
+          "libcore.java.util.TimeZoneTest#testAllDisplayNames",
+          "libcore.io.OsTest#testUnixDomainSockets_in_file_system",
+          "org.apache.harmony.luni.tests.java.net.URLConnectionTest#test_setReadTimeoutI",
           "org.apache.harmony.tests.java.util.DateTest#test_Constructor",
           "org.apache.harmony.tests.java.util.ScannerTest#test_Constructor_LReadableByteChannel",
           "org.apache.harmony.tests.java.util.TimeZoneTest#test_hasSameRules_Ljava_util_TimeZone",
-          "libcore.java.util.TimeZoneTest#testAllDisplayNames"]
+          "org.apache.harmony.tests.java.text.ChoiceFormatTest#testEscapedPatternWithConsecutiveQuotes",
+          "org.apache.harmony.tests.java.text.ChoiceFormatTest#testToPatternWithInfinities",
+          "org.apache.harmony.tests.java.text.MessageFormatTest#test19011159"]
+},
+{
+  description: "Failing due to a locale problem on hammerhead.",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.icu.DateIntervalFormatTest#test10089890",
+          "libcore.icu.DateIntervalFormatTest#test10209343_when_not_this_year",
+          "libcore.icu.DateIntervalFormatTest#test10560853_for_single_day_events",
+          "libcore.icu.DateIntervalFormatTest#test10560853_when_time_not_displayed",
+          "libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeString",
+          "libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanString",
+          "libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringAbbrev",
+          "libcore.java.text.OldDateFormatTest#test_parseLString",
+          "libcore.java.text.SimpleDateFormatTest#testDstZoneNameWithNonDstTimestamp",
+          "libcore.java.text.SimpleDateFormatTest#testDstZoneWithNonDstTimestampForNonHourDstZone",
+          "libcore.java.text.SimpleDateFormatTest#testNonDstZoneNameWithDstTimestamp",
+          "libcore.java.text.SimpleDateFormatTest#testNonDstZoneWithDstTimestampForNonHourDstZone",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parseLjava_lang_StringLjava_text_ParsePosition"]
+},
+{
+  description: "Failing due to missing localhost on volantis.",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest",
+          "org.apache.harmony.luni.tests.internal.net.www.protocol.https.HttpsURLConnectionTest",
+          "org.apache.harmony.luni.tests.java.net.URLConnectionTest"]
+},
+{
+  description: "Failing due to missing localhost on hammerhead and volantis.",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.javax.crypto.CipherTest#testCipherInitWithCertificate"]
 },
 {
   description: "Test timeouts",
@@ -50,5 +87,17 @@
   result: EXEC_FAILED,
   modes: [device],
   names: ["org.apache.harmony.tests.java.lang.ProcessTest#test_getErrorStream"]
+},
+{
+  description: "Short date format flag ignored for es_US locale.",
+  result: EXEC_FAILED,
+  name: "libcore.icu.DateIntervalFormatTest#test_formatDateInterval",
+  bug: 18619426
+},
+{
+  description: "Error decoding digital signature bytes.",
+  result: EXEC_FAILED,
+  name: "org.apache.harmony.security.tests.java.security.Signature2Test#test_verify$BII",
+  bug: 18869265
 }
 ]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 9fa3fda..a19fd15 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -28,14 +28,32 @@
 fi
 
 # Packages that currently work correctly with the expectation files.
-working_packages=("libcore.java.lang"
+working_packages=("libcore.icu"
+                  "libcore.io"
+                  "libcore.java.lang"
                   "libcore.java.math"
+                  "libcore.java.text"
                   "libcore.java.util"
+                  "libcore.javax.crypto"
+                  "libcore.javax.security"
+                  "libcore.javax.sql"
+                  "libcore.javax.xml"
+                  "libcore.net"
+                  "libcore.reflect"
+                  "libcore.util"
                   "org.apache.harmony.annotation"
+                  "org.apache.harmony.crypto"
+                  "org.apache.harmony.luni"
+                  "org.apache.harmony.nio"
                   "org.apache.harmony.regex"
+                  "org.apache.harmony.security"
+                  "org.apache.harmony.testframework"
+                  "org.apache.harmony.tests.java.io"
                   "org.apache.harmony.tests.java.lang"
                   "org.apache.harmony.tests.java.math"
                   "org.apache.harmony.tests.java.util"
+                  "org.apache.harmony.tests.java.text"
+                  "org.apache.harmony.tests.javax.security"
                   "tests.java.lang.String")
 
 # Run the tests using vogar.