Merge "Add a HCurrentMethod node."
diff --git a/Android.mk b/Android.mk
index 3467f1d..98d5fb1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -119,6 +119,10 @@
 
 # Sync test files to the target, depends upon all things that must be pushed to the target.
 .PHONY: test-art-target-sync
+# Check if we need to sync. In case ART_TEST_ANDROID_ROOT is not empty,
+# the code below uses 'adb push' instead of 'adb sync', which does not
+# check if the files on the device have changed.
+ifneq ($(ART_TEST_NO_SYNC),true)
 ifeq ($(ART_TEST_ANDROID_ROOT),)
 test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
 	adb root
@@ -130,9 +134,7 @@
 	adb wait-for-device push $(ANDROID_PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
 	adb push $(ANDROID_PRODUCT_OUT)/data /data
 endif
-
-# Undefine variable now its served its purpose.
-TEST_ART_TARGET_SYNC_DEPS :=
+endif
 
 # "mm test-art" to build and run all tests on host and device
 .PHONY: test-art
@@ -377,6 +379,15 @@
 build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUTS)
 
 ########################################################################
+# Rules for building all dependencies for tests.
+
+.PHONY: build-art-host-tests
+build-art-host-tests:   build-art-host $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES) $(ART_TEST_HOST_GTEST_DEPENDENCIES)
+
+.PHONY: build-art-target-tests
+build-art-target-tests:   build-art-target $(TEST_ART_TARGET_SYNC_DEPS)
+
+########################################################################
 # targets to switch back and forth from libdvm to libart
 
 .PHONY: use-art
@@ -467,3 +478,4 @@
 # Clear locally used variables.
 art_dont_bother :=
 art_test_bother :=
+TEST_ART_TARGET_SYNC_DEPS :=
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 3e427a3..b84154b 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -177,8 +177,8 @@
 ART_C_INCLUDES := \
   external/gtest/include \
   external/icu/icu4c/source/common \
-  external/valgrind/main/include \
-  external/valgrind/main \
+  external/valgrind/include \
+  external/valgrind \
   external/vixl/src \
   external/zlib \
 
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 69472b7..0876cc0 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -313,6 +313,7 @@
 ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
+ART_TEST_HOST_GTEST_DEPENDENCIES :=
 
 ART_GTEST_TARGET_ANDROID_ROOT := '/system'
 ifneq ($(ART_TEST_ANDROID_ROOT),)
@@ -374,11 +375,15 @@
   gtest_exe := $$(HOST_OUT_EXECUTABLES)/$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
   # Dependencies for all host gtests.
   gtest_deps := $$(HOST_CORE_DEX_LOCATIONS) \
-    $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION)
+    $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION) \
+    $$(gtest_exe) \
+    $$(ART_GTEST_$(1)_HOST_DEPS) \
+    $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX))
 
+  ART_TEST_HOST_GTEST_DEPENDENCIES += $$(gtest_deps)
 
 .PHONY: $$(gtest_rule)
-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX)) $$(gtest_deps)
+$$(gtest_rule): $$(gtest_exe) $$(gtest_deps)
 	$(hide) ($$(call ART_TEST_SKIP,$$@) && $$< && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@)
 
@@ -388,7 +393,7 @@
 
 
 .PHONY: valgrind-$$(gtest_rule)
-valgrind-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX)) $$(gtest_deps) $(ART_VALGRIND_DEPENDENCIES)
+valgrind-$$(gtest_rule): $$(gtest_deps) $(ART_VALGRIND_DEPENDENCIES)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
 	  VALGRIND_LIB=$(HOST_OUT)/lib64/valgrind \
 	  $(HOST_OUT_EXECUTABLES)/valgrind --leak-check=full --error-exitcode=1 $$< && \
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 8a63a48..5b74c94 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -57,12 +57,12 @@
    public:
     Section(const std::string& name, Elf_Word type, Elf_Word flags,
             const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize)
-        : header_(new Elf_Shdr()), section_index_(0), name_(name), link_(link) {
-      header_->sh_type = type;
-      header_->sh_flags = flags;
-      header_->sh_info = info;
-      header_->sh_addralign = align;
-      header_->sh_entsize = entsize;
+        : header_(), section_index_(0), name_(name), link_(link) {
+      header_.sh_type = type;
+      header_.sh_flags = flags;
+      header_.sh_info = info;
+      header_.sh_addralign = align;
+      header_.sh_entsize = entsize;
     }
     virtual ~Section() {}
 
@@ -80,11 +80,11 @@
     }
 
     const Elf_Shdr* GetHeader() const {
-      return header_.get();
+      return &header_;
     }
 
     Elf_Shdr* GetHeader() {
-      return header_.get();
+      return &header_;
     }
 
     Elf_Word GetSectionIndex() const {
@@ -101,9 +101,7 @@
     }
 
    private:
-    // Elf_Shdr is somewhat large so allocate it on the heap.
-    // Otherwise we get in trouble with stack frame sizes.
-    std::unique_ptr<Elf_Shdr> header_;
+    Elf_Shdr header_;
     Elf_Word section_index_;
     const std::string name_;
     const Section* const link_;
@@ -168,6 +166,10 @@
           patched_(false), patch_(patch), patch_base_section_(patch_base_section) {
     }
 
+    RawSection(const std::string& name, Elf_Word type)
+        : RawSection(name, type, 0, nullptr, 0, 1, 0, nullptr, nullptr) {
+    }
+
     Elf_Word GetSize() const OVERRIDE {
       return buffer_.size();
     }
@@ -779,10 +781,12 @@
 
   template<typename T>
   static bool WriteArray(File* elf_file, const T* data, size_t count) {
-    DCHECK(data != nullptr);
-    if (!elf_file->WriteFully(data, count * sizeof(T))) {
-      PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath();
-      return false;
+    if (count != 0) {
+      DCHECK(data != nullptr);
+      if (!elf_file->WriteFully(data, count * sizeof(T))) {
+        PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath();
+        return false;
+      }
     }
     return true;
   }
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 05b5c68..3f0a80b 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -19,6 +19,7 @@
 #include <unordered_map>
 #include <unordered_set>
 
+#include "base/casts.h"
 #include "base/logging.h"
 #include "base/unix_file/fd_file.h"
 #include "compiled_method.h"
@@ -69,36 +70,17 @@
 template <typename ElfTypes>
 static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer);
 
-// Encode patch locations in .oat_patches format.
+// Encode patch locations as LEB128 list of deltas between consecutive addresses.
 template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::EncodeOatPatches(
-    const OatWriter::PatchLocationsMap& sections,
-    std::vector<uint8_t>* buffer) {
-  for (const auto& section : sections) {
-    const std::string& name = section.first;
-    std::vector<uintptr_t>* locations = section.second.get();
-    DCHECK(!name.empty());
-    std::sort(locations->begin(), locations->end());
-    // Reserve buffer space - guess 2 bytes per ULEB128.
-    buffer->reserve(buffer->size() + name.size() + locations->size() * 2);
-    // Write null-terminated section name.
-    const uint8_t* name_data = reinterpret_cast<const uint8_t*>(name.c_str());
-    buffer->insert(buffer->end(), name_data, name_data + name.size() + 1);
-    // Write placeholder for data length.
-    size_t length_pos = buffer->size();
-    EncodeUnsignedLeb128(buffer, UINT32_MAX);
-    // Write LEB128 encoded list of advances (deltas between consequtive addresses).
-    size_t data_pos = buffer->size();
-    uintptr_t address = 0;  // relative to start of section.
-    for (uintptr_t location : *locations) {
-      DCHECK_LT(location - address, UINT32_MAX) << "Large gap between patch locations";
-      EncodeUnsignedLeb128(buffer, location - address);
-      address = location;
-    }
-    // Update length.
-    UpdateUnsignedLeb128(buffer->data() + length_pos, buffer->size() - data_pos);
+void ElfWriterQuick<ElfTypes>::EncodeOatPatches(const std::vector<uintptr_t>& locations,
+                                                std::vector<uint8_t>* buffer) {
+  buffer->reserve(buffer->size() + locations.size() * 2);  // guess 2 bytes per ULEB128.
+  uintptr_t address = 0;  // relative to start of section.
+  for (uintptr_t location : locations) {
+    DCHECK_GE(location, address) << "Patch locations are not in sorted order";
+    EncodeUnsignedLeb128(buffer, dchecked_integral_cast<uint32_t>(location - address));
+    address = location;
   }
-  buffer->push_back(0);  // End of sections.
 }
 
 class RodataWriter FINAL : public CodeOutput {
@@ -174,48 +156,62 @@
       isa, rodata_size, &rodata_writer, text_size, &text_writer, bss_size));
 
   // Add debug sections.
-  // They are stack allocated here (in the same scope as the builder),
-  // but they are registred with the builder only if they are used.
+  // They are allocated here (in the same scope as the builder),
+  // but they are registered with the builder only if they are used.
   using RawSection = typename ElfBuilder<ElfTypes>::RawSection;
   const auto* text = builder->GetText();
   const bool is64bit = Is64BitInstructionSet(isa);
   const int pointer_size = GetInstructionSetPointerSize(isa);
-  RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
-                      is64bit ? Patch<Elf_Addr, uint64_t, kPointerRelativeAddress> :
-                                Patch<Elf_Addr, uint32_t, kPointerRelativeAddress>,
-                      text);
-  RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0,
-                          Patch<Elf_Addr, uint32_t, kSectionRelativeAddress>, text);
-  RawSection debug_frame(".debug_frame", SHT_PROGBITS, 0, nullptr, 0, pointer_size, 0,
-                         is64bit ? Patch<Elf_Addr, uint64_t, kAbsoluteAddress> :
-                                   Patch<Elf_Addr, uint32_t, kAbsoluteAddress>,
-                         text);
-  RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
-                        Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
-  RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-  RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-  RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
-                        Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
+  std::unique_ptr<RawSection> eh_frame(new RawSection(
+      ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
+      is64bit ? Patch<Elf_Addr, uint64_t, kPointerRelativeAddress> :
+                Patch<Elf_Addr, uint32_t, kPointerRelativeAddress>,
+      text));
+  std::unique_ptr<RawSection> eh_frame_hdr(new RawSection(
+      ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0,
+      Patch<Elf_Addr, uint32_t, kSectionRelativeAddress>, text));
+  std::unique_ptr<RawSection> debug_frame(new RawSection(
+      ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, pointer_size, 0,
+      is64bit ? Patch<Elf_Addr, uint64_t, kAbsoluteAddress> :
+                Patch<Elf_Addr, uint32_t, kAbsoluteAddress>,
+      text));
+  std::unique_ptr<RawSection> debug_frame_oat_patches(new RawSection(
+      ".debug_frame.oat_patches", SHT_OAT_PATCH));
+  std::unique_ptr<RawSection> debug_info(new RawSection(
+      ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
+      Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text));
+  std::unique_ptr<RawSection> debug_info_oat_patches(new RawSection(
+      ".debug_info.oat_patches", SHT_OAT_PATCH));
+  std::unique_ptr<RawSection> debug_abbrev(new RawSection(
+      ".debug_abbrev", SHT_PROGBITS));
+  std::unique_ptr<RawSection> debug_str(new RawSection(
+      ".debug_str", SHT_PROGBITS));
+  std::unique_ptr<RawSection> debug_line(new RawSection(
+      ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
+      Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text));
+  std::unique_ptr<RawSection> debug_line_oat_patches(new RawSection(
+      ".debug_line.oat_patches", SHT_OAT_PATCH));
   if (!oat_writer->GetMethodDebugInfo().empty()) {
     if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
       if (kCFIFormat == dwarf::DW_EH_FRAME_FORMAT) {
         dwarf::WriteCFISection(
             compiler_driver_, oat_writer,
             dwarf::DW_EH_PE_pcrel, kCFIFormat,
-            eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
-            eh_frame_hdr.GetBuffer(), eh_frame_hdr.GetPatchLocations());
-        builder->RegisterSection(&eh_frame);
-        builder->RegisterSection(&eh_frame_hdr);
+            eh_frame->GetBuffer(), eh_frame->GetPatchLocations(),
+            eh_frame_hdr->GetBuffer(), eh_frame_hdr->GetPatchLocations());
+        builder->RegisterSection(eh_frame.get());
+        builder->RegisterSection(eh_frame_hdr.get());
       } else {
         DCHECK(kCFIFormat == dwarf::DW_DEBUG_FRAME_FORMAT);
         dwarf::WriteCFISection(
             compiler_driver_, oat_writer,
             dwarf::DW_EH_PE_absptr, kCFIFormat,
-            debug_frame.GetBuffer(), debug_frame.GetPatchLocations(),
+            debug_frame->GetBuffer(), debug_frame->GetPatchLocations(),
             nullptr, nullptr);
-        builder->RegisterSection(&debug_frame);
-        *oat_writer->GetAbsolutePatchLocationsFor(".debug_frame") =
-            *debug_frame.GetPatchLocations();
+        builder->RegisterSection(debug_frame.get());
+        EncodeOatPatches(*debug_frame->GetPatchLocations(),
+                         debug_frame_oat_patches->GetBuffer());
+        builder->RegisterSection(debug_frame_oat_patches.get());
       }
     }
     if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
@@ -224,29 +220,32 @@
       // Generate DWARF .debug_* sections.
       dwarf::WriteDebugSections(
           compiler_driver_, oat_writer,
-          debug_info.GetBuffer(), debug_info.GetPatchLocations(),
-          debug_abbrev.GetBuffer(),
-          debug_str.GetBuffer(),
-          debug_line.GetBuffer(), debug_line.GetPatchLocations());
-      builder->RegisterSection(&debug_info);
-      builder->RegisterSection(&debug_abbrev);
-      builder->RegisterSection(&debug_str);
-      builder->RegisterSection(&debug_line);
-      *oat_writer->GetAbsolutePatchLocationsFor(".debug_info") =
-          *debug_info.GetPatchLocations();
-      *oat_writer->GetAbsolutePatchLocationsFor(".debug_line") =
-          *debug_line.GetPatchLocations();
+          debug_info->GetBuffer(), debug_info->GetPatchLocations(),
+          debug_abbrev->GetBuffer(),
+          debug_str->GetBuffer(),
+          debug_line->GetBuffer(), debug_line->GetPatchLocations());
+      builder->RegisterSection(debug_info.get());
+      EncodeOatPatches(*debug_info->GetPatchLocations(),
+                       debug_info_oat_patches->GetBuffer());
+      builder->RegisterSection(debug_info_oat_patches.get());
+      builder->RegisterSection(debug_abbrev.get());
+      builder->RegisterSection(debug_str.get());
+      builder->RegisterSection(debug_line.get());
+      EncodeOatPatches(*debug_line->GetPatchLocations(),
+                       debug_line_oat_patches->GetBuffer());
+      builder->RegisterSection(debug_line_oat_patches.get());
     }
   }
 
-  // Add relocation section.
-  RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, nullptr, 0, 1, 0);
-  if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() ||
-      // ElfWriter::Fixup will be called regardless and it needs to be able
-      // to patch debug sections so we have to include patches for them.
-      compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
-    EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer());
-    builder->RegisterSection(&oat_patches);
+  // Add relocation section for .text.
+  std::unique_ptr<RawSection> text_oat_patches(new RawSection(
+      ".text.oat_patches", SHT_OAT_PATCH));
+  if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
+    // Note that ElfWriter::Fixup will be called regardless and therefore
+    // we need to include oat_patches for debug sections unconditionally.
+    EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(),
+                     text_oat_patches->GetBuffer());
+    builder->RegisterSection(text_oat_patches.get());
   }
 
   return builder->Write(elf_file_);
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index 955b568..fd202ee 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -35,7 +35,7 @@
                      const CompilerDriver& driver)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static void EncodeOatPatches(const OatWriter::PatchLocationsMap& sections,
+  static void EncodeOatPatches(const std::vector<uintptr_t>& locations,
                                std::vector<uint8_t>* buffer);
 
  protected:
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 08523d8..ccf34b8 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -88,73 +88,41 @@
   }
 }
 
-// Run only on host since we do unaligned memory accesses.
-#ifndef HAVE_ANDROID_OS
-
-static void PatchSection(const std::vector<uintptr_t>& patch_locations,
-                         std::vector<uint8_t>* section, int32_t delta) {
-  for (uintptr_t location : patch_locations) {
-    *reinterpret_cast<int32_t*>(section->data() + location) += delta;
-  }
-}
-
 TEST_F(ElfWriterTest, EncodeDecodeOatPatches) {
-  std::vector<uint8_t> oat_patches;  // Encoded patches.
+  const std::vector<std::vector<uintptr_t>> test_data {
+      { 0, 4, 8, 15, 128, 200 },
+      { 8, 8 + 127 },
+      { 8, 8 + 128 },
+      { },
+  };
+  for (const auto& patch_locations : test_data) {
+    constexpr int32_t delta = 0x11235813;
 
-  // Encode patch locations for a few sections.
-  OatWriter::PatchLocationsMap sections;
-  std::vector<uintptr_t> patches0 { 0, 4, 8, 15, 128, 200 };  // NOLINT
-  sections.emplace(".section0", std::unique_ptr<std::vector<uintptr_t>>(
-      new std::vector<uintptr_t> { patches0 }));
-  std::vector<uintptr_t> patches1 { 8, 127 };  // NOLINT
-  sections.emplace(".section1", std::unique_ptr<std::vector<uintptr_t>>(
-      new std::vector<uintptr_t> { patches1 }));
-  std::vector<uintptr_t> patches2 { };  // NOLINT
-  sections.emplace(".section2", std::unique_ptr<std::vector<uintptr_t>>(
-      new std::vector<uintptr_t> { patches2 }));
-  ElfWriterQuick32::EncodeOatPatches(sections, &oat_patches);
+    // Encode patch locations.
+    std::vector<uint8_t> oat_patches;
+    ElfWriterQuick32::EncodeOatPatches(patch_locations, &oat_patches);
 
-  // Create buffers to be patched.
-  std::vector<uint8_t> initial_data(256);
-  for (size_t i = 0; i < initial_data.size(); i++) {
-    initial_data[i] = i;
+    // Create buffer to be patched.
+    std::vector<uint8_t> initial_data(256);
+    for (size_t i = 0; i < initial_data.size(); i++) {
+      initial_data[i] = i;
+    }
+
+    // Patch manually.
+    std::vector<uint8_t> expected = initial_data;
+    for (uintptr_t location : patch_locations) {
+      typedef __attribute__((__aligned__(1))) uint32_t UnalignedAddress;
+      *reinterpret_cast<UnalignedAddress*>(expected.data() + location) += delta;
+    }
+
+    // Decode and apply patch locations.
+    std::vector<uint8_t> actual = initial_data;
+    ElfFileImpl32::ApplyOatPatches(
+        oat_patches.data(), oat_patches.data() + oat_patches.size(), delta,
+        actual.data(), actual.data() + actual.size());
+
+    EXPECT_EQ(expected, actual);
   }
-  std::vector<uint8_t> section0_expected = initial_data;
-  std::vector<uint8_t> section1_expected = initial_data;
-  std::vector<uint8_t> section2_expected = initial_data;
-  std::vector<uint8_t> section0_actual = initial_data;
-  std::vector<uint8_t> section1_actual = initial_data;
-  std::vector<uint8_t> section2_actual = initial_data;
-
-  // Patch manually.
-  constexpr int32_t delta = 0x11235813;
-  PatchSection(patches0, &section0_expected, delta);
-  PatchSection(patches1, &section1_expected, delta);
-  PatchSection(patches2, &section2_expected, delta);
-
-  // Decode and apply patch locations.
-  bool section0_successful = ElfFileImpl32::ApplyOatPatches(
-      oat_patches.data(), oat_patches.data() + oat_patches.size(),
-      ".section0", delta,
-      section0_actual.data(), section0_actual.data() + section0_actual.size());
-  EXPECT_TRUE(section0_successful);
-  EXPECT_EQ(section0_expected, section0_actual);
-
-  bool section1_successful = ElfFileImpl32::ApplyOatPatches(
-      oat_patches.data(), oat_patches.data() + oat_patches.size(),
-      ".section1", delta,
-      section1_actual.data(), section1_actual.data() + section1_actual.size());
-  EXPECT_TRUE(section1_successful);
-  EXPECT_EQ(section1_expected, section1_actual);
-
-  bool section2_successful = ElfFileImpl32::ApplyOatPatches(
-      oat_patches.data(), oat_patches.data() + oat_patches.size(),
-      ".section2", delta,
-      section2_actual.data(), section2_actual.data() + section2_actual.size());
-  EXPECT_TRUE(section2_successful);
-  EXPECT_EQ(section2_expected, section2_actual);
 }
 
-#endif
-
 }  // namespace art
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index bf32feb..02a2588 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -972,8 +972,8 @@
   // Fix up the object previously had hash codes.
   for (const std::pair<mirror::Object*, uint32_t>& hash_pair : saved_hashes_) {
     Object* obj = hash_pair.first;
-    DCHECK_EQ(obj->GetLockWord(false).ReadBarrierState(), 0U);
-    obj->SetLockWord(LockWord::FromHashCode(hash_pair.second, 0U), false);
+    DCHECK_EQ(obj->GetLockWord<kVerifyNone>(false).ReadBarrierState(), 0U);
+    obj->SetLockWord<kVerifyNone>(LockWord::FromHashCode(hash_pair.second, 0U), false);
   }
   saved_hashes_.clear();
 }
@@ -1008,11 +1008,11 @@
   const size_t num_elements = arr->GetLength();
   if (target_ptr_size_ == 4u) {
     // Will get fixed up by fixup object.
-    dst->SetClass(down_cast<mirror::Class*>(
+    dst->SetClass<kVerifyNone>(down_cast<mirror::Class*>(
     GetImageAddress(mirror::IntArray::GetArrayClass())));
   } else {
     DCHECK_EQ(target_ptr_size_, 8u);
-    dst->SetClass(down_cast<mirror::Class*>(
+    dst->SetClass<kVerifyNone>(down_cast<mirror::Class*>(
     GetImageAddress(mirror::LongArray::GetArrayClass())));
   }
   mirror::Array* dest_array = down_cast<mirror::Array*>(dst);
@@ -1027,15 +1027,15 @@
       fixup_location = image_begin_ + it2->second;
     }
     if (target_ptr_size_ == 4u) {
-      down_cast<mirror::IntArray*>(dest_array)->SetWithoutChecks<kVerifyNone>(
+      down_cast<mirror::IntArray*>(dest_array)->SetWithoutChecks<false, false, kVerifyNone>(
           i, static_cast<uint32_t>(reinterpret_cast<uint64_t>(fixup_location)));
     } else {
       DCHECK_EQ(target_ptr_size_, 8u);
-      down_cast<mirror::LongArray*>(dest_array)->SetWithoutChecks<kVerifyNone>(
+      down_cast<mirror::LongArray*>(dest_array)->SetWithoutChecks<false, false, kVerifyNone>(
           i, reinterpret_cast<uint64_t>(fixup_location));
     }
   }
-  dst->SetLockWord(LockWord::Default(), false);
+  dst->SetLockWord<kVerifyNone>(LockWord::Default(), false);
   return true;
 }
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 15b4017..745cdcf 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -351,9 +351,8 @@
  public:
   InitCodeMethodVisitor(OatWriter* writer, size_t offset)
     : OatDexMethodVisitor(writer, offset),
-      text_absolute_patch_locations_(writer->GetAbsolutePatchLocationsFor(".text")),
       debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) {
-    text_absolute_patch_locations_->reserve(
+    writer_->absolute_patch_locations_.reserve(
         writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
   }
 
@@ -444,7 +443,7 @@
           uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
             if (!patch.IsPcRelative()) {
-              text_absolute_patch_locations_->push_back(base_loc + patch.LiteralOffset());
+              writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
             }
           }
         }
@@ -547,9 +546,6 @@
   // so we can simply compare the pointers to find out if things are duplicated.
   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
 
-  // Patch locations for the .text section.
-  std::vector<uintptr_t>* const text_absolute_patch_locations_;
-
   // Cache of compiler's --debuggable option.
   const bool debuggable_;
 };
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 6f1b4ec..82b9377 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 #include <cstddef>
-#include <map>
 #include <memory>
 
 #include "linker/relative_patcher.h"  // For linker::RelativePatcherTargetProvider.
@@ -82,8 +81,6 @@
 //
 class OatWriter {
  public:
-  typedef std::map<std::string, std::unique_ptr<std::vector<uintptr_t>>> PatchLocationsMap;
-
   OatWriter(const std::vector<const DexFile*>& dex_files,
             uint32_t image_file_location_oat_checksum,
             uintptr_t image_file_location_oat_begin,
@@ -105,19 +102,10 @@
     return bss_size_;
   }
 
-  const PatchLocationsMap& GetAbsolutePatchLocations() const {
+  const std::vector<uintptr_t>& GetAbsolutePatchLocations() const {
     return absolute_patch_locations_;
   }
 
-  std::vector<uintptr_t>* GetAbsolutePatchLocationsFor(const char* section_name) {
-    auto it = absolute_patch_locations_.emplace(
-        std::string(section_name), std::unique_ptr<std::vector<uintptr_t>>());
-    if (it.second) {  // Inserted new item.
-      it.first->second.reset(new std::vector<uintptr_t>());
-    }
-    return it.first->second.get();
-  }
-
   bool WriteRodata(OutputStream* out);
   bool WriteCode(OutputStream* out);
 
@@ -339,9 +327,8 @@
 
   std::unique_ptr<linker::RelativePatcher> relative_patcher_;
 
-  // The locations of absolute patches relative to the start of section.
-  // The map's key is the ELF's section name (including the dot).
-  PatchLocationsMap absolute_patch_locations_;
+  // The locations of absolute patches relative to the start of the executable section.
+  std::vector<uintptr_t> absolute_patch_locations_;
 
   // Map method reference to assigned offset.
   // Wrap the map in a class implementing linker::RelativePatcherTargetProvider.
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 163458f..48090a3 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -647,7 +647,7 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
   HInstruction* new_array = new (allocator)
-      HNewArray(constant_10, 0, Primitive::kPrimInt, kQuickAllocArray);
+      HNewArray(constant_10, 0, Primitive::kPrimInt, graph->GetDexFile(), kQuickAllocArray);
   block->AddInstruction(new_array);
   block->AddInstruction(new (allocator) HGoto());
 
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index c142e4d..41c1d2c 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1034,7 +1034,11 @@
   QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
       ? kQuickAllocArrayWithAccessCheck
       : kQuickAllocArray;
-  HInstruction* object = new (arena_) HNewArray(length, dex_pc, type_index, entrypoint);
+  HInstruction* object = new (arena_) HNewArray(length,
+                                                dex_pc,
+                                                type_index,
+                                                *dex_compilation_unit_->GetDexFile(),
+                                                entrypoint);
   current_block_->AddInstruction(object);
 
   const char* descriptor = dex_file_->StringByTypeIdx(type_index);
@@ -2001,8 +2005,8 @@
       QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
           ? kQuickAllocArrayWithAccessCheck
           : kQuickAllocArray;
-      current_block_->AddInstruction(
-          new (arena_) HNewArray(length, dex_pc, type_index, entrypoint));
+      current_block_->AddInstruction(new (arena_) HNewArray(
+          length, dex_pc, type_index, *dex_compilation_unit_->GetDexFile(), entrypoint));
       UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
       break;
     }
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 1cca522..ab3b6b0 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1029,19 +1029,19 @@
   GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
 }
 
-void LocationsBuilderARM::VisitCondition(HCondition* comp) {
+void LocationsBuilderARM::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
-  if (comp->NeedsMaterialization()) {
+  locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+  if (cond->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   }
 }
 
-void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
-  if (!comp->NeedsMaterialization()) return;
-  LocationSummary* locations = comp->GetLocations();
+void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
+  if (!cond->NeedsMaterialization()) return;
+  LocationSummary* locations = cond->GetLocations();
   Register left = locations->InAt(0).AsRegister<Register>();
 
   if (locations->InAt(1).IsRegister()) {
@@ -1058,11 +1058,11 @@
       __ cmp(left, ShifterOperand(temp));
     }
   }
-  __ it(ARMCondition(comp->GetCondition()), kItElse);
+  __ it(ARMCondition(cond->GetCondition()), kItElse);
   __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
-         ARMCondition(comp->GetCondition()));
+         ARMCondition(cond->GetCondition()));
   __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
-         ARMOppositeCondition(comp->GetCondition()));
+         ARMOppositeCondition(cond->GetCondition()));
 }
 
 void LocationsBuilderARM::VisitEqual(HEqual* comp) {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 3c5efa4..1688efc 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -984,20 +984,20 @@
   UNUSED(store);
 }
 
-void LocationsBuilderX86::VisitCondition(HCondition* comp) {
+void LocationsBuilderX86::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
-  if (comp->NeedsMaterialization()) {
+  if (cond->NeedsMaterialization()) {
     // We need a byte register.
     locations->SetOut(Location::RegisterLocation(ECX));
   }
 }
 
-void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
-  if (comp->NeedsMaterialization()) {
-    LocationSummary* locations = comp->GetLocations();
+void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
+  if (cond->NeedsMaterialization()) {
+    LocationSummary* locations = cond->GetLocations();
     Register reg = locations->Out().AsRegister<Register>();
     // Clear register: setcc only sets the low byte.
     __ xorl(reg, reg);
@@ -1015,7 +1015,7 @@
     } else {
       __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
     }
-    __ setb(X86Condition(comp->GetCondition()), reg);
+    __ setb(X86Condition(cond->GetCondition()), reg);
   }
 }
 
@@ -1960,6 +1960,8 @@
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
+        } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
+          __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
         } else {
           __ leal(out.AsRegister<Register>(), Address(
               first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 7b08c89..7847701 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -945,19 +945,19 @@
   UNUSED(store);
 }
 
-void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
+void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
-  if (comp->NeedsMaterialization()) {
+  if (cond->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
 }
 
-void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
-  if (comp->NeedsMaterialization()) {
-    LocationSummary* locations = comp->GetLocations();
+void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
+  if (cond->NeedsMaterialization()) {
+    LocationSummary* locations = cond->GetLocations();
     CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
     // Clear register: setcc only sets the low byte.
     __ xorl(reg, reg);
@@ -975,7 +975,7 @@
     } else {
       __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
     }
-    __ setcc(X86_64Condition(comp->GetCondition()), reg);
+    __ setcc(X86_64Condition(cond->GetCondition()), reg);
   }
 }
 
@@ -2118,6 +2118,8 @@
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+        } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
+          __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
         } else {
           __ leal(out.AsRegister<CpuRegister>(), Address(
               first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
@@ -2141,6 +2143,8 @@
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+        } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
+          __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
         } else {
           __ leaq(out.AsRegister<CpuRegister>(), Address(
               first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index d542e59..869809d 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2676,16 +2676,19 @@
   HNewArray(HInstruction* length,
             uint32_t dex_pc,
             uint16_t type_index,
+            const DexFile& dex_file,
             QuickEntrypointEnum entrypoint)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         dex_pc_(dex_pc),
         type_index_(type_index),
+        dex_file_(dex_file),
         entrypoint_(entrypoint) {
     SetRawInputAt(0, length);
   }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
+  const DexFile& GetDexFile() const { return dex_file_; }
 
   // Calls runtime so needs an environment.
   bool NeedsEnvironment() const OVERRIDE { return true; }
@@ -2702,6 +2705,7 @@
  private:
   const uint32_t dex_pc_;
   const uint16_t type_index_;
+  const DexFile& dex_file_;
   const QuickEntrypointEnum entrypoint_;
 
   DISALLOW_COPY_AND_ASSIGN(HNewArray);
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 601b48a..91b2e6f 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -35,7 +35,7 @@
 
 void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
   // TODO: handle other instructions that give type info
-  // (NewArray/Call/Field accesses/array accesses)
+  // (Call/Field accesses/array accesses)
 
   // Initialize exact types first for faster convergence.
   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
@@ -44,6 +44,8 @@
       VisitNewInstance(instr->AsNewInstance());
     } else if (instr->IsLoadClass()) {
       VisitLoadClass(instr->AsLoadClass());
+    } else if (instr->IsNewArray()) {
+      VisitNewArray(instr->AsNewArray());
     }
   }
 
@@ -159,18 +161,29 @@
   }
 }
 
-void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) {
+void ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr,
+                                                       uint16_t type_idx,
+                                                       const DexFile& dex_file) {
+  DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
+
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache =
-      Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
+  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier.
-  mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
+  mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class != nullptr) {
     MutableHandle<mirror::Class> handle = handles_->NewHandle(resolved_class);
     instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, true));
   }
 }
 
+void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) {
+  UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile());
+}
+
+void ReferenceTypePropagation::VisitNewArray(HNewArray* instr) {
+  UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile());
+}
+
 void ReferenceTypePropagation::VisitLoadClass(HLoadClass* instr) {
   ScopedObjectAccess soa(Thread::Current());
   mirror::DexCache* dex_cache =
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index b68fc67..12c3362 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -42,6 +42,7 @@
  private:
   void VisitNewInstance(HNewInstance* new_instance);
   void VisitLoadClass(HLoadClass* load_class);
+  void VisitNewArray(HNewArray* instr);
   void VisitPhi(HPhi* phi);
   void VisitBasicBlock(HBasicBlock* block);
 
@@ -50,6 +51,7 @@
 
   void BoundTypeForIfNotNull(HBasicBlock* block);
   void BoundTypeForIfInstanceOf(HBasicBlock* block);
+  void UpdateReferenceTypeInfo(HInstruction* instr, uint16_t type_idx, const DexFile& dex_file);
 
   void ProcessWorklist();
   void AddToWorklist(HInstruction* instr);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index a67ef8f..04f5a6a 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1035,7 +1035,7 @@
   void DumpCodeInfo(std::ostream& os,
                     const CodeInfo& code_info,
                     const DexFile::CodeItem& code_item) {
-    code_info.Dump(os, code_item.registers_size_);
+    code_info.Dump(os, code_item.registers_size_, true);
   }
 
   // Display a vmap table.
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index ef84a17..8db1d23 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -563,21 +563,21 @@
   uintptr_t quick= reinterpret_cast<uintptr_t>(
       object->GetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(pointer_size));
   if (quick != 0) {
-    copy->SetEntryPointFromQuickCompiledCodePtrSize(reinterpret_cast<void*>(quick + delta_),
-                                                    pointer_size);
+    copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
+        reinterpret_cast<void*>(quick + delta_), pointer_size);
   }
   uintptr_t interpreter = reinterpret_cast<uintptr_t>(
       object->GetEntryPointFromInterpreterPtrSize<kVerifyNone>(pointer_size));
   if (interpreter != 0) {
-    copy->SetEntryPointFromInterpreterPtrSize(
+    copy->SetEntryPointFromInterpreterPtrSize<kVerifyNone>(
         reinterpret_cast<mirror::EntryPointFromInterpreter*>(interpreter + delta_), pointer_size);
   }
 
   uintptr_t native_method = reinterpret_cast<uintptr_t>(
       object->GetEntryPointFromJniPtrSize(pointer_size));
   if (native_method != 0) {
-    copy->SetEntryPointFromJniPtrSize(reinterpret_cast<void*>(native_method + delta_),
-                                      pointer_size);
+    copy->SetEntryPointFromJniPtrSize<kVerifyNone>(
+        reinterpret_cast<void*>(native_method + delta_), pointer_size);
   }
 }
 
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index af2f661..5488f9d 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -134,7 +134,7 @@
     gprs[i] = gprs_[i] != nullptr ? *gprs_[i] : Arm64Context::kBadGprBase + i;
   }
   for (size_t i = 0; i < kNumberOfDRegisters; ++i) {
-    fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : Arm64Context::kBadGprBase + i;
+    fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : Arm64Context::kBadFprBase + i;
   }
   DCHECK_EQ(reinterpret_cast<uintptr_t>(Thread::Current()), gprs[TR]);
   art_quick_do_long_jump(gprs, fprs);
diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc
index f0c893a..24892e9 100644
--- a/runtime/arch/mips/context_mips.cc
+++ b/runtime/arch/mips/context_mips.cc
@@ -87,7 +87,7 @@
     gprs[i] = gprs_[i] != nullptr ? *gprs_[i] : MipsContext::kBadGprBase + i;
   }
   for (size_t i = 0; i < kNumberOfFRegisters; ++i) {
-    fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : MipsContext::kBadGprBase + i;
+    fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : MipsContext::kBadFprBase + i;
   }
   art_quick_do_long_jump(gprs, fprs);
 }
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 0752c59..728e8e3 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3703,7 +3703,9 @@
 
   mirror::ArtMethod* m = single_step_control->GetMethod();
   const int32_t line_number = visitor.line_number;
-  if (!m->IsNative()) {
+  // Note: if the thread is not running Java code (pure native thread), there is no "current"
+  // method on the stack (and no line number either).
+  if (m != nullptr && !m->IsNative()) {
     const DexFile::CodeItem* const code_item = m->GetCodeItem();
     DebugCallbackContext context(single_step_control, line_number, code_item);
     m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index b1d933d..9fd8c87 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1401,86 +1401,53 @@
 }
 
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) {
+bool ElfFileImpl<ElfTypes>::FixupDebugSections(Elf_Addr base_address_delta) {
   if (base_address_delta == 0) {
     return true;
   }
-  if (FindSectionByName(".debug_frame") != nullptr) {
-    if (!ApplyOatPatchesTo(".debug_frame", base_address_delta)) {
-      return false;
-    }
-  }
-  if (FindSectionByName(".debug_info") != nullptr) {
-    if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) {
-      return false;
-    }
-  }
-  if (FindSectionByName(".debug_line") != nullptr) {
-    if (!ApplyOatPatchesTo(".debug_line", base_address_delta)) {
-      return false;
-    }
-  }
-  return true;
+  return ApplyOatPatchesTo(".debug_frame", base_address_delta) &&
+         ApplyOatPatchesTo(".debug_info", base_address_delta) &&
+         ApplyOatPatchesTo(".debug_line", base_address_delta);
 }
 
 template <typename ElfTypes>
 bool ElfFileImpl<ElfTypes>::ApplyOatPatchesTo(
-    const char* target_section_name,
-    typename std::make_signed<Elf_Off>::type delta) {
-  auto patches_section = FindSectionByName(".oat_patches");
+    const char* target_section_name, Elf_Addr delta) {
+  auto target_section = FindSectionByName(target_section_name);
+  if (target_section == nullptr) {
+    return true;
+  }
+  std::string patches_name = target_section_name + std::string(".oat_patches");
+  auto patches_section = FindSectionByName(patches_name.c_str());
   if (patches_section == nullptr) {
-    LOG(ERROR) << ".oat_patches section not found.";
+    LOG(ERROR) << patches_name << " section not found.";
     return false;
   }
   if (patches_section->sh_type != SHT_OAT_PATCH) {
-    LOG(ERROR) << "Unexpected type of .oat_patches.";
+    LOG(ERROR) << "Unexpected type of " << patches_name;
     return false;
   }
-  auto target_section = FindSectionByName(target_section_name);
-  if (target_section == nullptr) {
-    LOG(ERROR) << target_section_name << " section not found.";
-    return false;
-  }
-  if (!ApplyOatPatches(
+  ApplyOatPatches(
       Begin() + patches_section->sh_offset,
       Begin() + patches_section->sh_offset + patches_section->sh_size,
-      target_section_name, delta,
+      delta,
       Begin() + target_section->sh_offset,
-      Begin() + target_section->sh_offset + target_section->sh_size)) {
-    LOG(ERROR) << target_section_name << " section not found in .oat_patches.";
-  }
+      Begin() + target_section->sh_offset + target_section->sh_size);
   return true;
 }
 
-// Apply .oat_patches to given section.
+// Apply LEB128 encoded patches to given section.
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::ApplyOatPatches(
-    const uint8_t* patches, const uint8_t* patches_end,
-    const char* target_section_name,
-    typename std::make_signed<Elf_Off>::type delta,
+void ElfFileImpl<ElfTypes>::ApplyOatPatches(
+    const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta,
     uint8_t* to_patch, const uint8_t* to_patch_end) {
-  // Read null-terminated section name.
-  const char* section_name;
-  while ((section_name = reinterpret_cast<const char*>(patches))[0] != '\0') {
-    patches += strlen(section_name) + 1;
-    uint32_t length = DecodeUnsignedLeb128(&patches);
-    const uint8_t* next_section = patches + length;
-    // Is it the section we want to patch?
-    if (strcmp(section_name, target_section_name) == 0) {
-      // Read LEB128 encoded list of advances.
-      while (patches < next_section) {
-        DCHECK_LT(patches, patches_end) << "Unexpected end of .oat_patches.";
-        to_patch += DecodeUnsignedLeb128(&patches);
-        DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of " << section_name;
-        // TODO: 32-bit vs 64-bit.  What is the right type to use here?
-        auto* patch_loc = reinterpret_cast<typename std::make_signed<Elf_Off>::type*>(to_patch);
-        *patch_loc += delta;
-      }
-      return true;
-    }
-    patches = next_section;
+  typedef __attribute__((__aligned__(1))) Elf_Addr UnalignedAddress;
+  while (patches < patches_end) {
+    to_patch += DecodeUnsignedLeb128(&patches);
+    DCHECK_LE(patches, patches_end) << "Unexpected end of patch list.";
+    DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of section.";
+    *reinterpret_cast<UnalignedAddress*>(to_patch) += delta;
   }
-  return false;
 }
 
 template <typename ElfTypes>
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
index 3ad096f..0f466bd 100644
--- a/runtime/elf_file_impl.h
+++ b/runtime/elf_file_impl.h
@@ -119,12 +119,9 @@
   bool FixupProgramHeaders(Elf_Addr base_address);
   bool FixupSymbols(Elf_Addr base_address, bool dynamic);
   bool FixupRelocations(Elf_Addr base_address);
-  bool FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta);
-  bool ApplyOatPatchesTo(const char* target_section_name,
-                         typename std::make_signed<Elf_Off>::type base_address_delta);
-  static bool ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end,
-                              const char* target_section_name,
-                              typename std::make_signed<Elf_Off>::type delta,
+  bool FixupDebugSections(Elf_Addr base_address_delta);
+  bool ApplyOatPatchesTo(const char* target_section_name, Elf_Addr base_address_delta);
+  static void ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta,
                               uint8_t* to_patch, const uint8_t* to_patch_end);
 
   bool Strip(std::string* error_msg);
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index 8cd6ca6..3bcaf93 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -38,22 +38,24 @@
 
 class ScopedQuickEntrypointChecks {
  public:
-  explicit ScopedQuickEntrypointChecks(Thread *self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : self_(self) {
-    if (kIsDebugBuild) {
+  explicit ScopedQuickEntrypointChecks(Thread *self,
+                                       bool entry_check = kIsDebugBuild,
+                                       bool exit_check = kIsDebugBuild)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : self_(self), exit_check_(exit_check) {
+    if (entry_check) {
       TestsOnEntry();
     }
   }
 
-  explicit ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : self_(kIsDebugBuild ? Thread::Current() : nullptr) {
+  ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : self_(kIsDebugBuild ? Thread::Current() : nullptr), exit_check_(kIsDebugBuild) {
     if (kIsDebugBuild) {
       TestsOnEntry();
     }
   }
 
   ~ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (kIsDebugBuild) {
+    if (exit_check_) {
       TestsOnExit();
     }
   }
@@ -70,6 +72,7 @@
   }
 
   Thread* const self_;
+  bool exit_check_;
 };
 
 static constexpr size_t GetCalleeSaveFrameSize(InstructionSet isa, Runtime::CalleeSaveType type) {
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index eb1b105..2bb73ef 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -29,7 +29,9 @@
                                                              Thread* self,
                                                              uintptr_t lr)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ScopedQuickEntrypointChecks sqec(self);
+  // Instrumentation changes the stack. Thus, when exiting, the stack cannot be verified, so skip
+  // that part.
+  ScopedQuickEntrypointChecks sqec(self, kIsDebugBuild, false);
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   const void* result;
   if (instrumentation->IsDeoptimized(method)) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index f5bc080..c029eeb 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -823,7 +823,10 @@
                                                     Thread* self,
                                                     StackReference<mirror::ArtMethod>* sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ScopedQuickEntrypointChecks sqec(self);
+  // The resolution trampoline stashes the resolved method into the callee-save frame to transport
+  // it. Thus, when exiting, the stack cannot be verified (as the resolved method most likely
+  // does not have the same stack layout as the callee-save method).
+  ScopedQuickEntrypointChecks sqec(self, kIsDebugBuild, false);
   // Start new JNI local reference state
   JNIEnvExt* env = self->GetJniEnv();
   ScopedObjectAccessUnchecked soa(env);
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index e93717e..f3546b1 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -239,7 +239,7 @@
 }
 
 template<typename T>
-template<bool kTransactionActive, bool kCheckTransaction>
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
 inline void PrimitiveArray<T>::SetWithoutChecks(int32_t i, T value) {
   if (kCheckTransaction) {
     DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
@@ -247,7 +247,7 @@
   if (kTransactionActive) {
     Runtime::Current()->RecordWriteArray(this, i, GetWithoutChecks(i));
   }
-  DCHECK(CheckIsValidIndex(i));
+  DCHECK(CheckIsValidIndex<kVerifyFlags>(i));
   GetData()[i] = value;
 }
 // Backward copy where elements are of aligned appropriately for T. Count is in T sized units.
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 832ad68..167f824 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -131,7 +131,9 @@
 
   // TODO fix thread safety analysis broken by the use of template. This should be
   // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
-  template<bool kTransactionActive, bool kCheckTransaction = true>
+  template<bool kTransactionActive,
+           bool kCheckTransaction = true,
+           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetWithoutChecks(int32_t i, T value) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS;
 
   /*
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 39d0f56..7760ea2 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -59,19 +59,23 @@
       OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass);
 }
 
+template<VerifyObjectFlags kVerifyFlags>
 inline LockWord Object::GetLockWord(bool as_volatile) {
   if (as_volatile) {
-    return LockWord(GetField32Volatile(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+    return LockWord(GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
   }
-  return LockWord(GetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+  return LockWord(GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
 }
 
+template<VerifyObjectFlags kVerifyFlags>
 inline void Object::SetLockWord(LockWord new_val, bool as_volatile) {
   // Force use of non-transactional mode and do not check.
   if (as_volatile) {
-    SetField32Volatile<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
+    SetField32Volatile<false, false, kVerifyFlags>(
+        OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
   } else {
-    SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
+    SetField32<false, false, kVerifyFlags>(
+        OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
   }
 }
 
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 5afe99f..2c0e626 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -125,7 +125,9 @@
 
   // As_volatile can be false if the mutators are suspended. This is an optimization since it
   // avoids the barriers.
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   LockWord GetLockWord(bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetLockWord(LockWord new_val, bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 9736e15..a172197 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -16,6 +16,9 @@
 
 #include "dalvik_system_VMRuntime.h"
 
+#ifdef HAVE_ANDROID_OS
+extern "C" void android_set_application_target_sdk_version(uint32_t version);
+#endif
 #include <limits.h>
 #include <ScopedUtfChars.h>
 
@@ -192,6 +195,12 @@
   // Note that targetSdkVersion may be CUR_DEVELOPMENT (10000).
   // Note that targetSdkVersion may be 0, meaning "current".
   Runtime::Current()->SetTargetSdkVersion(target_sdk_version);
+
+#ifdef HAVE_ANDROID_OS
+  // This part is letting libc/dynamic linker know about current app's
+  // target sdk version to enable compatibility workarounds.
+  android_set_application_target_sdk_version(static_cast<uint32_t>(target_sdk_version));
+#endif
 }
 
 static void VMRuntime_registerNativeAllocation(JNIEnv* env, jobject, jint bytes) {
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 6a0c07d..c36ee05 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -18,6 +18,8 @@
 
 #include <stdint.h>
 
+#include "indenter.h"
+
 namespace art {
 
 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
@@ -203,72 +205,95 @@
                                 DexRegisterLocation location,
                                 const std::string& prefix = "v",
                                 const std::string& suffix = "") {
-  os << "      " << prefix << dex_register_num << ": "
-     << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
-     << " (" << location.GetValue() << ")" << suffix << '\n';
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
+  indented_os << prefix << dex_register_num << ": "
+              << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
+              << " (" << location.GetValue() << ")" << suffix << '\n';
+}
+
+void CodeInfo::DumpStackMap(std::ostream& os,
+                            size_t stack_map_num,
+                            uint16_t number_of_dex_registers) const {
+  StackMap stack_map = GetStackMapAt(stack_map_num);
+  DumpStackMapHeader(os, stack_map_num);
+  if (stack_map.HasDexRegisterMap(*this)) {
+    DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+    dex_register_map.Dump(os, *this, number_of_dex_registers);
+  }
 }
 
 void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
   StackMap stack_map = GetStackMapAt(stack_map_num);
-  os << "    StackMap " << stack_map_num
-     << std::hex
-     << " (dex_pc=0x" << stack_map.GetDexPc(*this)
-     << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
-     << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
-     << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
-     << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
-     << std::dec
-     << ", stack_mask=0b";
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
+  indented_os << "StackMap " << stack_map_num
+              << std::hex
+              << " (dex_pc=0x" << stack_map.GetDexPc(*this)
+              << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
+              << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
+              << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
+              << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
+              << std::dec
+              << ", stack_mask=0b";
   MemoryRegion stack_mask = stack_map.GetStackMask(*this);
   for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
-    os << stack_mask.LoadBit(e - i - 1);
+    indented_os << stack_mask.LoadBit(e - i - 1);
   }
-  os << ")\n";
+  indented_os << ")\n";
 };
 
-void CodeInfo::Dump(std::ostream& os, uint16_t number_of_dex_registers) const {
+void CodeInfo::Dump(std::ostream& os,
+                    uint16_t number_of_dex_registers,
+                    bool dump_stack_maps) const {
   uint32_t code_info_size = GetOverallSize();
   size_t number_of_stack_maps = GetNumberOfStackMaps();
-  os << "  Optimized CodeInfo (size=" << code_info_size
-     << ", number_of_dex_registers=" << number_of_dex_registers
-     << ", number_of_stack_maps=" << number_of_stack_maps
-     << ", has_inline_info=" << HasInlineInfo()
-     << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
-     << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
-     << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
-     << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
-     << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
-     << ")\n";
-
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
+  indented_os << "Optimized CodeInfo (size=" << code_info_size
+              << ", number_of_dex_registers=" << number_of_dex_registers
+              << ", number_of_stack_maps=" << number_of_stack_maps
+              << ", has_inline_info=" << HasInlineInfo()
+              << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
+              << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
+              << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
+              << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
+              << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
+              << ")\n";
   // Display the Dex register location catalog.
-  size_t number_of_location_catalog_entries = GetNumberOfDexRegisterLocationCatalogEntries();
-  size_t location_catalog_size_in_bytes = GetDexRegisterLocationCatalogSize();
-  os << "  DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
-     << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
-  DexRegisterLocationCatalog dex_register_location_catalog = GetDexRegisterLocationCatalog();
-  for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
-    DexRegisterLocation location = dex_register_location_catalog.GetDexRegisterLocation(i);
-    DumpRegisterMapping(os, i, location, "entry ");
-  }
-
+  GetDexRegisterLocationCatalog().Dump(indented_os, *this);
   // Display stack maps along with (live) Dex register maps.
-  for (size_t i = 0; i < number_of_stack_maps; ++i) {
-    StackMap stack_map = GetStackMapAt(i);
-    DumpStackMapHeader(os, i);
-    if (stack_map.HasDexRegisterMap(*this)) {
-      DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-      dex_register_map.Dump(os, *this, number_of_dex_registers);
+  if (dump_stack_maps) {
+    for (size_t i = 0; i < number_of_stack_maps; ++i) {
+      DumpStackMap(indented_os, i, number_of_dex_registers);
     }
   }
   // TODO: Dump the stack map's inline information? We need to know more from the caller:
   //       we need to know the number of dex registers for each inlined method.
 }
 
+void DexRegisterLocationCatalog::Dump(std::ostream& os, const CodeInfo& code_info) {
+  size_t number_of_location_catalog_entries =
+      code_info.GetNumberOfDexRegisterLocationCatalogEntries();
+  size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize();
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
+  indented_os
+      << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
+      << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
+  for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
+    DexRegisterLocation location = GetDexRegisterLocation(i);
+    DumpRegisterMapping(indented_os, i, location, "entry ");
+  }
+}
+
 void DexRegisterMap::Dump(std::ostream& os,
                           const CodeInfo& code_info,
                           uint16_t number_of_dex_registers) const {
   size_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
   // TODO: Display the bit mask of live Dex registers.
   for (size_t j = 0; j < number_of_dex_registers; ++j) {
     if (IsDexRegisterLive(j)) {
@@ -276,7 +301,7 @@
           j, number_of_dex_registers, number_of_location_catalog_entries);
       DexRegisterLocation location = GetDexRegisterLocation(j, number_of_dex_registers, code_info);
       DumpRegisterMapping(
-          os, j, location, "v",
+          indented_os, j, location, "v",
           "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
     }
   }
@@ -285,18 +310,20 @@
 void InlineInfo::Dump(std::ostream& os,
                       const CodeInfo& code_info,
                       uint16_t number_of_dex_registers[]) const {
-  os << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
+  indented_os << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
 
   for (size_t i = 0; i < GetDepth(); ++i) {
-    os << " At depth " << i
-       << std::hex
-       << " (dex_pc=0x" << GetDexPcAtDepth(i)
-       << ", method_index=0x" << GetMethodIndexAtDepth(i)
-       << ")\n";
+    indented_os << " At depth " << i
+                << std::hex
+                << " (dex_pc=0x" << GetDexPcAtDepth(i)
+                << ", method_index=0x" << GetMethodIndexAtDepth(i)
+                << ")\n";
     if (HasDexRegisterMapAtDepth(i)) {
       DexRegisterMap dex_register_map =
           code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]);
-      dex_register_map.Dump(os, code_info, number_of_dex_registers[i]);
+      dex_register_map.Dump(indented_os, code_info, number_of_dex_registers[i]);
     }
   }
 }
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 69e57ff..eefdaa7 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -356,6 +356,8 @@
     return region_.size();
   }
 
+  void Dump(std::ostream& os, const CodeInfo& code_info);
+
   // Special (invalid) Dex register location catalog entry index meaning
   // that there is no location for a given Dex register (i.e., it is
   // mapped to a DexRegisterLocation::Kind::kNone location).
@@ -1046,7 +1048,15 @@
     return StackMap();
   }
 
-  void Dump(std::ostream& os, uint16_t number_of_dex_registers) const;
+  // Dump this CodeInfo object on `os`.  If `dump_stack_maps` is true,
+  // also dump the stack maps and the associated Dex register maps.
+  void Dump(std::ostream& os, uint16_t number_of_dex_registers, bool dump_stack_maps) const;
+
+  // Dump stack map number `stack_map_num` as well as associated data on `os`,
+  // such as Dex register locations.
+  void DumpStackMap(std::ostream& os, size_t stack_map_num, uint16_t number_of_dex_registers) const;
+  // Dump the header of stack map number `stack_map_num` on `os`, without
+  // associated data.
   void DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const;
 
  private: