Merge "Eliminate redundant constructor barriers when inlining."
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 03165ed..e02fe4b 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -579,6 +579,8 @@
         log_verbosity.class_linker = true;
       } else if (verbose_options[j] == "compiler") {
         log_verbosity.compiler = true;
+      } else if (verbose_options[j] == "deopt") {
+        log_verbosity.deopt = true;
       } else if (verbose_options[j] == "gc") {
         log_verbosity.gc = true;
       } else if (verbose_options[j] == "heap") {
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index f7501d2..5e345db 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -30,6 +30,8 @@
 
 namespace art {
 
+constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT;
+
 class CFITest : public dwarf::DwarfTest {
  public:
   void GenerateExpected(FILE* f, InstructionSet isa, const char* isa_str,
@@ -46,11 +48,11 @@
     // Pretty-print CFI opcodes.
     constexpr bool is64bit = false;
     dwarf::DebugFrameOpCodeWriter<> initial_opcodes;
-    dwarf::WriteEhFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8),
-                           initial_opcodes, &eh_frame_data_);
-    std::vector<uintptr_t> eh_frame_patches;
-    dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
-                           &eh_frame_data_, &eh_frame_patches);
+    dwarf::WriteDebugFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8),
+                              initial_opcodes, kCFIFormat, &debug_frame_data_);
+    std::vector<uintptr_t> debug_frame_patches;
+    dwarf::WriteDebugFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
+                              kCFIFormat, &debug_frame_data_, &debug_frame_patches);
     ReformatCfi(Objdump(false, "-W"), &lines);
     // Pretty-print assembly.
     auto* opts = new DisassemblerOptions(false, actual_asm.data(), true);
diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/dwarf/dwarf_constants.h
index 61a44cd..3b570e5 100644
--- a/compiler/dwarf/dwarf_constants.h
+++ b/compiler/dwarf/dwarf_constants.h
@@ -680,6 +680,14 @@
   DW_EH_PE_aligned = 0x50,
 };
 
+enum CFIFormat : uint8_t {
+  // This is the original format as defined by the specification.
+  // It is used for the .debug_frame section.
+  DW_DEBUG_FRAME_FORMAT,
+  // Slightly modified format used for the .eh_frame section.
+  DW_EH_FRAME_FORMAT
+};
+
 }  // namespace dwarf
 }  // namespace art
 
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index edba00a..4971f0e 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -26,6 +26,8 @@
 namespace art {
 namespace dwarf {
 
+constexpr CFIFormat kCFIFormat = DW_DEBUG_FRAME_FORMAT;
+
 // Run the tests only on host since we need objdump.
 #ifndef HAVE_ANDROID_OS
 
@@ -120,30 +122,30 @@
   DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)");
 
   DebugFrameOpCodeWriter<> initial_opcodes;
-  WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8),
-                  initial_opcodes, &eh_frame_data_);
-  std::vector<uintptr_t> eh_frame_patches;
+  WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8),
+                     initial_opcodes, kCFIFormat, &debug_frame_data_);
+  std::vector<uintptr_t> debug_frame_patches;
   std::vector<uintptr_t> expected_patches { 28 };  // NOLINT
-  WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
-                  &eh_frame_data_, &eh_frame_patches);
+  WriteDebugFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
+                     kCFIFormat, &debug_frame_data_, &debug_frame_patches);
 
-  EXPECT_EQ(expected_patches, eh_frame_patches);
+  EXPECT_EQ(expected_patches, debug_frame_patches);
   CheckObjdumpOutput(is64bit, "-W");
 }
 
 TEST_F(DwarfTest, DebugFrame64) {
   constexpr bool is64bit = true;
   DebugFrameOpCodeWriter<> initial_opcodes;
-  WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
-                  initial_opcodes, &eh_frame_data_);
+  WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
+                     initial_opcodes, kCFIFormat, &debug_frame_data_);
   DebugFrameOpCodeWriter<> opcodes;
-  std::vector<uintptr_t> eh_frame_patches;
+  std::vector<uintptr_t> debug_frame_patches;
   std::vector<uintptr_t> expected_patches { 32 };  // NOLINT
-  WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
-                  opcodes.data(), &eh_frame_data_, &eh_frame_patches);
+  WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
+                     opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches);
   DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
 
-  EXPECT_EQ(expected_patches, eh_frame_patches);
+  EXPECT_EQ(expected_patches, debug_frame_patches);
   CheckObjdumpOutput(is64bit, "-W");
 }
 
@@ -173,11 +175,11 @@
   DW_CHECK_NEXT("DW_CFA_offset: r14 (r14)");
   DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)");
   DebugFrameOpCodeWriter<> initial_opcodes;
-  WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
-                  initial_opcodes, &eh_frame_data_);
-  std::vector<uintptr_t> eh_frame_patches;
-  WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
-                  opcodes.data(), &eh_frame_data_, &eh_frame_patches);
+  WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
+                     initial_opcodes, kCFIFormat, &debug_frame_data_);
+  std::vector<uintptr_t> debug_frame_patches;
+  WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
+                     opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches);
 
   CheckObjdumpOutput(is64bit, "-W");
 }
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 230ebe3..3afb5ea 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -69,7 +69,7 @@
     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);
-    RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0);
+    RawSection debug_frame(".debug_frame", SHT_PROGBITS, 0, nullptr, 0, 8, 0);
     if (!debug_info_data_.empty()) {
       debug_info.SetBuffer(debug_info_data_);
       builder.RegisterSection(&debug_info);
@@ -86,9 +86,9 @@
       debug_line.SetBuffer(debug_line_data_);
       builder.RegisterSection(&debug_line);
     }
-    if (!eh_frame_data_.empty()) {
-      eh_frame.SetBuffer(eh_frame_data_);
-      builder.RegisterSection(&eh_frame);
+    if (!debug_frame_data_.empty()) {
+      debug_frame.SetBuffer(debug_frame_data_);
+      builder.RegisterSection(&debug_frame);
     }
     ScratchFile file;
     builder.Write(file.GetFile());
@@ -167,7 +167,7 @@
   }
 
   // Buffers which are going to assembled into ELF file and passed to objdump.
-  std::vector<uint8_t> eh_frame_data_;
+  std::vector<uint8_t> debug_frame_data_;
   std::vector<uint8_t> debug_info_data_;
   std::vector<uint8_t> debug_abbrev_data_;
   std::vector<uint8_t> debug_str_data_;
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index 9f64766..ad315ee 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -35,17 +35,18 @@
 // and compilers are expected *not* to use it by default.
 // In particular, it is not related to machine architecture.
 
-// Write common information entry (CIE) to .eh_frame section.
+// Write common information entry (CIE) to .debug_frame or .eh_frame section.
 template<typename Allocator>
-void WriteEhFrameCIE(bool is64bit,
-                     ExceptionHeaderValueApplication address_type,
-                     Reg return_address_register,
-                     const DebugFrameOpCodeWriter<Allocator>& opcodes,
-                     std::vector<uint8_t>* eh_frame) {
-  Writer<> writer(eh_frame);
+void WriteDebugFrameCIE(bool is64bit,
+                        ExceptionHeaderValueApplication address_type,
+                        Reg return_address_register,
+                        const DebugFrameOpCodeWriter<Allocator>& opcodes,
+                        CFIFormat format,
+                        std::vector<uint8_t>* debug_frame) {
+  Writer<> writer(debug_frame);
   size_t cie_header_start_ = writer.data()->size();
   writer.PushUint32(0);  // Length placeholder.
-  writer.PushUint32(0);  // CIE id.
+  writer.PushUint32((format == DW_EH_FRAME_FORMAT) ? 0 : 0xFFFFFFFF);  // CIE id.
   writer.PushUint8(1);   // Version.
   writer.PushString("zR");
   writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor);
@@ -62,20 +63,26 @@
   writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
 }
 
-// Write frame description entry (FDE) to .eh_frame section.
+// Write frame description entry (FDE) to .debug_frame or .eh_frame section.
 template<typename Allocator>
-void WriteEhFrameFDE(bool is64bit, size_t cie_offset,
-                     uint64_t initial_address, uint64_t address_range,
-                     const std::vector<uint8_t, Allocator>* opcodes,
-                     std::vector<uint8_t>* eh_frame,
-                     std::vector<uintptr_t>* eh_frame_patches) {
-  Writer<> writer(eh_frame);
+void WriteDebugFrameFDE(bool is64bit, size_t cie_offset,
+                        uint64_t initial_address, uint64_t address_range,
+                        const std::vector<uint8_t, Allocator>* opcodes,
+                        CFIFormat format,
+                        std::vector<uint8_t>* debug_frame,
+                        std::vector<uintptr_t>* debug_frame_patches) {
+  Writer<> writer(debug_frame);
   size_t fde_header_start = writer.data()->size();
   writer.PushUint32(0);  // Length placeholder.
-  uint32_t cie_pointer = writer.data()->size() - cie_offset;
-  writer.PushUint32(cie_pointer);
+  if (format == DW_EH_FRAME_FORMAT) {
+    uint32_t cie_pointer = writer.data()->size() - cie_offset;
+    writer.PushUint32(cie_pointer);
+  } else {
+    uint32_t cie_pointer = cie_offset;
+    writer.PushUint32(cie_pointer);
+  }
   // Relocate initial_address, but not address_range (it is size).
-  eh_frame_patches->push_back(writer.data()->size());
+  debug_frame_patches->push_back(writer.data()->size());
   if (is64bit) {
     writer.PushUint64(initial_address);
     writer.PushUint64(address_range);
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 5e9cf76..a1aabc3 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -29,9 +29,10 @@
 namespace art {
 namespace dwarf {
 
-static void WriteEhFrameCIE(InstructionSet isa,
-                            ExceptionHeaderValueApplication addr_type,
-                            std::vector<uint8_t>* eh_frame) {
+static void WriteDebugFrameCIE(InstructionSet isa,
+                               ExceptionHeaderValueApplication addr_type,
+                               CFIFormat format,
+                               std::vector<uint8_t>* eh_frame) {
   // Scratch registers should be marked as undefined.  This tells the
   // debugger that its value in the previous frame is not recoverable.
   bool is64bit = Is64BitInstructionSet(isa);
@@ -57,7 +58,8 @@
         }
       }
       auto return_reg = Reg::ArmCore(14);  // R14(LR).
-      WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+      WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+                         opcodes, format, eh_frame);
       return;
     }
     case kArm64: {
@@ -80,7 +82,8 @@
         }
       }
       auto return_reg = Reg::Arm64Core(30);  // R30(LR).
-      WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+      WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+                         opcodes, format, eh_frame);
       return;
     }
     case kMips:
@@ -96,7 +99,8 @@
         }
       }
       auto return_reg = Reg::MipsCore(31);  // R31(RA).
-      WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+      WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+                         opcodes, format, eh_frame);
       return;
     }
     case kX86: {
@@ -122,7 +126,8 @@
         }
       }
       auto return_reg = Reg::X86Core(8);  // R8(EIP).
-      WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+      WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+                         opcodes, format, eh_frame);
       return;
     }
     case kX86_64: {
@@ -148,7 +153,8 @@
         }
       }
       auto return_reg = Reg::X86_64Core(16);  // R16(RIP).
-      WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+      WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+                         opcodes, format, eh_frame);
       return;
     }
     case kNone:
@@ -158,58 +164,61 @@
   UNREACHABLE();
 }
 
-void WriteEhFrame(const CompilerDriver* compiler,
-                  const OatWriter* oat_writer,
-                  ExceptionHeaderValueApplication address_type,
-                  std::vector<uint8_t>* eh_frame,
-                  std::vector<uintptr_t>* eh_frame_patches,
-                  std::vector<uint8_t>* eh_frame_hdr,
-                  std::vector<uintptr_t>* eh_frame_hdr_patches) {
+void WriteCFISection(const CompilerDriver* compiler,
+                     const OatWriter* oat_writer,
+                     ExceptionHeaderValueApplication address_type,
+                     CFIFormat format,
+                     std::vector<uint8_t>* debug_frame,
+                     std::vector<uintptr_t>* debug_frame_patches,
+                     std::vector<uint8_t>* eh_frame_hdr,
+                     std::vector<uintptr_t>* eh_frame_hdr_patches) {
   const auto& method_infos = oat_writer->GetMethodDebugInfo();
   const InstructionSet isa = compiler->GetInstructionSet();
 
-  // Write .eh_frame section.
+  // Write .eh_frame/.debug_frame section.
   std::map<uint32_t, size_t> address_to_fde_offset_map;
-  size_t cie_offset = eh_frame->size();
-  WriteEhFrameCIE(isa, address_type, eh_frame);
+  size_t cie_offset = debug_frame->size();
+  WriteDebugFrameCIE(isa, address_type, format, debug_frame);
   for (const OatWriter::DebugInfo& mi : method_infos) {
     if (!mi.deduped_) {  // Only one FDE per unique address.
       const SwapVector<uint8_t>* opcodes = mi.compiled_method_->GetCFIInfo();
       if (opcodes != nullptr) {
-        address_to_fde_offset_map.emplace(mi.low_pc_, eh_frame->size());
-        WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset,
-                        mi.low_pc_, mi.high_pc_ - mi.low_pc_,
-                        opcodes, eh_frame, eh_frame_patches);
+        address_to_fde_offset_map.emplace(mi.low_pc_, debug_frame->size());
+        WriteDebugFrameFDE(Is64BitInstructionSet(isa), cie_offset,
+                           mi.low_pc_, mi.high_pc_ - mi.low_pc_,
+                           opcodes, format, debug_frame, debug_frame_patches);
       }
     }
   }
 
-  // Write .eh_frame_hdr section.
-  Writer<> header(eh_frame_hdr);
-  header.PushUint8(1);  // Version.
-  // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
-  // so we have to use pcrel which means relative to the pointer's location.
-  header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
-  // Encoding of binary search table size.
-  header.PushUint8(DW_EH_PE_udata4);
-  // Encoding of binary search table addresses - libunwind supports only this
-  // specific combination, which means relative to the start of .eh_frame_hdr.
-  header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4);
-  // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section
-  const int32_t relative_eh_frame_begin = -static_cast<int32_t>(eh_frame->size());
-  header.PushInt32(relative_eh_frame_begin - 4U);
-  // Binary search table size (number of entries).
-  header.PushUint32(dchecked_integral_cast<uint32_t>(address_to_fde_offset_map.size()));
-  // Binary search table.
-  for (const auto& address_to_fde_offset : address_to_fde_offset_map) {
-    u_int32_t code_address = address_to_fde_offset.first;
-    int32_t fde_address = dchecked_integral_cast<int32_t>(address_to_fde_offset.second);
-    eh_frame_hdr_patches->push_back(header.data()->size());
-    header.PushUint32(code_address);
-    // We know the exact layout (eh_frame is immediately before eh_frame_hdr)
-    // and the data is relative to the start of the eh_frame_hdr,
-    // so patching isn't necessary (in contrast to the code address above).
-    header.PushInt32(relative_eh_frame_begin + fde_address);
+  if (format == DW_EH_FRAME_FORMAT) {
+    // Write .eh_frame_hdr section.
+    Writer<> header(eh_frame_hdr);
+    header.PushUint8(1);  // Version.
+    // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
+    // so we have to use pcrel which means relative to the pointer's location.
+    header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+    // Encoding of binary search table size.
+    header.PushUint8(DW_EH_PE_udata4);
+    // Encoding of binary search table addresses - libunwind supports only this
+    // specific combination, which means relative to the start of .eh_frame_hdr.
+    header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4);
+    // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section
+    const int32_t relative_eh_frame_begin = -static_cast<int32_t>(debug_frame->size());
+    header.PushInt32(relative_eh_frame_begin - 4U);
+    // Binary search table size (number of entries).
+    header.PushUint32(dchecked_integral_cast<uint32_t>(address_to_fde_offset_map.size()));
+    // Binary search table.
+    for (const auto& address_to_fde_offset : address_to_fde_offset_map) {
+      u_int32_t code_address = address_to_fde_offset.first;
+      int32_t fde_address = dchecked_integral_cast<int32_t>(address_to_fde_offset.second);
+      eh_frame_hdr_patches->push_back(header.data()->size());
+      header.PushUint32(code_address);
+      // We know the exact layout (eh_frame is immediately before eh_frame_hdr)
+      // and the data is relative to the start of the eh_frame_hdr,
+      // so patching isn't necessary (in contrast to the code address above).
+      header.PushInt32(relative_eh_frame_begin + fde_address);
+    }
   }
 }
 
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index 28d0e2c..69f7e0d 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -25,13 +25,14 @@
 namespace art {
 namespace dwarf {
 
-void WriteEhFrame(const CompilerDriver* compiler,
-                  const OatWriter* oat_writer,
-                  ExceptionHeaderValueApplication address_type,
-                  std::vector<uint8_t>* eh_frame,
-                  std::vector<uintptr_t>* eh_frame_patches,
-                  std::vector<uint8_t>* eh_frame_hdr,
-                  std::vector<uintptr_t>* eh_frame_hdr_patches);
+void WriteCFISection(const CompilerDriver* compiler,
+                     const OatWriter* oat_writer,
+                     ExceptionHeaderValueApplication address_type,
+                     CFIFormat format,
+                     std::vector<uint8_t>* debug_frame,
+                     std::vector<uintptr_t>* debug_frame_patches,
+                     std::vector<uint8_t>* eh_frame_hdr,
+                     std::vector<uintptr_t>* eh_frame_hdr_patches);
 
 void WriteDebugSections(const CompilerDriver* compiler,
                         const OatWriter* oat_writer,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 79f9955..96dd7ca 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -37,6 +37,14 @@
 
 namespace art {
 
+// .eh_frame and .debug_frame are almost identical.
+// Except for some minor formatting differences, the main difference
+// is that .eh_frame is allocated within the running program because
+// it is used by C++ exception handling (which we do not use so we
+// can choose either).  C++ compilers generally tend to use .eh_frame
+// because if they need it sometimes, they might as well always use it.
+constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_EH_FRAME_FORMAT;
+
 template <typename ElfTypes>
 bool ElfWriterQuick<ElfTypes>::Create(File* elf_file,
                                       OatWriter* oat_writer,
@@ -161,12 +169,17 @@
   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);
@@ -175,12 +188,25 @@
                         Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
   if (!oat_writer->GetMethodDebugInfo().empty()) {
     if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
-      dwarf::WriteEhFrame(
-          compiler_driver_, oat_writer, dwarf::DW_EH_PE_pcrel,
-          eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
-          eh_frame_hdr.GetBuffer(), eh_frame_hdr.GetPatchLocations());
-      builder->RegisterSection(&eh_frame);
-      builder->RegisterSection(&eh_frame_hdr);
+      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);
+      } 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(),
+            nullptr, nullptr);
+        builder->RegisterSection(&debug_frame);
+        *oat_writer->GetAbsolutePatchLocationsFor(".debug_frame") =
+            *debug_frame.GetPatchLocations();
+      }
     }
     if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
       // Add methods to .symtab.
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 672e55e..7b37f74 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -3037,7 +3037,8 @@
 }
 
 void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
-                                                 const FieldInfo& field_info) {
+                                                 const FieldInfo& field_info,
+                                                 bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
 
   LocationSummary* locations = instruction->GetLocations();
@@ -3126,7 +3127,8 @@
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     Register card = locations->GetTemp(1).AsRegister<Register>();
-    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+    codegen_->MarkGCCard(
+        temp, card, base, value.AsRegister<Register>(), value_can_be_null);
   }
 
   if (is_volatile) {
@@ -3253,7 +3255,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3277,7 +3279,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3547,7 +3549,7 @@
           DCHECK_EQ(value_type, Primitive::kPrimNot);
           Register temp = locations->GetTemp(0).AsRegister<Register>();
           Register card = locations->GetTemp(1).AsRegister<Register>();
-          codegen_->MarkGCCard(temp, card, obj, value);
+          codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
         }
       } else {
         DCHECK_EQ(value_type, Primitive::kPrimNot);
@@ -3652,13 +3654,21 @@
   __ b(slow_path->GetEntryLabel(), CS);
 }
 
-void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
+void CodeGeneratorARM::MarkGCCard(Register temp,
+                                  Register card,
+                                  Register object,
+                                  Register value,
+                                  bool can_be_null) {
   Label is_null;
-  __ CompareAndBranchIfZero(value, &is_null);
+  if (can_be_null) {
+    __ CompareAndBranchIfZero(value, &is_null);
+  }
   __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
   __ strb(card, Address(card, temp));
-  __ Bind(&is_null);
+  if (can_be_null) {
+    __ Bind(&is_null);
+  }
 }
 
 void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 2edbcf8..071bbee 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -181,7 +181,9 @@
                                HInstruction* instruction);
   void GenerateWideAtomicLoad(Register addr, uint32_t offset,
                               Register out_lo, Register out_hi);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   void GenerateImplicitNullCheck(HNullCheck* instruction);
   void GenerateExplicitNullCheck(HNullCheck* instruction);
@@ -274,7 +276,7 @@
       int32_t offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path);
 
   // Emit a write barrier.
-  void MarkGCCard(Register temp, Register card, Register object, Register value);
+  void MarkGCCard(Register temp, Register card, Register object, Register value, bool can_be_null);
 
   Label* GetLabelOf(HBasicBlock* block) const {
     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 34720e2..b6d99ab 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -701,16 +701,20 @@
   return Location::NoLocation();
 }
 
-void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
+void CodeGeneratorARM64::MarkGCCard(Register object, Register value, bool value_can_be_null) {
   UseScratchRegisterScope temps(GetVIXLAssembler());
   Register card = temps.AcquireX();
   Register temp = temps.AcquireW();   // Index within the CardTable - 32bit.
   vixl::Label done;
-  __ Cbz(value, &done);
+  if (value_can_be_null) {
+    __ Cbz(value, &done);
+  }
   __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
   __ Strb(card, MemOperand(card, temp.X()));
-  __ Bind(&done);
+  if (value_can_be_null) {
+    __ Bind(&done);
+  }
 }
 
 void CodeGeneratorARM64::SetupBlockedRegisters(bool is_baseline) const {
@@ -1265,7 +1269,8 @@
 }
 
 void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
-                                                   const FieldInfo& field_info) {
+                                                   const FieldInfo& field_info,
+                                                   bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   BlockPoolsScope block_pools(GetVIXLAssembler());
 
@@ -1291,7 +1296,7 @@
   }
 
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
-    codegen_->MarkGCCard(obj, Register(value));
+    codegen_->MarkGCCard(obj, Register(value), value_can_be_null);
   }
 }
 
@@ -1517,7 +1522,7 @@
       codegen_->MaybeRecordImplicitNullCheck(instruction);
     }
     if (CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue())) {
-      codegen_->MarkGCCard(obj, value.W());
+      codegen_->MarkGCCard(obj, value.W(), instruction->GetValueCanBeNull());
     }
   }
 }
@@ -2089,7 +2094,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
@@ -2832,7 +2837,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 702bcd4..b56ca10 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -157,7 +157,9 @@
   void GenerateMemoryBarrier(MemBarrierKind kind);
   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
   void HandleBinaryOp(HBinaryOperation* instr);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   void HandleShift(HBinaryOperation* instr);
   void GenerateImplicitNullCheck(HNullCheck* instruction);
@@ -267,7 +269,7 @@
   vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
 
   // Emit a write barrier.
-  void MarkGCCard(vixl::Register object, vixl::Register value);
+  void MarkGCCard(vixl::Register object, vixl::Register value, bool value_can_be_null);
 
   // Register allocation.
 
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 0212da1..a6f01da 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -3227,16 +3227,24 @@
   DCHECK(!IsLeafMethod());
 }
 
-void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
+void CodeGeneratorX86::MarkGCCard(Register temp,
+                                  Register card,
+                                  Register object,
+                                  Register value,
+                                  bool value_can_be_null) {
   Label is_null;
-  __ testl(value, value);
-  __ j(kEqual, &is_null);
+  if (value_can_be_null) {
+    __ testl(value, value);
+    __ j(kEqual, &is_null);
+  }
   __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
   __ movl(temp, object);
   __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
   __ movb(Address(temp, card, TIMES_1, 0),
           X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
-  __ Bind(&is_null);
+  if (value_can_be_null) {
+    __ Bind(&is_null);
+  }
 }
 
 void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
@@ -3381,7 +3389,8 @@
 }
 
 void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
-                                                 const FieldInfo& field_info) {
+                                                 const FieldInfo& field_info,
+                                                 bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
 
   LocationSummary* locations = instruction->GetLocations();
@@ -3454,7 +3463,7 @@
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     Register card = locations->GetTemp(1).AsRegister<Register>();
-    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
   }
 
   if (is_volatile) {
@@ -3475,7 +3484,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -3483,7 +3492,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3817,7 +3826,8 @@
         if (needs_write_barrier) {
           Register temp = locations->GetTemp(0).AsRegister<Register>();
           Register card = locations->GetTemp(1).AsRegister<Register>();
-          codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
+          codegen_->MarkGCCard(
+              temp, card, obj, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
         }
       } else {
         DCHECK_EQ(value_type, Primitive::kPrimNot);
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 5a5a37b..28766d8 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -170,7 +170,9 @@
   void GenerateShrLong(const Location& loc, int shift);
   void GenerateUShrLong(const Location& loc, int shift);
   void GenerateMemoryBarrier(MemBarrierKind kind);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not.
   // `is_wide` specifies whether it is long/double or not.
@@ -260,7 +262,11 @@
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp);
 
   // Emit a write barrier.
-  void MarkGCCard(Register temp, Register card, Register object, Register value);
+  void MarkGCCard(Register temp,
+                  Register card,
+                  Register object,
+                  Register value,
+                  bool value_can_be_null);
 
   void LoadCurrentMethod(Register reg);
 
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 63d6846..f49c26d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -3249,7 +3249,8 @@
 }
 
 void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
-                                                    const FieldInfo& field_info) {
+                                                    const FieldInfo& field_info,
+                                                    bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
 
   LocationSummary* locations = instruction->GetLocations();
@@ -3329,7 +3330,7 @@
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
     CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
-    codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
   }
 
   if (is_volatile) {
@@ -3342,7 +3343,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3366,7 +3367,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
@@ -3671,7 +3672,8 @@
           DCHECK_EQ(value_type, Primitive::kPrimNot);
           CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
           CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
-          codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
+          codegen_->MarkGCCard(
+              temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
         }
       } else {
         DCHECK_EQ(value_type, Primitive::kPrimNot);
@@ -3816,16 +3818,21 @@
 void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
                                      CpuRegister card,
                                      CpuRegister object,
-                                     CpuRegister value) {
+                                     CpuRegister value,
+                                     bool value_can_be_null) {
   Label is_null;
-  __ testl(value, value);
-  __ j(kEqual, &is_null);
+  if (value_can_be_null) {
+    __ testl(value, value);
+    __ j(kEqual, &is_null);
+  }
   __ gs()->movq(card, Address::Absolute(
       Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
   __ movq(temp, object);
   __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
   __ movb(Address(temp, card, TIMES_1, 0),  card);
-  __ Bind(&is_null);
+  if (value_can_be_null) {
+    __ Bind(&is_null);
+  }
 }
 
 void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 480ea6b..d7bd525 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -174,7 +174,9 @@
   void GenerateDivRemIntegral(HBinaryOperation* instruction);
   void HandleShift(HBinaryOperation* operation);
   void GenerateMemoryBarrier(MemBarrierKind kind);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   void GenerateImplicitNullCheck(HNullCheck* instruction);
   void GenerateExplicitNullCheck(HNullCheck* instruction);
@@ -248,7 +250,11 @@
   }
 
   // Emit a write barrier.
-  void MarkGCCard(CpuRegister temp, CpuRegister card, CpuRegister object, CpuRegister value);
+  void MarkGCCard(CpuRegister temp,
+                  CpuRegister card,
+                  CpuRegister object,
+                  CpuRegister value,
+                  bool value_can_be_null);
 
   // Helper method to move a value between two locations.
   void Move(Location destination, Location source);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 46fad17..0adb931 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -45,6 +45,8 @@
   void VisitEqual(HEqual* equal) OVERRIDE;
   void VisitNotEqual(HNotEqual* equal) OVERRIDE;
   void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE;
+  void VisitInstanceFieldSet(HInstanceFieldSet* equal) OVERRIDE;
+  void VisitStaticFieldSet(HStaticFieldSet* equal) OVERRIDE;
   void VisitArraySet(HArraySet* equal) OVERRIDE;
   void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
   void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
@@ -78,6 +80,8 @@
 }
 
 void InstructionSimplifierVisitor::Run() {
+  // Iterate in reverse post order to open up more simplifications to users
+  // of instructions that got simplified.
   for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
     // The simplification of an instruction to another instruction may yield
     // possibilities for other simplifications. So although we perform a reverse
@@ -199,6 +203,20 @@
   }
 }
 
+void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+      && !instruction->GetValue()->CanBeNull()) {
+    instruction->ClearValueCanBeNull();
+  }
+}
+
+void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+      && !instruction->GetValue()->CanBeNull()) {
+    instruction->ClearValueCanBeNull();
+  }
+}
+
 void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
   HBasicBlock* block = check->GetBlock();
   // Currently always keep the suspend check at entry.
@@ -294,6 +312,10 @@
       instruction->ClearNeedsTypeCheck();
     }
   }
+
+  if (!value->CanBeNull()) {
+    instruction->ClearValueCanBeNull();
+  }
 }
 
 void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index dccfe9a..e785bf9 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -657,7 +657,8 @@
   if (type == Primitive::kPrimNot) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     Register card = locations->GetTemp(1).AsRegister<Register>();
-    codegen->MarkGCCard(temp, card, base, value);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(temp, card, base, value, value_can_be_null);
   }
 }
 
@@ -725,7 +726,8 @@
   if (type == Primitive::kPrimNot) {
     // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
     // object and scan the receiver at the next GC for nothing.
-    codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null);
   }
 
   // Prevent reordering with prior memory operations.
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 2c4fab0..53497b6 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -797,7 +797,8 @@
   }
 
   if (type == Primitive::kPrimNot) {
-    codegen->MarkGCCard(base, value);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(base, value, value_can_be_null);
   }
 }
 
@@ -856,7 +857,8 @@
   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
   if (type == Primitive::kPrimNot) {
     // Mark card for object assuming new value is stored.
-    codegen->MarkGCCard(base, value);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(base, value, value_can_be_null);
   }
 
   UseScratchRegisterScope temps(masm);
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 28b7a07..d2ca42d 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1503,10 +1503,12 @@
   }
 
   if (type == Primitive::kPrimNot) {
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
                         locations->GetTemp(1).AsRegister<Register>(),
                         base,
-                        value_loc.AsRegister<Register>());
+                        value_loc.AsRegister<Register>(),
+                        value_can_be_null);
   }
 }
 
@@ -1602,10 +1604,12 @@
     Register value = locations->InAt(4).AsRegister<Register>();
     if (type == Primitive::kPrimNot) {
       // Mark card for object assuming new value is stored.
+      bool value_can_be_null = true;  // TODO: Worth finding out this information?
       codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
                           locations->GetTemp(1).AsRegister<Register>(),
                           base,
-                          value);
+                          value,
+                          value_can_be_null);
     }
 
     __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 0efa714..2ccecfe 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1374,10 +1374,12 @@
   }
 
   if (type == Primitive::kPrimNot) {
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
                         locations->GetTemp(1).AsRegister<CpuRegister>(),
                         base,
-                        value);
+                        value,
+                        value_can_be_null);
   }
 }
 
@@ -1459,10 +1461,12 @@
     // Integer or object.
     if (type == Primitive::kPrimNot) {
       // Mark card for object assuming new value is stored.
+      bool value_can_be_null = true;  // TODO: Worth finding out this information?
       codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
                           locations->GetTemp(1).AsRegister<CpuRegister>(),
                           base,
-                          value);
+                          value,
+                          value_can_be_null);
     }
 
     __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 0291992..2850368 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3173,7 +3173,8 @@
                     MemberOffset field_offset,
                     bool is_volatile)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
-        field_info_(field_offset, field_type, is_volatile) {
+        field_info_(field_offset, field_type, is_volatile),
+        value_can_be_null_(true) {
     SetRawInputAt(0, object);
     SetRawInputAt(1, value);
   }
@@ -3187,11 +3188,14 @@
   Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
   bool IsVolatile() const { return field_info_.IsVolatile(); }
   HInstruction* GetValue() const { return InputAt(1); }
+  bool GetValueCanBeNull() const { return value_can_be_null_; }
+  void ClearValueCanBeNull() { value_can_be_null_ = false; }
 
   DECLARE_INSTRUCTION(InstanceFieldSet);
 
  private:
   const FieldInfo field_info_;
+  bool value_can_be_null_;
 
   DISALLOW_COPY_AND_ASSIGN(HInstanceFieldSet);
 };
@@ -3240,7 +3244,8 @@
       : HTemplateInstruction(SideEffects::ChangesSomething()),
         dex_pc_(dex_pc),
         expected_component_type_(expected_component_type),
-        needs_type_check_(value->GetType() == Primitive::kPrimNot) {
+        needs_type_check_(value->GetType() == Primitive::kPrimNot),
+        value_can_be_null_(true) {
     SetRawInputAt(0, array);
     SetRawInputAt(1, index);
     SetRawInputAt(2, value);
@@ -3262,6 +3267,11 @@
     needs_type_check_ = false;
   }
 
+  void ClearValueCanBeNull() {
+    value_can_be_null_ = false;
+  }
+
+  bool GetValueCanBeNull() const { return value_can_be_null_; }
   bool NeedsTypeCheck() const { return needs_type_check_; }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
@@ -3287,6 +3297,7 @@
   const uint32_t dex_pc_;
   const Primitive::Type expected_component_type_;
   bool needs_type_check_;
+  bool value_can_be_null_;
 
   DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
@@ -3587,7 +3598,8 @@
                   MemberOffset field_offset,
                   bool is_volatile)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
-        field_info_(field_offset, field_type, is_volatile) {
+        field_info_(field_offset, field_type, is_volatile),
+        value_can_be_null_(true) {
     SetRawInputAt(0, cls);
     SetRawInputAt(1, value);
   }
@@ -3598,11 +3610,14 @@
   bool IsVolatile() const { return field_info_.IsVolatile(); }
 
   HInstruction* GetValue() const { return InputAt(1); }
+  bool GetValueCanBeNull() const { return value_can_be_null_; }
+  void ClearValueCanBeNull() { value_can_be_null_ = false; }
 
   DECLARE_INSTRUCTION(StaticFieldSet);
 
  private:
   const FieldInfo field_info_;
+  bool value_can_be_null_;
 
   DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
 };
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b4a45c6..3cf458a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -979,7 +979,10 @@
       oss.str("");  // Reset.
       oss << kRuntimeISA;
       key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
-      key_value_store_->Put(OatHeader::kPicKey, compile_pic ? "true" : "false");
+      key_value_store_->Put(OatHeader::kPicKey,
+                            compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue);
+      key_value_store_->Put(OatHeader::kDebuggableKey,
+                            debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue);
     }
   }
 
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 8b34374..35b50d1 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -39,6 +39,7 @@
 struct LogVerbosity {
   bool class_linker;  // Enabled with "-verbose:class".
   bool compiler;
+  bool deopt;
   bool gc;
   bool heap;
   bool jdwp;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b099088..292f830 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -819,6 +819,34 @@
   }
 }
 
+const OatFile* ClassLinker::GetBootOatFile() {
+  // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as
+  // they were all compiled into the same oat file. So grab the first one, which is guaranteed to
+  // exist if the boot class-path isn't empty.
+  if (boot_class_path_.empty()) {
+    return nullptr;
+  }
+  const DexFile* boot_dex_file = boot_class_path_[0];
+  // Is it from an oat file?
+  if (boot_dex_file->GetOatDexFile() != nullptr) {
+    return boot_dex_file->GetOatDexFile()->GetOatFile();
+  }
+  return nullptr;
+}
+
+const OatFile* ClassLinker::GetPrimaryOatFile() {
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
+  const OatFile* boot_oat_file = GetBootOatFile();
+  if (boot_oat_file != nullptr) {
+    for (const OatFile* oat_file : oat_files_) {
+      if (oat_file != boot_oat_file) {
+        return oat_file;
+      }
+    }
+  }
+  return nullptr;
+}
+
 // Check for class-def collisions in dex files.
 //
 // This works by maintaining a heap with one class from each dex file, sorted by the class
@@ -835,18 +863,7 @@
 
   // Add dex files from already loaded oat files, but skip boot.
   {
-    // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as
-    // they were all compiled into the same oat file. So grab the first one, which is guaranteed to
-    // exist if the boot class-path isn't empty.
-    const OatFile* boot_oat = nullptr;
-    if (!boot_class_path_.empty()) {
-      const DexFile* boot_dex_file = boot_class_path_[0];
-      // Is it from an oat file?
-      if (boot_dex_file->GetOatDexFile() != nullptr) {
-        boot_oat = boot_dex_file->GetOatDexFile()->GetOatFile();
-      }
-    }
-
+    const OatFile* boot_oat = GetBootOatFile();
     for (const OatFile* loaded_oat_file : oat_files_) {
       if (loaded_oat_file == boot_oat) {
         continue;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 57989b2..95c8aa0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -295,6 +295,10 @@
     return boot_class_path_;
   }
 
+  // Returns the first non-image oat file in the class path.
+  const OatFile* GetPrimaryOatFile()
+      LOCKS_EXCLUDED(dex_lock_);
+
   void VisitClasses(ClassVisitor* visitor, void* arg)
       LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -615,6 +619,9 @@
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
       LOCKS_EXCLUDED(dex_lock_);
 
+  // Returns the boot image oat file.
+  const OatFile* GetBootOatFile() SHARED_LOCKS_REQUIRED(dex_lock_);
+
   mirror::ArtMethod* CreateProxyConstructor(Thread* self, Handle<mirror::Class> klass,
                                             mirror::Class* proxy_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 0c5210d..b1d933d 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1402,25 +1402,23 @@
 
 template <typename ElfTypes>
 bool ElfFileImpl<ElfTypes>::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) {
-  const Elf_Shdr* debug_info = FindSectionByName(".debug_info");
-  const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
-  const Elf_Shdr* debug_str = FindSectionByName(".debug_str");
-  const Elf_Shdr* strtab_sec = FindSectionByName(".strtab");
-  const Elf_Shdr* symtab_sec = FindSectionByName(".symtab");
-
-  if (debug_info == nullptr || debug_abbrev == nullptr ||
-      debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
-    // Release version of ART does not generate debug info.
-    return true;
-  }
   if (base_address_delta == 0) {
     return true;
   }
-  if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) {
-    return false;
+  if (FindSectionByName(".debug_frame") != nullptr) {
+    if (!ApplyOatPatchesTo(".debug_frame", base_address_delta)) {
+      return false;
+    }
   }
-  if (!ApplyOatPatchesTo(".debug_line", 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;
 }
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 6a8aaf2..1b1ef66 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "base/logging.h"
 #include "callee_save_frame.h"
 #include "dex_file-inl.h"
 #include "interpreter/interpreter.h"
@@ -29,6 +30,12 @@
 
 extern "C" NO_RETURN void artDeoptimize(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
+
+  if (VLOG_IS_ON(deopt)) {
+    LOG(INFO) << "Deopting:";
+    self->Dump(LOG(INFO));
+  }
+
   self->SetException(Thread::GetDeoptimizationException());
   self->QuickDeliverException();
 }
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 53e56da..5401b56 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -373,8 +373,7 @@
       : mark_sweep_(mark_sweep), holder_(holder), offset_(offset) {
   }
 
-  void operator()(const Object* obj) const ALWAYS_INLINE
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  void operator()(const Object* obj) const ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS {
     if (kProfileLargeObjects) {
       // TODO: Differentiate between marking and testing somehow.
       ++mark_sweep_->large_object_test_;
@@ -385,17 +384,51 @@
                  (kIsDebugBuild && large_object_space != nullptr &&
                      !large_object_space->Contains(obj)))) {
       LOG(INTERNAL_FATAL) << "Tried to mark " << obj << " not contained by any spaces";
-      LOG(INTERNAL_FATAL) << "Attempting see if it's a bad root";
-      mark_sweep_->VerifyRoots();
       if (holder_ != nullptr) {
+        size_t holder_size = holder_->SizeOf();
         ArtField* field = holder_->FindFieldByOffset(offset_);
-        LOG(INTERNAL_FATAL) << "Field info: holder=" << holder_
+        LOG(INTERNAL_FATAL) << "Field info: "
+                            << " holder=" << holder_
+                            << " holder_size=" << holder_size
                             << " holder_type=" << PrettyTypeOf(holder_)
                             << " offset=" << offset_.Uint32Value()
-                            << " field=" << (field != nullptr ? field->GetName() : "nullptr");
+                            << " field=" << (field != nullptr ? field->GetName() : "nullptr")
+                            << " field_type="
+                            << (field != nullptr ? field->GetTypeDescriptor() : "")
+                            << " first_ref_field_offset="
+                            << (holder_->IsClass()
+                                ? holder_->AsClass()->GetFirstReferenceStaticFieldOffset()
+                                : holder_->GetClass()->GetFirstReferenceInstanceFieldOffset())
+                            << " num_of_ref_fields="
+                            << (holder_->IsClass()
+                                ? holder_->AsClass()->NumReferenceStaticFields()
+                                : holder_->GetClass()->NumReferenceInstanceFields())
+                            << "\n";
       }
       PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
       MemMap::DumpMaps(LOG(INTERNAL_FATAL), true);
+      {
+        LOG(INTERNAL_FATAL) << "Attempting see if it's a bad root";
+        Thread* self = Thread::Current();
+        if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
+          mark_sweep_->VerifyRoots();
+        } else {
+          const bool heap_bitmap_exclusive_locked =
+              Locks::heap_bitmap_lock_->IsExclusiveHeld(self);
+          if (heap_bitmap_exclusive_locked) {
+            Locks::heap_bitmap_lock_->ExclusiveUnlock(self);
+          }
+          Locks::mutator_lock_->SharedUnlock(self);
+          ThreadList* tl = Runtime::Current()->GetThreadList();
+          tl->SuspendAll(__FUNCTION__);
+          mark_sweep_->VerifyRoots();
+          tl->ResumeAll();
+          Locks::mutator_lock_->SharedLock(self);
+          if (heap_bitmap_exclusive_locked) {
+            Locks::heap_bitmap_lock_->ExclusiveLock(self);
+          }
+        }
+      }
       LOG(FATAL) << "Can't mark invalid object";
     }
   }
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index f350038..99f5d45 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -203,6 +203,9 @@
   oat_file_option_string += ImageHeader::GetOatLocationFromImageLocation(image_filename);
   arg_vector.push_back(oat_file_option_string);
 
+  // Note: we do not generate a fully debuggable boot image so we do not pass the
+  // compiler flag --debuggable here.
+
   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
   CHECK_EQ(image_isa, kRuntimeISA)
       << "We should always be generating an image for the current isa.";
diff --git a/runtime/oat.cc b/runtime/oat.cc
index c223e2e..4f6aabc 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -27,6 +27,8 @@
 
 constexpr uint8_t OatHeader::kOatMagic[4];
 constexpr uint8_t OatHeader::kOatVersion[4];
+constexpr const char OatHeader::kTrueValue[];
+constexpr const char OatHeader::kFalseValue[];
 
 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
   size_t estimate = 0U;
@@ -443,9 +445,16 @@
 }
 
 bool OatHeader::IsPic() const {
-  const char* pic_string = GetStoreValueByKey(OatHeader::kPicKey);
-  static const char kTrue[] = "true";
-  return (pic_string != nullptr && strncmp(pic_string, kTrue, sizeof(kTrue)) == 0);
+  return IsKeyEnabled(OatHeader::kPicKey);
+}
+
+bool OatHeader::IsDebuggable() const {
+  return IsKeyEnabled(OatHeader::kDebuggableKey);
+}
+
+bool OatHeader::IsKeyEnabled(const char* key) const {
+  const char* key_value = GetStoreValueByKey(key);
+  return (key_value != nullptr && strncmp(key_value, kTrueValue, sizeof(kTrueValue)) == 0);
 }
 
 void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
diff --git a/runtime/oat.h b/runtime/oat.h
index aaf442a..604e161 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,14 +32,18 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '6', '2', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '6', '3', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
   static constexpr const char* kDex2OatHostKey = "dex2oat-host";
   static constexpr const char* kPicKey = "pic";
+  static constexpr const char* kDebuggableKey = "debuggable";
   static constexpr const char* kClassPathKey = "classpath";
 
+  static constexpr const char kTrueValue[] = "true";
+  static constexpr const char kFalseValue[] = "false";
+
   static OatHeader* Create(InstructionSet instruction_set,
                            const InstructionSetFeatures* instruction_set_features,
                            const std::vector<const DexFile*>* dex_files,
@@ -99,6 +103,7 @@
 
   size_t GetHeaderSize() const;
   bool IsPic() const;
+  bool IsDebuggable() const;
 
  private:
   OatHeader(InstructionSet instruction_set,
@@ -108,6 +113,9 @@
             uint32_t image_file_location_oat_data_begin,
             const SafeMap<std::string, std::string>* variable_data);
 
+  // Returns true if the value of the given key is "true", false otherwise.
+  bool IsKeyEnabled(const char* key) const;
+
   void Flatten(const SafeMap<std::string, std::string>* variable_data);
 
   uint8_t magic_[4];
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index b0cbd0e..63ee4b1 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -703,6 +703,10 @@
   // TODO: Check against oat_patches. b/18144996
 }
 
+bool OatFile::IsDebuggable() const {
+  return GetOatHeader().IsDebuggable();
+}
+
 static constexpr char kDexClassPathEncodingSeparator = '*';
 
 std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index b32dd22..12e9f6c 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -81,6 +81,9 @@
 
   bool IsPic() const;
 
+  // Indicates whether the oat file was compiled with full debugging capability.
+  bool IsDebuggable() const;
+
   ElfFile* GetElfFile() const {
     CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
         << "Cannot get an elf file from " << GetLocation();
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index d07c09c..d0bfe6e 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -690,12 +690,20 @@
     return false;
   }
 
+  ClassLinker* linker = runtime->GetClassLinker();
+  CHECK(linker != nullptr) << "ClassLinker is not created yet";
+  const OatFile* primary_oat_file = linker->GetPrimaryOatFile();
+  const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable();
+
   std::vector<std::string> argv;
   argv.push_back(runtime->GetCompilerExecutable());
   argv.push_back("--runtime-arg");
   argv.push_back("-classpath");
   argv.push_back("--runtime-arg");
   argv.push_back(runtime->GetClassPathString());
+  if (debuggable) {
+    argv.push_back("--debuggable");
+  }
   runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
 
   if (!runtime->IsVerificationEnabled()) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2633898..2618661 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1678,10 +1678,6 @@
   std::string feature_string("--instruction-set-features=");
   feature_string += features->GetFeatureString();
   argv->push_back(feature_string);
-
-  if (Dbg::IsJdwpConfigured()) {
-    argv->push_back("--debuggable");
-  }
 }
 
 void Runtime::UpdateProfilerState(int state) {
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 8b504c1..922334e 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -62,7 +62,7 @@
 RUNTIME_OPTIONS_KEY (Unit,                DumpJITInfoOnShutdown)
 RUNTIME_OPTIONS_KEY (Unit,                IgnoreMaxFootprint)
 RUNTIME_OPTIONS_KEY (Unit,                LowMemoryMode)
-RUNTIME_OPTIONS_KEY (bool,                UseTLAB,                        kUseTlab)
+RUNTIME_OPTIONS_KEY (bool,                UseTLAB,                        (kUseTlab || kUseReadBarrier))
 RUNTIME_OPTIONS_KEY (bool,                EnableHSpaceCompactForOOM,      true)
 RUNTIME_OPTIONS_KEY (bool,                UseJIT,      false)
 RUNTIME_OPTIONS_KEY (unsigned int,        JITCompileThreshold, jit::Jit::kDefaultCompileThreshold)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 475fe8b..1b1bc54 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -286,6 +286,13 @@
   }
 }
 
+static bool IsLargeMethod(const DexFile::CodeItem* const code_item) {
+  uint16_t registers_size = code_item->registers_size_;
+  uint32_t insns_size = code_item->insns_size_in_code_units_;
+
+  return registers_size * insns_size > 4*1024*1024;
+}
+
 MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t method_idx,
                                                          const DexFile* dex_file,
                                                          Handle<mirror::DexCache> dex_cache,
@@ -329,7 +336,8 @@
     uint64_t duration_ns = NanoTime() - start_ns;
     if (duration_ns > MsToNs(100)) {
       LOG(WARNING) << "Verification of " << PrettyMethod(method_idx, *dex_file)
-                   << " took " << PrettyDuration(duration_ns);
+                   << " took " << PrettyDuration(duration_ns)
+                   << (IsLargeMethod(code_item) ? " (large method)" : "");
     }
   }
   return result;
@@ -1211,10 +1219,6 @@
   uint16_t registers_size = code_item_->registers_size_;
   uint32_t insns_size = code_item_->insns_size_in_code_units_;
 
-  if (registers_size * insns_size > 4*1024*1024) {
-    LOG(WARNING) << "warning: method is huge (regs=" << registers_size
-                 << " insns_size=" << insns_size << ")";
-  }
   /* Create and initialize table holding register status */
   reg_table_.Init(kTrackCompilerInterestPoints,
                   insn_flags_.get(),
diff --git a/test/462-checker-inlining-across-dex-files/src/Main.java b/test/462-checker-inlining-across-dex-files/src/Main.java
index 3d583b4..218c7ce 100644
--- a/test/462-checker-inlining-across-dex-files/src/Main.java
+++ b/test/462-checker-inlining-across-dex-files/src/Main.java
@@ -120,7 +120,8 @@
   // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
   // CHECK-DAG:                     Return [<<Class:l\d+>>]
   // CHECK-DAG:     <<Class>>       LoadClass
-  // Note: Verify backwards because there are two LoadClass instructions
+  // Note: There are two LoadClass instructions. We obtain the correct
+  //       instruction id by matching the Return's input list first.
 
   public static Class inlineMainClass() {
     return OtherDex.returnMainClass();
@@ -148,7 +149,8 @@
   // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
   // CHECK-DAG:                     Return [<<Class:l\d+>>]
   // CHECK-DAG:     <<Class>>       LoadClass
-  // Note: Verify backwards because there are two LoadClass instructions
+  // Note: There are two LoadClass instructions. We obtain the correct
+  //       instruction id by matching the Return's input list first.
 
   public static Class inlineOtherDexCallingMain() {
     return OtherDex.returnOtherDexCallingMain();
diff --git a/tools/checker/README b/tools/checker/README
index 2763948..858a773 100644
--- a/tools/checker/README
+++ b/tools/checker/README
@@ -47,7 +47,7 @@
 
   // CHECK-START: int MyClass.MyMethod() constant_folding (after)
   // CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
-  // CHECK:                      Return [ <<ID>> ]
+  // CHECK:                      Return [<<ID>>]
 
   The engine will attempt to match the check lines against the output of the
   group named on the first line. Together they verify that the CFG after