am c1134980: Merge "ART: Sometimes even empty methods take forever to verify" into mnc-dev

* commit 'c1134980c652b69a10b0317ff306e12f4feeea3c':
  ART: Sometimes even empty methods take forever to verify
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index e0c0b0c..2d6b6a3 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -80,7 +80,7 @@
 TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
 
 # Jar files for core.art.
-TARGET_CORE_JARS := core-libart conscrypt okhttp core-junit bouncycastle
+TARGET_CORE_JARS := core-libart conscrypt okhttp bouncycastle
 HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS))
 
 HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
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/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 47288b5..5dc93ce 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -74,8 +74,8 @@
 
 static constexpr bool kTimeCompileMethod = !kIsDebugBuild;
 
-// Whether to produce 64-bit ELF files for 64-bit targets. Leave this off for now.
-static constexpr bool kProduce64BitELFFiles = false;
+// Whether to produce 64-bit ELF files for 64-bit targets.
+static constexpr bool kProduce64BitELFFiles = true;
 
 // Whether classes-to-compile and methods-to-compile are only applied to the boot image, or, when
 // given, too all compilations.
@@ -1241,7 +1241,7 @@
   mirror::Class* referrer_class;
   mirror::DexCache* dex_cache;
   {
-    StackHandleScope<3> hs(soa.Self());
+    StackHandleScope<2> hs(soa.Self());
     Handle<mirror::DexCache> dex_cache_handle(
         hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
     Handle<mirror::ClassLoader> class_loader_handle(
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_builder.h b/compiler/elf_builder.h
index 63d3a0d..972bd08 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -56,12 +56,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_(), 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_(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;
     }
     virtual ~Section() {}
 
@@ -79,11 +79,11 @@
     }
 
     const Elf_Shdr* GetHeader() const {
-      return &header_;
+      return header_.get();
     }
 
     Elf_Shdr* GetHeader() {
-      return &header_;
+      return header_.get();
     }
 
     Elf_Word GetSectionIndex() const {
@@ -100,7 +100,9 @@
     }
 
    private:
-    Elf_Shdr header_;
+    // 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_Word section_index_;
     const std::string name_;
     const Section* const link_;
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 5e9cf76..f4df6c1 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);
+    }
   }
 }
 
@@ -234,6 +243,7 @@
                         std::vector<uintptr_t>* debug_line_patches) {
   const std::vector<OatWriter::DebugInfo>& method_infos = oat_writer->GetMethodDebugInfo();
   const InstructionSet isa = compiler->GetInstructionSet();
+  const bool is64bit = Is64BitInstructionSet(isa);
 
   // Find all addresses (low_pc) which contain deduped methods.
   // The first instance of method is not marked deduped_, but the rest is.
@@ -271,7 +281,7 @@
     }
 
     size_t debug_abbrev_offset = debug_abbrev->size();
-    DebugInfoEntryWriter<> info(false /* 32 bit */, debug_abbrev);
+    DebugInfoEntryWriter<> info(is64bit, debug_abbrev);
     info.StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes);
     info.WriteStrp(DW_AT_producer, "Android dex2oat", debug_str);
     info.WriteData1(DW_AT_language, DW_LANG_Java);
@@ -316,7 +326,7 @@
       case kX86_64:
         break;
     }
-    DebugLineOpCodeWriter<> opcodes(false /* 32bit */, code_factor_bits_);
+    DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_);
     opcodes.SetAddress(cunit_low_pc);
     if (dwarf_isa != -1) {
       opcodes.SetISA(dwarf_isa);
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/builder.cc b/compiler/optimizing/builder.cc
index a5c6f23..c4eaabf 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -539,11 +539,6 @@
 }
 
 static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) {
-  // dex compilation unit is null only when unit testing.
-  if (cu == nullptr) {
-    return false;
-  }
-
   Thread* self = Thread::Current();
   return cu->IsConstructor()
       && driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex());
@@ -551,9 +546,12 @@
 
 void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
   if (type == Primitive::kPrimVoid) {
-    // Note that we might insert redundant barriers when inlining `super` calls.
-    // TODO: add a data flow analysis to get rid of duplicate barriers.
-    if (RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_)) {
+    if (graph_->ShouldGenerateConstructorBarrier()) {
+      // The compilation unit is null during testing.
+      if (dex_compilation_unit_ != nullptr) {
+        DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_))
+          << "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier.";
+      }
       current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore));
     }
     current_block_->AddInstruction(new (arena_) HReturnVoid());
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 0e776b3..d71266d 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -645,23 +645,34 @@
     }
   }
 
+  uint32_t outer_dex_pc = dex_pc;
+  uint32_t outer_environment_size = 0;
+  uint32_t inlining_depth = 0;
+  if (instruction != nullptr) {
+    for (HEnvironment* environment = instruction->GetEnvironment();
+         environment != nullptr;
+         environment = environment->GetParent()) {
+      outer_dex_pc = environment->GetDexPc();
+      outer_environment_size = environment->Size();
+      if (environment != instruction->GetEnvironment()) {
+        inlining_depth++;
+      }
+    }
+  }
+
   // Collect PC infos for the mapping table.
   struct PcInfo pc_info;
-  pc_info.dex_pc = dex_pc;
+  pc_info.dex_pc = outer_dex_pc;
   pc_info.native_pc = GetAssembler()->CodeSize();
   pc_infos_.Add(pc_info);
 
-  uint32_t inlining_depth = 0;
-
   if (instruction == nullptr) {
     // For stack overflow checks.
-    stack_map_stream_.BeginStackMapEntry(dex_pc, pc_info.native_pc, 0, 0, 0, inlining_depth);
+    stack_map_stream_.BeginStackMapEntry(pc_info.dex_pc, pc_info.native_pc, 0, 0, 0, 0);
     stack_map_stream_.EndStackMapEntry();
     return;
   }
   LocationSummary* locations = instruction->GetLocations();
-  HEnvironment* environment = instruction->GetEnvironment();
-  size_t environment_size = instruction->EnvironmentSize();
 
   uint32_t register_mask = locations->GetRegisterMask();
   if (locations->OnlyCallsOnSlowPath()) {
@@ -674,23 +685,34 @@
   }
   // The register mask must be a subset of callee-save registers.
   DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask);
-  stack_map_stream_.BeginStackMapEntry(dex_pc,
+  stack_map_stream_.BeginStackMapEntry(pc_info.dex_pc,
                                        pc_info.native_pc,
                                        register_mask,
                                        locations->GetStackMask(),
-                                       environment_size,
+                                       outer_environment_size,
                                        inlining_depth);
-  if (environment != nullptr) {
-    // TODO: Handle parent environment.
-    DCHECK(environment->GetParent() == nullptr);
-    DCHECK_EQ(environment->GetDexPc(), dex_pc);
+
+  EmitEnvironment(instruction->GetEnvironment(), slow_path);
+  stack_map_stream_.EndStackMapEntry();
+}
+
+void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path) {
+  if (environment == nullptr) return;
+
+  if (environment->GetParent() != nullptr) {
+    // We emit the parent environment first.
+    EmitEnvironment(environment->GetParent(), slow_path);
+    stack_map_stream_.BeginInlineInfoEntry(environment->GetMethodIdx(),
+                                           environment->GetDexPc(),
+                                           environment->GetInvokeType(),
+                                           environment->Size());
   }
 
   // Walk over the environment, and record the location of dex registers.
-  for (size_t i = 0; i < environment_size; ++i) {
+  for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) {
     HInstruction* current = environment->GetInstructionAt(i);
     if (current == nullptr) {
-      stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kNone, 0);
+      stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
       continue;
     }
 
@@ -701,41 +723,44 @@
         if (current->IsLongConstant()) {
           int64_t value = current->AsLongConstant()->GetValue();
           stack_map_stream_.AddDexRegisterEntry(
-              i, DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+              DexRegisterLocation::Kind::kConstant, Low32Bits(value));
           stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value));
+              DexRegisterLocation::Kind::kConstant, High32Bits(value));
+          ++i;
           DCHECK_LT(i, environment_size);
         } else if (current->IsDoubleConstant()) {
           int64_t value = bit_cast<int64_t, double>(current->AsDoubleConstant()->GetValue());
           stack_map_stream_.AddDexRegisterEntry(
-              i, DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+              DexRegisterLocation::Kind::kConstant, Low32Bits(value));
           stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value));
+              DexRegisterLocation::Kind::kConstant, High32Bits(value));
+          ++i;
           DCHECK_LT(i, environment_size);
         } else if (current->IsIntConstant()) {
           int32_t value = current->AsIntConstant()->GetValue();
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
         } else if (current->IsNullConstant()) {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, 0);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0);
         } else {
           DCHECK(current->IsFloatConstant()) << current->DebugName();
           int32_t value = bit_cast<int32_t, float>(current->AsFloatConstant()->GetValue());
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
         }
         break;
       }
 
       case Location::kStackSlot: {
         stack_map_stream_.AddDexRegisterEntry(
-            i, DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+            DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
         break;
       }
 
       case Location::kDoubleStackSlot: {
         stack_map_stream_.AddDexRegisterEntry(
-            i, DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+            DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
         stack_map_stream_.AddDexRegisterEntry(
-            ++i, DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize));
+            DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize));
+        ++i;
         DCHECK_LT(i, environment_size);
         break;
       }
@@ -744,16 +769,18 @@
         int id = location.reg();
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(id)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(id);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
           if (current->GetType() == Primitive::kPrimLong) {
             stack_map_stream_.AddDexRegisterEntry(
-                ++i, DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+                DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInRegister, id);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
           if (current->GetType() == Primitive::kPrimLong) {
-            stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInRegister, id);
+            stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         }
@@ -764,17 +791,18 @@
         int id = location.reg();
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(id)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(id);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
           if (current->GetType() == Primitive::kPrimDouble) {
             stack_map_stream_.AddDexRegisterEntry(
-                ++i, DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+                DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInFpuRegister, id);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
           if (current->GetType() == Primitive::kPrimDouble) {
-            stack_map_stream_.AddDexRegisterEntry(
-                ++i, DexRegisterLocation::Kind::kInFpuRegister, id);
+            stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         }
@@ -786,16 +814,17 @@
         int high = location.high();
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(low)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(low);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInFpuRegister, low);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, low);
         }
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(high)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(high);
-          stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
+          ++i;
         } else {
-          stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kInFpuRegister, high);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, high);
+          ++i;
         }
         DCHECK_LT(i, environment_size);
         break;
@@ -806,23 +835,23 @@
         int high = location.high();
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(low)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(low);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInRegister, low);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, low);
         }
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(high)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(high);
-          stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
         } else {
-          stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kInRegister, high);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, high);
         }
+        ++i;
         DCHECK_LT(i, environment_size);
         break;
       }
 
       case Location::kInvalid: {
-        stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kNone, 0);
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
         break;
       }
 
@@ -830,7 +859,10 @@
         LOG(FATAL) << "Unexpected kind " << location.GetKind();
     }
   }
-  stack_map_stream_.EndStackMapEntry();
+
+  if (environment->GetParent() != nullptr) {
+    stack_map_stream_.EndInlineInfoEntry();
+  }
 }
 
 bool CodeGenerator::CanMoveNullCheckToUser(HNullCheck* null_check) {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index bdbd571..740beab 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -34,10 +34,15 @@
 // Binary encoding of 2^31 for type double.
 static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
 
+// Minimum value for a primitive integer.
+static int32_t constexpr kPrimIntMin = 0x80000000;
+// Minimum value for a primitive long.
+static int64_t constexpr kPrimLongMin = INT64_C(0x8000000000000000);
+
 // Maximum value for a primitive integer.
 static int32_t constexpr kPrimIntMax = 0x7fffffff;
 // Maximum value for a primitive long.
-static int64_t constexpr kPrimLongMax = 0x7fffffffffffffff;
+static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff);
 
 class Assembler;
 class CodeGenerator;
@@ -77,8 +82,8 @@
 
   virtual void EmitNativeCode(CodeGenerator* codegen) = 0;
 
-  void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
-  void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
+  virtual void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
+  virtual void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
   void RecordPcInfo(CodeGenerator* codegen, HInstruction* instruction, uint32_t dex_pc);
 
   bool IsCoreRegisterSaved(int reg) const {
@@ -97,11 +102,13 @@
     return saved_fpu_stack_offsets_[reg];
   }
 
- private:
+ protected:
   static constexpr size_t kMaximumNumberOfExpectedRegisters = 32;
   static constexpr uint32_t kRegisterNotSaved = -1;
   uint32_t saved_core_stack_offsets_[kMaximumNumberOfExpectedRegisters];
   uint32_t saved_fpu_stack_offsets_[kMaximumNumberOfExpectedRegisters];
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(SlowPathCode);
 };
 
@@ -436,6 +443,7 @@
   size_t GetStackOffsetOfSavedRegister(size_t index);
   void CompileInternal(CodeAllocator* allocator, bool is_baseline);
   void BlockIfInRegister(Location location, bool is_out = false) const;
+  void EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path);
 
   HGraph* const graph_;
   const CompilerOptions& compiler_options_;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index f56e446..1c76630 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -17,6 +17,7 @@
 #include "code_generator_arm.h"
 
 #include "arch/arm/instruction_set_features_arm.h"
+#include "code_generator_utils.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
 #include "intrinsics.h"
@@ -347,11 +348,11 @@
 }
 
 void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << ArmManagedRegister::FromCoreRegister(Register(reg));
+  stream << Register(reg);
 }
 
 void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << ArmManagedRegister::FromSRegister(SRegister(reg));
+  stream << SRegister(reg);
 }
 
 size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
@@ -390,7 +391,7 @@
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this),
-      assembler_(true),
+      assembler_(false /* can_relocate_branches */),
       isa_features_(isa_features) {
   // Save the PC register to mimic Quick.
   AddAllocatedRegister(Location::RegisterLocation(PC));
@@ -2185,11 +2186,134 @@
   }
 }
 
+void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = locations->Out().AsRegister<Register>();
+  Register dividend = locations->InAt(0).AsRegister<Register>();
+  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  DCHECK(imm == 1 || imm == -1);
+
+  if (instruction->IsRem()) {
+    __ LoadImmediate(out, 0);
+  } else {
+    if (imm == 1) {
+      __ Mov(out, dividend);
+    } else {
+      __ rsb(out, dividend, ShifterOperand(0));
+    }
+  }
+}
+
+void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = locations->Out().AsRegister<Register>();
+  Register dividend = locations->InAt(0).AsRegister<Register>();
+  Register temp = locations->GetTemp(0).AsRegister<Register>();
+  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  int32_t abs_imm = std::abs(imm);
+  DCHECK(IsPowerOfTwo(abs_imm));
+  int ctz_imm = CTZ(abs_imm);
+
+  if (ctz_imm == 1) {
+    __ Lsr(temp, dividend, 32 - ctz_imm);
+  } else {
+    __ Asr(temp, dividend, 31);
+    __ Lsr(temp, temp, 32 - ctz_imm);
+  }
+  __ add(out, temp, ShifterOperand(dividend));
+
+  if (instruction->IsDiv()) {
+    __ Asr(out, out, ctz_imm);
+    if (imm < 0) {
+      __ rsb(out, out, ShifterOperand(0));
+    }
+  } else {
+    __ ubfx(out, out, 0, ctz_imm);
+    __ sub(out, out, ShifterOperand(temp));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = locations->Out().AsRegister<Register>();
+  Register dividend = locations->InAt(0).AsRegister<Register>();
+  Register temp1 = locations->GetTemp(0).AsRegister<Register>();
+  Register temp2 = locations->GetTemp(1).AsRegister<Register>();
+  int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+
+  int64_t magic;
+  int shift;
+  CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
+
+  __ LoadImmediate(temp1, magic);
+  __ smull(temp2, temp1, dividend, temp1);
+
+  if (imm > 0 && magic < 0) {
+    __ add(temp1, temp1, ShifterOperand(dividend));
+  } else if (imm < 0 && magic > 0) {
+    __ sub(temp1, temp1, ShifterOperand(dividend));
+  }
+
+  if (shift != 0) {
+    __ Asr(temp1, temp1, shift);
+  }
+
+  if (instruction->IsDiv()) {
+    __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
+  } else {
+    __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
+    // TODO: Strength reduction for mls.
+    __ LoadImmediate(temp2, imm);
+    __ mls(out, temp1, temp2, dividend);
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  if (imm == 0) {
+    // Do not generate anything. DivZeroCheck would prevent any code to be executed.
+  } else if (imm == 1 || imm == -1) {
+    DivRemOneOrMinusOne(instruction);
+  } else if (IsPowerOfTwo(std::abs(imm))) {
+    DivRemByPowerOfTwo(instruction);
+  } else {
+    DCHECK(imm <= -2 || imm >= 2);
+    GenerateDivRemWithAnyConstant(instruction);
+  }
+}
+
 void LocationsBuilderARM::VisitDiv(HDiv* div) {
   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   if (div->GetResultType() == Primitive::kPrimLong) {
     // pLdiv runtime call.
     call_kind = LocationSummary::kCall;
+  } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
+    // sdiv will be replaced by other instruction sequence.
   } else if (div->GetResultType() == Primitive::kPrimInt &&
              !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
     // pIdivmod runtime call.
@@ -2200,7 +2324,20 @@
 
   switch (div->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (div->InputAt(1)->IsConstant()) {
+        locations->SetInAt(0, Location::RequiresRegister());
+        locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
+        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+        int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
+        if (abs_imm <= 1) {
+          // No temp register required.
+        } else {
+          locations->AddTemp(Location::RequiresRegister());
+          if (!IsPowerOfTwo(abs_imm)) {
+            locations->AddTemp(Location::RequiresRegister());
+          }
+        }
+      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::RequiresRegister());
         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2244,7 +2381,9 @@
 
   switch (div->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (second.IsConstant()) {
+        GenerateDivRemConstantIntegral(div);
+      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         __ sdiv(out.AsRegister<Register>(),
                 first.AsRegister<Register>(),
                 second.AsRegister<Register>());
@@ -2296,8 +2435,11 @@
 
   // Most remainders are implemented in the runtime.
   LocationSummary::CallKind call_kind = LocationSummary::kCall;
-  if (rem->GetResultType() == Primitive::kPrimInt &&
-      codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+  if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
+    // sdiv will be replaced by other instruction sequence.
+    call_kind = LocationSummary::kNoCall;
+  } else if ((rem->GetResultType() == Primitive::kPrimInt)
+             && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
     // Have hardware divide instruction for int, do it with three instructions.
     call_kind = LocationSummary::kNoCall;
   }
@@ -2306,7 +2448,20 @@
 
   switch (type) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (rem->InputAt(1)->IsConstant()) {
+        locations->SetInAt(0, Location::RequiresRegister());
+        locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
+        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+        int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
+        if (abs_imm <= 1) {
+          // No temp register required.
+        } else {
+          locations->AddTemp(Location::RequiresRegister());
+          if (!IsPowerOfTwo(abs_imm)) {
+            locations->AddTemp(Location::RequiresRegister());
+          }
+        }
+      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::RequiresRegister());
         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2363,7 +2518,9 @@
   Primitive::Type type = rem->GetResultType();
   switch (type) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+        if (second.IsConstant()) {
+          GenerateDivRemConstantIntegral(rem);
+        } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         Register reg1 = first.AsRegister<Register>();
         Register reg2 = second.AsRegister<Register>();
         Register temp = locations->GetTemp(0).AsRegister<Register>();
@@ -2880,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();
@@ -2969,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) {
@@ -3096,7 +3255,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3120,7 +3279,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3390,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);
@@ -3495,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 1a498e1..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);
@@ -189,6 +191,10 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void DivRemOneOrMinusOne(HBinaryOperation* instruction);
+  void DivRemByPowerOfTwo(HBinaryOperation* instruction);
+  void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
+  void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
 
   ArmAssembler* const assembler_;
   CodeGeneratorARM* const codegen_;
@@ -270,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 0222f93..b6d99ab 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -17,6 +17,7 @@
 #include "code_generator_arm64.h"
 
 #include "arch/arm64/instruction_set_features_arm64.h"
+#include "code_generator_utils.h"
 #include "common_arm64.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
@@ -64,6 +65,7 @@
 using helpers::WRegisterFrom;
 using helpers::XRegisterFrom;
 using helpers::ARM64EncodableConstantOrRegister;
+using helpers::ArtVixlRegCodeCoherentForRegSet;
 
 static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
 static constexpr int kCurrentMethodStackOffset = 0;
@@ -105,6 +107,88 @@
 #define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
 #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
 
+// Calculate memory accessing operand for save/restore live registers.
+static void SaveRestoreLiveRegistersHelper(CodeGenerator* codegen,
+                                           RegisterSet* register_set,
+                                           int64_t spill_offset,
+                                           bool is_save) {
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(register_set->GetCoreRegisters(),
+                                         codegen->GetNumberOfCoreRegisters(),
+                                         register_set->GetFloatingPointRegisters(),
+                                         codegen->GetNumberOfFloatingPointRegisters()));
+
+  CPURegList core_list = CPURegList(CPURegister::kRegister, kXRegSize,
+      register_set->GetCoreRegisters() & (~callee_saved_core_registers.list()));
+  CPURegList fp_list = CPURegList(CPURegister::kFPRegister, kDRegSize,
+      register_set->GetFloatingPointRegisters() & (~callee_saved_fp_registers.list()));
+
+  MacroAssembler* masm = down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler();
+  UseScratchRegisterScope temps(masm);
+
+  Register base = masm->StackPointer();
+  int64_t core_spill_size = core_list.TotalSizeInBytes();
+  int64_t fp_spill_size = fp_list.TotalSizeInBytes();
+  int64_t reg_size = kXRegSizeInBytes;
+  int64_t max_ls_pair_offset = spill_offset + core_spill_size + fp_spill_size - 2 * reg_size;
+  uint32_t ls_access_size = WhichPowerOf2(reg_size);
+  if (((core_list.Count() > 1) || (fp_list.Count() > 1)) &&
+      !masm->IsImmLSPair(max_ls_pair_offset, ls_access_size)) {
+    // If the offset does not fit in the instruction's immediate field, use an alternate register
+    // to compute the base address(float point registers spill base address).
+    Register new_base = temps.AcquireSameSizeAs(base);
+    __ Add(new_base, base, Operand(spill_offset + core_spill_size));
+    base = new_base;
+    spill_offset = -core_spill_size;
+    int64_t new_max_ls_pair_offset = fp_spill_size - 2 * reg_size;
+    DCHECK(masm->IsImmLSPair(spill_offset, ls_access_size));
+    DCHECK(masm->IsImmLSPair(new_max_ls_pair_offset, ls_access_size));
+  }
+
+  if (is_save) {
+    __ StoreCPURegList(core_list, MemOperand(base, spill_offset));
+    __ StoreCPURegList(fp_list, MemOperand(base, spill_offset + core_spill_size));
+  } else {
+    __ LoadCPURegList(core_list, MemOperand(base, spill_offset));
+    __ LoadCPURegList(fp_list, MemOperand(base, spill_offset + core_spill_size));
+  }
+}
+
+void SlowPathCodeARM64::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
+  RegisterSet* register_set = locations->GetLiveRegisters();
+  size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
+  for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
+    if (!codegen->IsCoreCalleeSaveRegister(i) && register_set->ContainsCoreRegister(i)) {
+      // If the register holds an object, update the stack mask.
+      if (locations->RegisterContainsObject(i)) {
+        locations->SetStackBit(stack_offset / kVRegSize);
+      }
+      DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+      DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+      saved_core_stack_offsets_[i] = stack_offset;
+      stack_offset += kXRegSizeInBytes;
+    }
+  }
+
+  for (size_t i = 0, e = codegen->GetNumberOfFloatingPointRegisters(); i < e; ++i) {
+    if (!codegen->IsFloatingPointCalleeSaveRegister(i) &&
+        register_set->ContainsFloatingPointRegister(i)) {
+      DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+      DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+      saved_fpu_stack_offsets_[i] = stack_offset;
+      stack_offset += kDRegSizeInBytes;
+    }
+  }
+
+  SaveRestoreLiveRegistersHelper(codegen, register_set,
+                                 codegen->GetFirstRegisterSlotInSlowPath(), true /* is_save */);
+}
+
+void SlowPathCodeARM64::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
+  RegisterSet* register_set = locations->GetLiveRegisters();
+  SaveRestoreLiveRegistersHelper(codegen, register_set,
+                                 codegen->GetFirstRegisterSlotInSlowPath(), false /* is_save */);
+}
+
 class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
  public:
   BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
@@ -529,6 +613,19 @@
   GetAssembler()->cfi().DefCFAOffset(GetFrameSize());
 }
 
+vixl::CPURegList CodeGeneratorARM64::GetFramePreservedCoreRegisters() const {
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(core_spill_mask_, GetNumberOfCoreRegisters(), 0, 0));
+  return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
+                          core_spill_mask_);
+}
+
+vixl::CPURegList CodeGeneratorARM64::GetFramePreservedFPRegisters() const {
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(0, 0, fpu_spill_mask_,
+                                         GetNumberOfFloatingPointRegisters()));
+  return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
+                          fpu_spill_mask_);
+}
+
 void CodeGeneratorARM64::Bind(HBasicBlock* block) {
   __ Bind(GetLabelOf(block));
 }
@@ -604,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 {
@@ -691,11 +792,11 @@
 }
 
 void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
+  stream << XRegister(reg);
 }
 
 void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
+  stream << DRegister(reg);
 }
 
 void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
@@ -979,14 +1080,12 @@
   BlockPoolsScope block_pools(GetVIXLAssembler());
   __ Ldr(lr, MemOperand(tr, entry_point_offset));
   __ Blr(lr);
-  if (instruction != nullptr) {
-    RecordPcInfo(instruction, dex_pc, slow_path);
-    DCHECK(instruction->IsSuspendCheck()
-        || instruction->IsBoundsCheck()
-        || instruction->IsNullCheck()
-        || instruction->IsDivZeroCheck()
-        || !IsLeafMethod());
-    }
+  RecordPcInfo(instruction, dex_pc, slow_path);
+  DCHECK(instruction->IsSuspendCheck()
+         || instruction->IsBoundsCheck()
+         || instruction->IsNullCheck()
+         || instruction->IsDivZeroCheck()
+         || !IsLeafMethod());
 }
 
 void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
@@ -1170,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());
 
@@ -1196,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);
   }
 }
 
@@ -1422,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());
     }
   }
 }
@@ -1605,6 +1705,152 @@
 #undef DEFINE_CONDITION_VISITORS
 #undef FOR_EACH_CONDITION_INSTRUCTION
 
+void InstructionCodeGeneratorARM64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = OutputRegister(instruction);
+  Register dividend = InputRegisterAt(instruction, 0);
+  int64_t imm = Int64FromConstant(second.GetConstant());
+  DCHECK(imm == 1 || imm == -1);
+
+  if (instruction->IsRem()) {
+    __ Mov(out, 0);
+  } else {
+    if (imm == 1) {
+      __ Mov(out, dividend);
+    } else {
+      __ Neg(out, dividend);
+    }
+  }
+}
+
+void InstructionCodeGeneratorARM64::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = OutputRegister(instruction);
+  Register dividend = InputRegisterAt(instruction, 0);
+  int64_t imm = Int64FromConstant(second.GetConstant());
+  int64_t abs_imm = std::abs(imm);
+  DCHECK(IsPowerOfTwo(abs_imm));
+  int ctz_imm = CTZ(abs_imm);
+
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp = temps.AcquireSameSizeAs(out);
+
+  if (instruction->IsDiv()) {
+    __ Add(temp, dividend, abs_imm - 1);
+    __ Cmp(dividend, 0);
+    __ Csel(out, temp, dividend, lt);
+    if (imm > 0) {
+      __ Asr(out, out, ctz_imm);
+    } else {
+      __ Neg(out, Operand(out, ASR, ctz_imm));
+    }
+  } else {
+    int bits = instruction->GetResultType() == Primitive::kPrimInt ? 32 : 64;
+    __ Asr(temp, dividend, bits - 1);
+    __ Lsr(temp, temp, bits - ctz_imm);
+    __ Add(out, dividend, temp);
+    __ And(out, out, abs_imm - 1);
+    __ Sub(out, out, temp);
+  }
+}
+
+void InstructionCodeGeneratorARM64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = OutputRegister(instruction);
+  Register dividend = InputRegisterAt(instruction, 0);
+  int64_t imm = Int64FromConstant(second.GetConstant());
+
+  Primitive::Type type = instruction->GetResultType();
+  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+  int64_t magic;
+  int shift;
+  CalculateMagicAndShiftForDivRem(imm, type == Primitive::kPrimLong /* is_long */, &magic, &shift);
+
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp = temps.AcquireSameSizeAs(out);
+
+  // temp = get_high(dividend * magic)
+  __ Mov(temp, magic);
+  if (type == Primitive::kPrimLong) {
+    __ Smulh(temp, dividend, temp);
+  } else {
+    __ Smull(temp.X(), dividend, temp);
+    __ Lsr(temp.X(), temp.X(), 32);
+  }
+
+  if (imm > 0 && magic < 0) {
+    __ Add(temp, temp, dividend);
+  } else if (imm < 0 && magic > 0) {
+    __ Sub(temp, temp, dividend);
+  }
+
+  if (shift != 0) {
+    __ Asr(temp, temp, shift);
+  }
+
+  if (instruction->IsDiv()) {
+    __ Sub(out, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+  } else {
+    __ Sub(temp, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+    // TODO: Strength reduction for msub.
+    Register temp_imm = temps.AcquireSameSizeAs(out);
+    __ Mov(temp_imm, imm);
+    __ Msub(out, temp, temp_imm, dividend);
+  }
+}
+
+void InstructionCodeGeneratorARM64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  Primitive::Type type = instruction->GetResultType();
+  DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Register out = OutputRegister(instruction);
+  Location second = locations->InAt(1);
+
+  if (second.IsConstant()) {
+    int64_t imm = Int64FromConstant(second.GetConstant());
+
+    if (imm == 0) {
+      // Do not generate anything. DivZeroCheck would prevent any code to be executed.
+    } else if (imm == 1 || imm == -1) {
+      DivRemOneOrMinusOne(instruction);
+    } else if (IsPowerOfTwo(std::abs(imm))) {
+      DivRemByPowerOfTwo(instruction);
+    } else {
+      DCHECK(imm <= -2 || imm >= 2);
+      GenerateDivRemWithAnyConstant(instruction);
+    }
+  } else {
+    Register dividend = InputRegisterAt(instruction, 0);
+    Register divisor = InputRegisterAt(instruction, 1);
+    if (instruction->IsDiv()) {
+      __ Sdiv(out, dividend, divisor);
+    } else {
+      UseScratchRegisterScope temps(GetVIXLAssembler());
+      Register temp = temps.AcquireSameSizeAs(out);
+      __ Sdiv(temp, dividend, divisor);
+      __ Msub(out, temp, divisor, dividend);
+    }
+  }
+}
+
 void LocationsBuilderARM64::VisitDiv(HDiv* div) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
@@ -1612,7 +1858,7 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
@@ -1633,7 +1879,7 @@
   switch (type) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
-      __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
+      GenerateDivRemIntegral(div);
       break;
 
     case Primitive::kPrimFloat:
@@ -1848,7 +2094,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
@@ -2456,7 +2702,7 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
@@ -2481,14 +2727,7 @@
   switch (type) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
-      UseScratchRegisterScope temps(GetVIXLAssembler());
-      Register dividend = InputRegisterAt(rem, 0);
-      Register divisor = InputRegisterAt(rem, 1);
-      Register output = OutputRegister(rem);
-      Register temp = temps.AcquireSameSizeAs(output);
-
-      __ Sdiv(temp, dividend, divisor);
-      __ Msub(output, temp, divisor, dividend);
+      GenerateDivRemIntegral(rem);
       break;
     }
 
@@ -2598,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 8aeea54..b56ca10 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -70,6 +70,9 @@
   vixl::Label* GetEntryLabel() { return &entry_label_; }
   vixl::Label* GetExitLabel() { return &exit_label_; }
 
+  void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
+  void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
+
  private:
   vixl::Label entry_label_;
   vixl::Label exit_label_;
@@ -154,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);
@@ -163,6 +168,11 @@
                              vixl::Label* true_target,
                              vixl::Label* false_target,
                              vixl::Label* always_true_target);
+  void DivRemOneOrMinusOne(HBinaryOperation* instruction);
+  void DivRemByPowerOfTwo(HBinaryOperation* instruction);
+  void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
+  void GenerateDivRemIntegral(HBinaryOperation* instruction);
+
 
   Arm64Assembler* const assembler_;
   CodeGeneratorARM64* const codegen_;
@@ -227,15 +237,8 @@
   void GenerateFrameEntry() OVERRIDE;
   void GenerateFrameExit() OVERRIDE;
 
-  vixl::CPURegList GetFramePreservedCoreRegisters() const {
-    return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
-                            core_spill_mask_);
-  }
-
-  vixl::CPURegList GetFramePreservedFPRegisters() const {
-    return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
-                            fpu_spill_mask_);
-  }
+  vixl::CPURegList GetFramePreservedCoreRegisters() const;
+  vixl::CPURegList GetFramePreservedFPRegisters() const;
 
   void Bind(HBasicBlock* block) OVERRIDE;
 
@@ -266,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.
 
@@ -277,10 +280,10 @@
 
   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
 
-  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
   // The number of registers that can be allocated. The register allocator may
   // decide to reserve and not use a few of them.
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2848a48..a6f01da 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -340,11 +340,11 @@
 }
 
 void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << X86ManagedRegister::FromCpuRegister(Register(reg));
+  stream << Register(reg);
 }
 
 void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
+  stream << XmmRegister(reg);
 }
 
 size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
@@ -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 e633970..f49c26d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -396,11 +396,11 @@
 }
 
 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
+  stream << Register(reg);
 }
 
 void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
+  stream << FloatRegister(reg);
 }
 
 size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
@@ -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/common_arm64.h b/compiler/optimizing/common_arm64.h
index 53f1f3c..246fff9 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -218,6 +218,28 @@
   return Location::RequiresRegister();
 }
 
+// Check if registers in art register set have the same register code in vixl. If the register
+// codes are same, we can initialize vixl register list simply by the register masks. Currently,
+// only SP/WSP and ZXR/WZR codes are different between art and vixl.
+// Note: This function is only used for debug checks.
+static inline bool ArtVixlRegCodeCoherentForRegSet(uint32_t art_core_registers,
+                                                   size_t num_core,
+                                                   uint32_t art_fpu_registers,
+                                                   size_t num_fpu) {
+  // The register masks won't work if the number of register is larger than 32.
+  DCHECK_GE(sizeof(art_core_registers) * 8, num_core);
+  DCHECK_GE(sizeof(art_fpu_registers) * 8, num_fpu);
+  for (size_t art_reg_code = 0;  art_reg_code < num_core; ++art_reg_code) {
+    if (RegisterSet::Contains(art_core_registers, art_reg_code)) {
+      if (art_reg_code != static_cast<size_t>(VIXLRegCodeFromART(art_reg_code))) {
+        return false;
+      }
+    }
+  }
+  // There is no register code translation for float registers.
+  return true;
+}
+
 }  // namespace helpers
 }  // namespace arm64
 }  // namespace art
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index b7a92b5..20ce110 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -28,6 +28,7 @@
   void VisitShift(HBinaryOperation* shift);
 
   void VisitAnd(HAnd* instruction) OVERRIDE;
+  void VisitCompare(HCompare* instruction) OVERRIDE;
   void VisitMul(HMul* instruction) OVERRIDE;
   void VisitOr(HOr* instruction) OVERRIDE;
   void VisitRem(HRem* instruction) OVERRIDE;
@@ -70,6 +71,14 @@
           inst->ReplaceWith(constant);
           inst->GetBlock()->RemoveInstruction(inst);
         }
+      } else if (inst->IsTypeConversion()) {
+        // Constant folding: replace `TypeConversion(a)' with a constant at
+        // compile time if `a' is a constant.
+        HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
+        if (constant != nullptr) {
+          inst->ReplaceWith(constant);
+          inst->GetBlock()->RemoveInstruction(inst);
+        }
       } else if (inst->IsDivZeroCheck()) {
         // We can safely remove the check if the input is a non-null constant.
         HDivZeroCheck* check = inst->AsDivZeroCheck();
@@ -108,6 +117,26 @@
   }
 }
 
+void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
+  HConstant* input_cst = instruction->GetConstantRight();
+  if (input_cst != nullptr) {
+    HInstruction* input_value = instruction->GetLeastConstantLeft();
+    if (Primitive::IsFloatingPointType(input_value->GetType()) &&
+        ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
+         (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
+      // Replace code looking like
+      //    CMP{G,L} dst, src, NaN
+      // with
+      //    CONSTANT +1 (gt bias)
+      // or
+      //    CONSTANT -1 (lt bias)
+      instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimInt,
+                                                       (instruction->IsGtBias() ? 1 : -1)));
+      instruction->GetBlock()->RemoveInstruction(instruction);
+    }
+  }
+}
+
 void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   Primitive::Type type = instruction->GetType();
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 6fbe75e..b31de98 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -17,6 +17,7 @@
 #include "dead_code_elimination.h"
 
 #include "base/bit_vector-inl.h"
+#include "ssa_phi_elimination.h"
 
 namespace art {
 
@@ -132,6 +133,7 @@
 
 void HDeadCodeElimination::Run() {
   RemoveDeadBlocks();
+  SsaRedundantPhiElimination(graph_).Run();
   RemoveDeadInstructions();
 }
 
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index f5c630b..7da4f2d 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -24,8 +24,68 @@
 #include "register_allocator.h"
 #include "ssa_liveness_analysis.h"
 
+#include <cctype>
+#include <sstream>
+
 namespace art {
 
+static bool HasWhitespace(const char* str) {
+  DCHECK(str != nullptr);
+  while (str[0] != 0) {
+    if (isspace(str[0])) {
+      return true;
+    }
+    str++;
+  }
+  return false;
+}
+
+class StringList {
+ public:
+  enum Format {
+    kArrayBrackets,
+    kSetBrackets,
+  };
+
+  // Create an empty list
+  explicit StringList(Format format = kArrayBrackets) : format_(format), is_empty_(true) {}
+
+  // Construct StringList from a linked list. List element class T
+  // must provide methods `GetNext` and `Dump`.
+  template<class T>
+  explicit StringList(T* first_entry, Format format = kArrayBrackets) : StringList(format) {
+    for (T* current = first_entry; current != nullptr; current = current->GetNext()) {
+      current->Dump(NewEntryStream());
+    }
+  }
+
+  std::ostream& NewEntryStream() {
+    if (is_empty_) {
+      is_empty_ = false;
+    } else {
+      sstream_ << ",";
+    }
+    return sstream_;
+  }
+
+ private:
+  Format format_;
+  bool is_empty_;
+  std::ostringstream sstream_;
+
+  friend std::ostream& operator<<(std::ostream& os, const StringList& list);
+};
+
+std::ostream& operator<<(std::ostream& os, const StringList& list) {
+  switch (list.format_) {
+    case StringList::kArrayBrackets: return os << "[" << list.sstream_.str() << "]";
+    case StringList::kSetBrackets:   return os << "{" << list.sstream_.str() << "}";
+    default:
+      LOG(FATAL) << "Invalid StringList format";
+      UNREACHABLE();
+  }
+}
+
 /**
  * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
  */
@@ -125,76 +185,99 @@
     output_<< std::endl;
   }
 
-  void DumpLocation(Location location) {
+  void DumpLocation(std::ostream& stream, const Location& location) {
     if (location.IsRegister()) {
-      codegen_.DumpCoreRegister(output_, location.reg());
+      codegen_.DumpCoreRegister(stream, location.reg());
     } else if (location.IsFpuRegister()) {
-      codegen_.DumpFloatingPointRegister(output_, location.reg());
+      codegen_.DumpFloatingPointRegister(stream, location.reg());
     } else if (location.IsConstant()) {
-      output_ << "constant";
+      stream << "#";
       HConstant* constant = location.GetConstant();
       if (constant->IsIntConstant()) {
-        output_ << " " << constant->AsIntConstant()->GetValue();
+        stream << constant->AsIntConstant()->GetValue();
       } else if (constant->IsLongConstant()) {
-        output_ << " " << constant->AsLongConstant()->GetValue();
+        stream << constant->AsLongConstant()->GetValue();
       }
     } else if (location.IsInvalid()) {
-      output_ << "invalid";
+      stream << "invalid";
     } else if (location.IsStackSlot()) {
-      output_ << location.GetStackIndex() << "(sp)";
+      stream << location.GetStackIndex() << "(sp)";
     } else if (location.IsFpuRegisterPair()) {
-      codegen_.DumpFloatingPointRegister(output_, location.low());
-      output_ << " and ";
-      codegen_.DumpFloatingPointRegister(output_, location.high());
+      codegen_.DumpFloatingPointRegister(stream, location.low());
+      stream << "|";
+      codegen_.DumpFloatingPointRegister(stream, location.high());
     } else if (location.IsRegisterPair()) {
-      codegen_.DumpCoreRegister(output_, location.low());
-      output_ << " and ";
-      codegen_.DumpCoreRegister(output_, location.high());
+      codegen_.DumpCoreRegister(stream, location.low());
+      stream << "|";
+      codegen_.DumpCoreRegister(stream, location.high());
     } else if (location.IsUnallocated()) {
-      output_ << "<U>";
+      stream << "unallocated";
     } else {
       DCHECK(location.IsDoubleStackSlot());
-      output_ << "2x" << location.GetStackIndex() << "(sp)";
+      stream << "2x" << location.GetStackIndex() << "(sp)";
     }
   }
 
+  std::ostream& StartAttributeStream(const char* name = nullptr) {
+    if (name == nullptr) {
+      output_ << " ";
+    } else {
+      DCHECK(!HasWhitespace(name)) << "Checker does not allow spaces in attributes";
+      output_ << " " << name << ":";
+    }
+    return output_;
+  }
+
   void VisitParallelMove(HParallelMove* instruction) OVERRIDE {
-    output_ << " (";
+    StartAttributeStream("liveness") << instruction->GetLifetimePosition();
+    StringList moves;
     for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
       MoveOperands* move = instruction->MoveOperandsAt(i);
-      DumpLocation(move->GetSource());
-      output_ << " -> ";
-      DumpLocation(move->GetDestination());
-      if (i + 1 != e) {
-        output_ << ", ";
-      }
+      std::ostream& str = moves.NewEntryStream();
+      DumpLocation(str, move->GetSource());
+      str << "->";
+      DumpLocation(str, move->GetDestination());
     }
-    output_ << ")";
-    output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
+    StartAttributeStream("moves") <<  moves;
   }
 
   void VisitIntConstant(HIntConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitLongConstant(HLongConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitPhi(HPhi* phi) OVERRIDE {
-    output_ << " " << phi->GetRegNumber();
+    StartAttributeStream("reg") << phi->GetRegNumber();
   }
 
   void VisitMemoryBarrier(HMemoryBarrier* barrier) OVERRIDE {
-    output_ << " " << barrier->GetBarrierKind();
+    StartAttributeStream("kind") << barrier->GetBarrierKind();
+  }
+
+  void VisitLoadClass(HLoadClass* load_cass) OVERRIDE {
+    StartAttributeStream("gen_clinit_check") << std::boolalpha
+        << load_cass->MustGenerateClinitCheck() << std::noboolalpha;
+  }
+
+  void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
+    StartAttributeStream("must_do_null_check") << std::boolalpha
+        << check_cast->MustDoNullCheck() << std::noboolalpha;
+  }
+
+  void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE {
+    StartAttributeStream("must_do_null_check") << std::boolalpha
+        << instance_of->MustDoNullCheck() << std::noboolalpha;
   }
 
   bool IsPass(const char* name) {
@@ -203,65 +286,66 @@
 
   void PrintInstruction(HInstruction* instruction) {
     output_ << instruction->DebugName();
-    instruction->Accept(this);
     if (instruction->InputCount() > 0) {
-      output_ << " [ ";
-      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
-        output_ << GetTypeId(inputs.Current()->GetType()) << inputs.Current()->GetId() << " ";
+      StringList inputs;
+      for (HInputIterator it(instruction); !it.Done(); it.Advance()) {
+        inputs.NewEntryStream() << GetTypeId(it.Current()->GetType()) << it.Current()->GetId();
       }
-      output_ << "]";
+      StartAttributeStream() << inputs;
     }
+    instruction->Accept(this);
     if (instruction->HasEnvironment()) {
-      output_ << " (env:";
+      StringList envs;
       for (HEnvironment* environment = instruction->GetEnvironment();
            environment != nullptr;
            environment = environment->GetParent()) {
-        output_ << " [ ";
+        StringList vregs;
         for (size_t i = 0, e = environment->Size(); i < e; ++i) {
           HInstruction* insn = environment->GetInstructionAt(i);
           if (insn != nullptr) {
-            output_ << GetTypeId(insn->GetType()) << insn->GetId() << " ";
+            vregs.NewEntryStream() << GetTypeId(insn->GetType()) << insn->GetId();
           } else {
-            output_ << " _ ";
+            vregs.NewEntryStream() << "_";
           }
         }
-        output_ << "]";
+        envs.NewEntryStream() << vregs;
       }
-      output_ << ")";
+      StartAttributeStream("env") << envs;
     }
     if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
         && is_after_pass_
         && instruction->GetLifetimePosition() != kNoLifetime) {
-      output_ << " (liveness: " << instruction->GetLifetimePosition();
+      StartAttributeStream("liveness") << instruction->GetLifetimePosition();
       if (instruction->HasLiveInterval()) {
-        output_ << " ";
-        const LiveInterval& interval = *instruction->GetLiveInterval();
-        interval.Dump(output_);
+        LiveInterval* interval = instruction->GetLiveInterval();
+        StartAttributeStream("ranges")
+            << StringList(interval->GetFirstRange(), StringList::kSetBrackets);
+        StartAttributeStream("uses") << StringList(interval->GetFirstUse());
+        StartAttributeStream("env_uses") << StringList(interval->GetFirstEnvironmentUse());
+        StartAttributeStream("is_fixed") << interval->IsFixed();
+        StartAttributeStream("is_split") << interval->IsSplit();
+        StartAttributeStream("is_low") << interval->IsLowInterval();
+        StartAttributeStream("is_high") << interval->IsHighInterval();
       }
-      output_ << ")";
     } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
+      StartAttributeStream("liveness") << instruction->GetLifetimePosition();
       LocationSummary* locations = instruction->GetLocations();
       if (locations != nullptr) {
-        output_ << " ( ";
+        StringList inputs;
         for (size_t i = 0; i < instruction->InputCount(); ++i) {
-          DumpLocation(locations->InAt(i));
-          output_ << " ";
+          DumpLocation(inputs.NewEntryStream(), locations->InAt(i));
         }
-        output_ << ")";
-        if (locations->Out().IsValid()) {
-          output_ << " -> ";
-          DumpLocation(locations->Out());
-        }
+        std::ostream& attr = StartAttributeStream("locations");
+        attr << inputs << "->";
+        DumpLocation(attr, locations->Out());
       }
-      output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
     } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
                || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)) {
-      output_ << " ( loop_header:";
       HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
       if (info == nullptr) {
-        output_ << "null )";
+        StartAttributeStream("loop") << "none";
       } else {
-        output_ << "B" << info->GetHeader()->GetBlockId() << " )";
+        StartAttributeStream("loop") << "B" << info->GetHeader()->GetBlockId();
       }
     }
   }
@@ -281,7 +365,7 @@
       output_ << bci << " " << num_uses << " "
               << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
       PrintInstruction(instruction);
-      output_ << kEndInstructionMarker << std::endl;
+      output_ << " " << kEndInstructionMarker << std::endl;
     }
   }
 
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index afffc7a..47c6318 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -169,10 +169,31 @@
     resolved_method->GetAccessFlags(),
     nullptr);
 
+  bool requires_ctor_barrier = false;
+
+  if (dex_compilation_unit.IsConstructor()) {
+    // If it's a super invocation and we already generate a barrier there's no need
+    // to generate another one.
+    // We identify super calls by looking at the "this" pointer. If its value is the
+    // same as the local "this" pointer then we must have a super invocation.
+    bool is_super_invocation = invoke_instruction->InputAt(0)->IsParameterValue()
+        && invoke_instruction->InputAt(0)->AsParameterValue()->IsThis();
+    if (is_super_invocation && graph_->ShouldGenerateConstructorBarrier()) {
+      requires_ctor_barrier = false;
+    } else {
+      Thread* self = Thread::Current();
+      requires_ctor_barrier = compiler_driver_->RequiresConstructorBarrier(self,
+          dex_compilation_unit.GetDexFile(),
+          dex_compilation_unit.GetClassDefIndex());
+    }
+  }
+
   HGraph* callee_graph = new (graph_->GetArena()) HGraph(
       graph_->GetArena(),
       caller_dex_file,
       method_index,
+      requires_ctor_barrier,
+      invoke_instruction->GetOriginalInvokeType(),
       graph_->IsDebuggable(),
       graph_->GetCurrentInstructionId());
 
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 46fad17..fcb3471 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;
@@ -63,6 +65,7 @@
   void VisitUShr(HUShr* instruction) OVERRIDE;
   void VisitXor(HXor* instruction) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
+  bool IsDominatedByInputNullCheck(HInstruction* instr);
 
   OptimizingCompilerStats* stats_;
   bool simplification_occurred_ = false;
@@ -78,6 +81,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
@@ -170,9 +175,20 @@
   }
 }
 
+bool InstructionSimplifierVisitor::IsDominatedByInputNullCheck(HInstruction* instr) {
+  HInstruction* input = instr->InputAt(0);
+  for (HUseIterator<HInstruction*> it(input->GetUses()); !it.Done(); it.Advance()) {
+    HInstruction* use = it.Current()->GetUser();
+    if (use->IsNullCheck() && use->StrictlyDominates(instr)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
   HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
-  if (!check_cast->InputAt(0)->CanBeNull()) {
+  if (!check_cast->InputAt(0)->CanBeNull() || IsDominatedByInputNullCheck(check_cast)) {
     check_cast->ClearMustDoNullCheck();
   }
 
@@ -194,11 +210,25 @@
 }
 
 void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) {
-  if (!instruction->InputAt(0)->CanBeNull()) {
+  if (!instruction->InputAt(0)->CanBeNull() || IsDominatedByInputNullCheck(instruction)) {
     instruction->ClearMustDoNullCheck();
   }
 }
 
+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 +324,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.cc b/compiler/optimizing/nodes.cc
index 41adc72..47da9cc 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -16,6 +16,7 @@
 
 #include "nodes.h"
 
+#include "code_generator.h"
 #include "ssa_builder.h"
 #include "base/bit_vector-inl.h"
 #include "utils/growable_array.h"
@@ -794,6 +795,84 @@
   }
 }
 
+HConstant* HTypeConversion::TryStaticEvaluation() const {
+  HGraph* graph = GetBlock()->GetGraph();
+  if (GetInput()->IsIntConstant()) {
+    int32_t value = GetInput()->AsIntConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimLong:
+        return graph->GetLongConstant(static_cast<int64_t>(value));
+      case Primitive::kPrimFloat:
+        return graph->GetFloatConstant(static_cast<float>(value));
+      case Primitive::kPrimDouble:
+        return graph->GetDoubleConstant(static_cast<double>(value));
+      default:
+        return nullptr;
+    }
+  } else if (GetInput()->IsLongConstant()) {
+    int64_t value = GetInput()->AsLongConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimInt:
+        return graph->GetIntConstant(static_cast<int32_t>(value));
+      case Primitive::kPrimFloat:
+        return graph->GetFloatConstant(static_cast<float>(value));
+      case Primitive::kPrimDouble:
+        return graph->GetDoubleConstant(static_cast<double>(value));
+      default:
+        return nullptr;
+    }
+  } else if (GetInput()->IsFloatConstant()) {
+    float value = GetInput()->AsFloatConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimInt:
+        if (std::isnan(value))
+          return graph->GetIntConstant(0);
+        if (value >= kPrimIntMax)
+          return graph->GetIntConstant(kPrimIntMax);
+        if (value <= kPrimIntMin)
+          return graph->GetIntConstant(kPrimIntMin);
+        return graph->GetIntConstant(static_cast<int32_t>(value));
+      case Primitive::kPrimLong:
+        if (std::isnan(value))
+          return graph->GetLongConstant(0);
+        if (value >= kPrimLongMax)
+          return graph->GetLongConstant(kPrimLongMax);
+        if (value <= kPrimLongMin)
+          return graph->GetLongConstant(kPrimLongMin);
+        return graph->GetLongConstant(static_cast<int64_t>(value));
+      case Primitive::kPrimDouble:
+        return graph->GetDoubleConstant(static_cast<double>(value));
+      default:
+        return nullptr;
+    }
+  } else if (GetInput()->IsDoubleConstant()) {
+    double value = GetInput()->AsDoubleConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimInt:
+        if (std::isnan(value))
+          return graph->GetIntConstant(0);
+        if (value >= kPrimIntMax)
+          return graph->GetIntConstant(kPrimIntMax);
+        if (value <= kPrimLongMin)
+          return graph->GetIntConstant(kPrimIntMin);
+        return graph->GetIntConstant(static_cast<int32_t>(value));
+      case Primitive::kPrimLong:
+        if (std::isnan(value))
+          return graph->GetLongConstant(0);
+        if (value >= kPrimLongMax)
+          return graph->GetLongConstant(kPrimLongMax);
+        if (value <= kPrimLongMin)
+          return graph->GetLongConstant(kPrimLongMin);
+        return graph->GetLongConstant(static_cast<int64_t>(value));
+      case Primitive::kPrimFloat:
+        return graph->GetFloatConstant(static_cast<float>(value));
+      default:
+        return nullptr;
+    }
+  }
+  return nullptr;
+}
+
 HConstant* HUnaryOperation::TryStaticEvaluation() const {
   if (GetInput()->IsIntConstant()) {
     int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 77b587e..12ace41 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -60,6 +60,8 @@
 static constexpr uint32_t kMaxIntShiftValue = 0x1f;
 static constexpr uint64_t kMaxLongShiftValue = 0x3f;
 
+static constexpr InvokeType kInvalidInvokeType = static_cast<InvokeType>(-1);
+
 enum IfCondition {
   kCondEQ,
   kCondNE,
@@ -120,6 +122,8 @@
   HGraph(ArenaAllocator* arena,
          const DexFile& dex_file,
          uint32_t method_idx,
+         bool should_generate_constructor_barrier,
+         InvokeType invoke_type = kInvalidInvokeType,
          bool debuggable = false,
          int start_instruction_id = 0)
       : arena_(arena),
@@ -137,6 +141,8 @@
         current_instruction_id_(start_instruction_id),
         dex_file_(dex_file),
         method_idx_(method_idx),
+        invoke_type_(invoke_type),
+        should_generate_constructor_barrier_(should_generate_constructor_barrier),
         cached_null_constant_(nullptr),
         cached_int_constants_(std::less<int32_t>(), arena->Adapter()),
         cached_float_constants_(std::less<int32_t>(), arena->Adapter()),
@@ -247,6 +253,10 @@
     has_bounds_checks_ = value;
   }
 
+  bool ShouldGenerateConstructorBarrier() const {
+    return should_generate_constructor_barrier_;
+  }
+
   bool IsDebuggable() const { return debuggable_; }
 
   // Returns a constant of the given type and value. If it does not exist
@@ -277,6 +287,10 @@
     return method_idx_;
   }
 
+  InvokeType GetInvokeType() const {
+    return invoke_type_;
+  }
+
  private:
   void VisitBlockForDominatorTree(HBasicBlock* block,
                                   HBasicBlock* predecessor,
@@ -359,6 +373,11 @@
   // The method index in the dex file.
   const uint32_t method_idx_;
 
+  // If inlined, this encodes how the callee is being invoked.
+  const InvokeType invoke_type_;
+
+  const bool should_generate_constructor_barrier_;
+
   // Cached constants.
   HNullConstant* cached_null_constant_;
   ArenaSafeMap<int32_t, HIntConstant*> cached_int_constants_;
@@ -1093,13 +1112,15 @@
                size_t number_of_vregs,
                const DexFile& dex_file,
                uint32_t method_idx,
-               uint32_t dex_pc)
+               uint32_t dex_pc,
+               InvokeType invoke_type)
      : vregs_(arena, number_of_vregs),
        locations_(arena, number_of_vregs),
        parent_(nullptr),
        dex_file_(dex_file),
        method_idx_(method_idx),
-       dex_pc_(dex_pc) {
+       dex_pc_(dex_pc),
+       invoke_type_(invoke_type) {
     vregs_.SetSize(number_of_vregs);
     for (size_t i = 0; i < number_of_vregs; i++) {
       vregs_.Put(i, HUserRecord<HEnvironment*>());
@@ -1111,16 +1132,20 @@
     }
   }
 
+  HEnvironment(ArenaAllocator* arena, const HEnvironment& to_copy)
+      : HEnvironment(arena,
+                     to_copy.Size(),
+                     to_copy.GetDexFile(),
+                     to_copy.GetMethodIdx(),
+                     to_copy.GetDexPc(),
+                     to_copy.GetInvokeType()) {}
+
   void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
-    parent_ = new (allocator) HEnvironment(allocator,
-                                           parent->Size(),
-                                           parent->GetDexFile(),
-                                           parent->GetMethodIdx(),
-                                           parent->GetDexPc());
+    parent_ = new (allocator) HEnvironment(allocator, *parent);
+    parent_->CopyFrom(parent);
     if (parent->GetParent() != nullptr) {
       parent_->SetAndCopyParentChain(allocator, parent->GetParent());
     }
-    parent_->CopyFrom(parent);
   }
 
   void CopyFrom(const GrowableArray<HInstruction*>& locals);
@@ -1161,6 +1186,10 @@
     return method_idx_;
   }
 
+  InvokeType GetInvokeType() const {
+    return invoke_type_;
+  }
+
   const DexFile& GetDexFile() const {
     return dex_file_;
   }
@@ -1180,6 +1209,7 @@
   const DexFile& dex_file_;
   const uint32_t method_idx_;
   const uint32_t dex_pc_;
+  const InvokeType invoke_type_;
 
   friend class HInstruction;
 
@@ -1393,12 +1423,7 @@
   // copying, the uses lists are being updated.
   void CopyEnvironmentFrom(HEnvironment* environment) {
     ArenaAllocator* allocator = GetBlock()->GetGraph()->GetArena();
-    environment_ = new (allocator) HEnvironment(
-        allocator,
-        environment->Size(),
-        environment->GetDexFile(),
-        environment->GetMethodIdx(),
-        environment->GetDexPc());
+    environment_ = new (allocator) HEnvironment(allocator, *environment);
     environment_->CopyFrom(environment);
     if (environment->GetParent() != nullptr) {
       environment_->SetAndCopyParentChain(allocator, environment->GetParent());
@@ -1408,16 +1433,11 @@
   void CopyEnvironmentFromWithLoopPhiAdjustment(HEnvironment* environment,
                                                 HBasicBlock* block) {
     ArenaAllocator* allocator = GetBlock()->GetGraph()->GetArena();
-    environment_ = new (allocator) HEnvironment(
-        allocator,
-        environment->Size(),
-        environment->GetDexFile(),
-        environment->GetMethodIdx(),
-        environment->GetDexPc());
+    environment_ = new (allocator) HEnvironment(allocator, *environment);
+    environment_->CopyFromWithLoopPhiAdjustment(environment, block);
     if (environment->GetParent() != nullptr) {
       environment_->SetAndCopyParentChain(allocator, environment->GetParent());
     }
-    environment_->CopyFromWithLoopPhiAdjustment(environment, block);
   }
 
   // Returns the number of entries in the environment. Typically, that is the
@@ -2197,15 +2217,16 @@
   size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
 
   bool IsMinusOne() const OVERRIDE {
-    return bit_cast<uint32_t, float>(AsFloatConstant()->GetValue()) ==
-        bit_cast<uint32_t, float>((-1.0f));
+    return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f));
   }
   bool IsZero() const OVERRIDE {
-    return AsFloatConstant()->GetValue() == 0.0f;
+    return value_ == 0.0f;
   }
   bool IsOne() const OVERRIDE {
-    return bit_cast<uint32_t, float>(AsFloatConstant()->GetValue()) ==
-        bit_cast<uint32_t, float>(1.0f);
+    return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
+  }
+  bool IsNaN() const {
+    return std::isnan(value_);
   }
 
   DECLARE_INSTRUCTION(FloatConstant);
@@ -2235,15 +2256,16 @@
   size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
 
   bool IsMinusOne() const OVERRIDE {
-    return bit_cast<uint64_t, double>(AsDoubleConstant()->GetValue()) ==
-        bit_cast<uint64_t, double>((-1.0));
+    return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0));
   }
   bool IsZero() const OVERRIDE {
-    return AsDoubleConstant()->GetValue() == 0.0;
+    return value_ == 0.0;
   }
   bool IsOne() const OVERRIDE {
-    return bit_cast<uint64_t, double>(AsDoubleConstant()->GetValue()) ==
-        bit_cast<uint64_t, double>(1.0);
+    return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0);
+  }
+  bool IsNaN() const {
+    return std::isnan(value_);
   }
 
   DECLARE_INSTRUCTION(DoubleConstant);
@@ -2366,6 +2388,8 @@
 
   uint32_t GetDexMethodIndex() const { return dex_method_index_; }
 
+  InvokeType GetOriginalInvokeType() const { return original_invoke_type_; }
+
   Intrinsics GetIntrinsic() const {
     return intrinsic_;
   }
@@ -2382,13 +2406,15 @@
           uint32_t number_of_other_inputs,
           Primitive::Type return_type,
           uint32_t dex_pc,
-          uint32_t dex_method_index)
+          uint32_t dex_method_index,
+          InvokeType original_invoke_type)
     : HInstruction(SideEffects::All()),
       number_of_arguments_(number_of_arguments),
       inputs_(arena, number_of_arguments),
       return_type_(return_type),
       dex_pc_(dex_pc),
       dex_method_index_(dex_method_index),
+      original_invoke_type_(original_invoke_type),
       intrinsic_(Intrinsics::kNone) {
     uint32_t number_of_inputs = number_of_arguments + number_of_other_inputs;
     inputs_.SetSize(number_of_inputs);
@@ -2404,6 +2430,7 @@
   const Primitive::Type return_type_;
   const uint32_t dex_pc_;
   const uint32_t dex_method_index_;
+  const InvokeType original_invoke_type_;
   Intrinsics intrinsic_;
 
  private:
@@ -2435,8 +2462,8 @@
                 clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 1u : 0u,
                 return_type,
                 dex_pc,
-                dex_method_index),
-        original_invoke_type_(original_invoke_type),
+                dex_method_index,
+                original_invoke_type),
         invoke_type_(invoke_type),
         is_recursive_(is_recursive),
         clinit_check_requirement_(clinit_check_requirement),
@@ -2449,7 +2476,6 @@
     return false;
   }
 
-  InvokeType GetOriginalInvokeType() const { return original_invoke_type_; }
   InvokeType GetInvokeType() const { return invoke_type_; }
   bool IsRecursive() const { return is_recursive_; }
   bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); }
@@ -2507,7 +2533,6 @@
   }
 
  private:
-  const InvokeType original_invoke_type_;
   const InvokeType invoke_type_;
   const bool is_recursive_;
   ClinitCheckRequirement clinit_check_requirement_;
@@ -2526,7 +2551,7 @@
                  uint32_t dex_pc,
                  uint32_t dex_method_index,
                  uint32_t vtable_index)
-      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index),
+      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kVirtual),
         vtable_index_(vtable_index) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -2552,7 +2577,7 @@
                    uint32_t dex_pc,
                    uint32_t dex_method_index,
                    uint32_t imt_index)
-      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index),
+      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kInterface),
         imt_index_(imt_index) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -2900,6 +2925,8 @@
 
   bool CanBeNull() const OVERRIDE { return !is_this_; }
 
+  bool IsThis() const { return is_this_; }
+
   DECLARE_INSTRUCTION(ParameterValue);
 
  private:
@@ -2980,6 +3007,10 @@
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
 
+  // Try to statically evaluate the conversion and return a HConstant
+  // containing the result.  If the input cannot be converted, return nullptr.
+  HConstant* TryStaticEvaluation() const;
+
   DECLARE_INSTRUCTION(TypeConversion);
 
  private:
@@ -3157,7 +3188,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);
   }
@@ -3171,11 +3203,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);
 };
@@ -3224,7 +3259,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);
@@ -3246,6 +3282,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_; }
@@ -3271,6 +3312,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);
 };
@@ -3417,8 +3459,8 @@
     return generate_clinit_check_;
   }
 
-  void SetMustGenerateClinitCheck() {
-    generate_clinit_check_ = true;
+  void SetMustGenerateClinitCheck(bool generate_clinit_check) {
+    generate_clinit_check_ = generate_clinit_check;
   }
 
   bool CanCallRuntime() const {
@@ -3571,7 +3613,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);
   }
@@ -3582,11 +3625,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);
 };
@@ -3889,7 +3935,9 @@
       }
       for (size_t i = 0, e = moves_.Size(); i < e; ++i) {
         DCHECK(!destination.OverlapsWith(moves_.Get(i).GetDestination()))
-            << "Overlapped destination for two moves in a parallel move.";
+            << "Overlapped destination for two moves in a parallel move: "
+            << moves_.Get(i).GetSource() << " ==> " << moves_.Get(i).GetDestination() << " and "
+            << source << " ==> " << destination;
       }
     }
     moves_.Add(MoveOperands(source, destination, type, instruction));
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index 2736453..782cde4 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -51,7 +51,7 @@
   exit_block->AddInstruction(new (&allocator) HExit());
 
   HEnvironment* environment = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic);
   null_check->SetRawEnvironment(environment);
   environment->SetRawEnvAt(0, parameter);
   parameter->AddEnvUseAt(null_check->GetEnvironment(), 0);
@@ -132,7 +132,7 @@
   ASSERT_TRUE(parameter1->GetUses().HasOnlyOneUse());
 
   HEnvironment* environment = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic);
   GrowableArray<HInstruction*> array(&allocator, 1);
   array.Add(parameter1);
 
@@ -143,13 +143,13 @@
   ASSERT_TRUE(parameter1->GetEnvUses().HasOnlyOneUse());
 
   HEnvironment* parent1 = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic);
   parent1->CopyFrom(array);
 
   ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 2u);
 
   HEnvironment* parent2 = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic);
   parent2->CopyFrom(array);
   parent1->SetAndCopyParentChain(&allocator, parent2);
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8bb5d8e..b2e8ecd 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -512,9 +512,14 @@
     class_def_idx, method_idx, access_flags,
     compiler_driver->GetVerifiedMethod(&dex_file, method_idx));
 
+  bool requires_barrier = dex_compilation_unit.IsConstructor()
+      && compiler_driver->RequiresConstructorBarrier(Thread::Current(),
+                                                     dex_compilation_unit.GetDexFile(),
+                                                     dex_compilation_unit.GetClassDefIndex());
   ArenaAllocator arena(Runtime::Current()->GetArenaPool());
   HGraph* graph = new (&arena) HGraph(
-      &arena, dex_file, method_idx, compiler_driver->GetCompilerOptions().GetDebuggable());
+      &arena, dex_file, method_idx, requires_barrier, kInvalidInvokeType,
+      compiler_driver->GetCompilerOptions().GetDebuggable());
 
   // For testing purposes, we put a special marker on method names that should be compiled
   // with this compiler. This makes sure we're not regressing.
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 4f8ec65..1fe9346 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -74,7 +74,7 @@
 
 inline HGraph* CreateGraph(ArenaAllocator* allocator) {
   return new (allocator) HGraph(
-      allocator, *reinterpret_cast<DexFile*>(allocator->Alloc(sizeof(DexFile))), -1);
+      allocator, *reinterpret_cast<DexFile*>(allocator->Alloc(sizeof(DexFile))), -1, false);
 }
 
 // Create a control-flow graph from Dex instructions.
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 78d1185..538736b 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -53,7 +53,7 @@
   if (check->GetPrevious() == cls) {
     // Pass the initialization duty to the `HLoadClass` instruction,
     // and remove the instruction from the graph.
-    cls->SetMustGenerateClinitCheck();
+    cls->SetMustGenerateClinitCheck(true);
     check->GetBlock()->RemoveInstruction(check);
   }
 }
@@ -82,8 +82,15 @@
 void PrepareForRegisterAllocation::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
   if (invoke->IsStaticWithExplicitClinitCheck()) {
     size_t last_input_index = invoke->InputCount() - 1;
-    HInstruction* last_input = invoke->InputAt(last_input_index);
-    DCHECK(last_input->IsLoadClass()) << last_input->DebugName();
+    HLoadClass* last_input = invoke->InputAt(last_input_index)->AsLoadClass();
+    DCHECK(last_input != nullptr)
+        << "Last input is not HLoadClass. It is " << last_input->DebugName();
+
+    // The static call will initialize the class so there's no need for a clinit check if
+    // it's the first user.
+    if (last_input == invoke->GetPrevious()) {
+      last_input->SetMustGenerateClinitCheck(false);
+    }
 
     // Remove a load class instruction as last input of a static
     // invoke, which has been added (along with a clinit check,
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index f53f846..925099a 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -775,7 +775,7 @@
     } else if (current->IsLowInterval()) {
       reg = FindAvailableRegisterPair(free_until, current->GetStart());
     } else {
-      reg = FindAvailableRegister(free_until);
+      reg = FindAvailableRegister(free_until, current);
     }
   }
 
@@ -839,14 +839,52 @@
   return reg;
 }
 
-int RegisterAllocator::FindAvailableRegister(size_t* next_use) const {
+bool RegisterAllocator::IsCallerSaveRegister(int reg) const {
+  return processing_core_registers_
+      ? !codegen_->IsCoreCalleeSaveRegister(reg)
+      : !codegen_->IsFloatingPointCalleeSaveRegister(reg);
+}
+
+int RegisterAllocator::FindAvailableRegister(size_t* next_use, LiveInterval* current) const {
+  // We special case intervals that do not span a safepoint to try to find a caller-save
+  // register if one is available. We iterate from 0 to the number of registers,
+  // so if there are caller-save registers available at the end, we continue the iteration.
+  bool prefers_caller_save = !current->HasWillCallSafepoint();
   int reg = kNoRegister;
-  // Pick the register that is used the last.
   for (size_t i = 0; i < number_of_registers_; ++i) {
-    if (IsBlocked(i)) continue;
-    if (reg == kNoRegister || next_use[i] > next_use[reg]) {
+    if (IsBlocked(i)) {
+      // Register cannot be used. Continue.
+      continue;
+    }
+
+    // Best case: we found a register fully available.
+    if (next_use[i] == kMaxLifetimePosition) {
+      if (prefers_caller_save && !IsCallerSaveRegister(i)) {
+        // We can get shorter encodings on some platforms by using
+        // small register numbers. So only update the candidate if the previous
+        // one was not available for the whole method.
+        if (reg == kNoRegister || next_use[reg] != kMaxLifetimePosition) {
+          reg = i;
+        }
+        // Continue the iteration in the hope of finding a caller save register.
+        continue;
+      } else {
+        reg = i;
+        // We know the register is good enough. Return it.
+        break;
+      }
+    }
+
+    // If we had no register before, take this one as a reference.
+    if (reg == kNoRegister) {
       reg = i;
-      if (next_use[i] == kMaxLifetimePosition) break;
+      continue;
+    }
+
+    // Pick the register that is used the last.
+    if (next_use[i] > next_use[reg]) {
+      reg = i;
+      continue;
     }
   }
   return reg;
@@ -971,7 +1009,7 @@
       || (first_use >= next_use[GetHighForLowRegister(reg)]);
   } else {
     DCHECK(!current->IsHighInterval());
-    reg = FindAvailableRegister(next_use);
+    reg = FindAvailableRegister(next_use, current);
     should_spill = (first_use >= next_use[reg]);
   }
 
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index dc9c708..6d5bfc3 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -140,7 +140,8 @@
   void DumpInterval(std::ostream& stream, LiveInterval* interval) const;
   void DumpAllIntervals(std::ostream& stream) const;
   int FindAvailableRegisterPair(size_t* next_use, size_t starting_at) const;
-  int FindAvailableRegister(size_t* next_use) const;
+  int FindAvailableRegister(size_t* next_use, LiveInterval* current) const;
+  bool IsCallerSaveRegister(int reg) const;
 
   // Try splitting an active non-pair or unaligned pair interval at the given `position`.
   // Returns whether it was successful at finding such an interval.
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 59a2852..c51d248 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -504,7 +504,7 @@
     // typed and the value in a dex register will not be used for both floating point and
     // non-floating point operations. So the only reason an instruction would want a floating
     // point equivalent is for an unused phi that will be removed by the dead phi elimination phase.
-    DCHECK(user->IsPhi());
+    DCHECK(user->IsPhi()) << "is actually " << user->DebugName() << " (" << user->GetId() << ")";
     return value;
   }
 }
@@ -547,7 +547,8 @@
       current_locals_->Size(),
       GetGraph()->GetDexFile(),
       GetGraph()->GetMethodIdx(),
-      instruction->GetDexPc());
+      instruction->GetDexPc(),
+      GetGraph()->GetInvokeType());
   environment->CopyFrom(*current_locals_);
   instruction->SetRawEnvironment(environment);
 }
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 82c5454..4b19c5b 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -76,7 +76,7 @@
   }
 
   void Dump(std::ostream& stream) const {
-    stream << "[" << start_ << ", " << end_ << ")";
+    stream << "[" << start_ << "," << end_ << ")";
   }
 
   LiveRange* Dup(ArenaAllocator* allocator) const {
@@ -542,6 +542,15 @@
     return defined_by_;
   }
 
+  bool HasWillCallSafepoint() const {
+    for (SafepointPosition* safepoint = first_safepoint_;
+         safepoint != nullptr;
+         safepoint = safepoint->GetNext()) {
+      if (safepoint->GetLocations()->WillCall()) return true;
+    }
+    return false;
+  }
+
   SafepointPosition* FindSafepointJustBefore(size_t position) const {
     for (SafepointPosition* safepoint = first_safepoint_, *previous = nullptr;
          safepoint != nullptr;
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 8344fc3..b446815 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include "stack_map_stream.h"
 
 namespace art {
@@ -52,6 +51,7 @@
   dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
   native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
   register_mask_max_ = std::max(register_mask_max_, register_mask);
+  current_dex_register_ = 0;
 }
 
 void StackMapStream::EndStackMapEntry() {
@@ -60,11 +60,7 @@
   current_entry_ = StackMapEntry();
 }
 
-void StackMapStream::AddDexRegisterEntry(uint16_t dex_register,
-                                         DexRegisterLocation::Kind kind,
-                                         int32_t value) {
-  DCHECK_LT(dex_register, current_entry_.num_dex_registers);
-
+void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
   if (kind != DexRegisterLocation::Kind::kNone) {
     // Ensure we only use non-compressed location kind at this stage.
     DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
@@ -87,18 +83,49 @@
       location_catalog_entries_indices_.Insert(std::make_pair(location, index));
     }
 
-    current_entry_.live_dex_registers_mask->SetBit(dex_register);
-    current_entry_.dex_register_map_hash +=
-      (1 << (dex_register % (sizeof(current_entry_.dex_register_map_hash) * kBitsPerByte)));
-    current_entry_.dex_register_map_hash += static_cast<uint32_t>(value);
-    current_entry_.dex_register_map_hash += static_cast<uint32_t>(kind);
+    if (in_inline_frame_) {
+      // TODO: Support sharing DexRegisterMap across InlineInfo.
+      DCHECK_LT(current_dex_register_, current_inline_info_.num_dex_registers);
+      current_inline_info_.live_dex_registers_mask->SetBit(current_dex_register_);
+    } else {
+      DCHECK_LT(current_dex_register_, current_entry_.num_dex_registers);
+      current_entry_.live_dex_registers_mask->SetBit(current_dex_register_);
+      current_entry_.dex_register_map_hash += (1 <<
+          (current_dex_register_ % (sizeof(current_entry_.dex_register_map_hash) * kBitsPerByte)));
+      current_entry_.dex_register_map_hash += static_cast<uint32_t>(value);
+      current_entry_.dex_register_map_hash += static_cast<uint32_t>(kind);
+    }
   }
+  current_dex_register_++;
 }
 
-void StackMapStream::AddInlineInfoEntry(uint32_t method_index) {
-  InlineInfoEntry entry;
-  entry.method_index = method_index;
-  inline_infos_.Add(entry);
+void StackMapStream::BeginInlineInfoEntry(uint32_t method_index,
+                                          uint32_t dex_pc,
+                                          InvokeType invoke_type,
+                                          uint32_t num_dex_registers) {
+  DCHECK(!in_inline_frame_);
+  in_inline_frame_ = true;
+  current_inline_info_.method_index = method_index;
+  current_inline_info_.dex_pc = dex_pc;
+  current_inline_info_.invoke_type = invoke_type;
+  current_inline_info_.num_dex_registers = num_dex_registers;
+  current_inline_info_.dex_register_locations_start_index = dex_register_locations_.Size();
+  if (num_dex_registers != 0) {
+    current_inline_info_.live_dex_registers_mask =
+        new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
+  } else {
+    current_inline_info_.live_dex_registers_mask = nullptr;
+  }
+  current_dex_register_ = 0;
+}
+
+void StackMapStream::EndInlineInfoEntry() {
+  DCHECK(in_inline_frame_);
+  DCHECK_EQ(current_dex_register_, current_inline_info_.num_dex_registers)
+      << "Inline information contains less registers than expected";
+  in_inline_frame_ = false;
+  inline_infos_.Add(current_inline_info_);
+  current_inline_info_ = InlineInfoEntry();
 }
 
 size_t StackMapStream::PrepareForFillIn() {
@@ -142,17 +169,18 @@
   return size;
 }
 
-size_t StackMapStream::ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
+size_t StackMapStream::ComputeDexRegisterMapSize(uint32_t num_dex_registers,
+                                                 const BitVector& live_dex_registers_mask) const {
   // Size of the map in bytes.
   size_t size = DexRegisterMap::kFixedSize;
   // Add the live bit mask for the Dex register liveness.
-  size += DexRegisterMap::GetLiveBitMaskSize(entry.num_dex_registers);
+  size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers);
   // Compute the size of the set of live Dex register entries.
   size_t number_of_live_dex_registers = 0;
   for (size_t dex_register_number = 0;
-       dex_register_number < entry.num_dex_registers;
+       dex_register_number < num_dex_registers;
        ++dex_register_number) {
-    if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
+    if (live_dex_registers_mask.IsBitSet(dex_register_number)) {
       ++number_of_live_dex_registers;
     }
   }
@@ -167,11 +195,18 @@
 
 size_t StackMapStream::ComputeDexRegisterMapsSize() const {
   size_t size = 0;
+  size_t inline_info_index = 0;
   for (size_t i = 0; i < stack_maps_.Size(); ++i) {
     StackMapEntry entry = stack_maps_.Get(i);
     if (entry.same_dex_register_map_as_ == kNoSameDexMapFound) {
+      size += ComputeDexRegisterMapSize(entry.num_dex_registers, *entry.live_dex_registers_mask);
+    } else {
       // Entries with the same dex map will have the same offset.
-      size += ComputeDexRegisterMapSize(entry);
+    }
+    for (size_t j = 0; j < entry.inlining_depth; ++j) {
+      InlineInfoEntry inline_entry = inline_infos_.Get(inline_info_index++);
+      size += ComputeDexRegisterMapSize(inline_entry.num_dex_registers,
+                                        *inline_entry.live_dex_registers_mask);
     }
   }
   return size;
@@ -247,34 +282,19 @@
                      .GetDexRegisterMapOffset(code_info));
       } else {
         // New dex registers maps should be added to the stack map.
-        MemoryRegion register_region =
-            dex_register_locations_region.Subregion(
-                next_dex_register_map_offset,
-                ComputeDexRegisterMapSize(entry));
+        MemoryRegion register_region = dex_register_locations_region.Subregion(
+            next_dex_register_map_offset,
+            ComputeDexRegisterMapSize(entry.num_dex_registers, *entry.live_dex_registers_mask));
         next_dex_register_map_offset += register_region.size();
         DexRegisterMap dex_register_map(register_region);
         stack_map.SetDexRegisterMapOffset(
           code_info, register_region.start() - dex_register_locations_region.start());
 
-        // Set the live bit mask.
-        dex_register_map.SetLiveBitMask(entry.num_dex_registers, *entry.live_dex_registers_mask);
-
-        // Set the dex register location mapping data.
-        for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
-             dex_register_number < entry.num_dex_registers;
-             ++dex_register_number) {
-          if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
-            size_t location_catalog_entry_index =
-                dex_register_locations_.Get(entry.dex_register_locations_start_index
-                                            + index_in_dex_register_locations);
-            dex_register_map.SetLocationCatalogEntryIndex(
-                index_in_dex_register_locations,
-                location_catalog_entry_index,
-                entry.num_dex_registers,
-                location_catalog_entries_.Size());
-            ++index_in_dex_register_locations;
-          }
-        }
+        // Set the dex register location.
+        FillInDexRegisterMap(dex_register_map,
+                             entry.num_dex_registers,
+                             *entry.live_dex_registers_mask,
+                             entry.dex_register_locations_start_index);
       }
     }
 
@@ -291,9 +311,30 @@
           code_info, inline_region.start() - dex_register_locations_region.start());
 
       inline_info.SetDepth(entry.inlining_depth);
-      for (size_t j = 0; j < entry.inlining_depth; ++j) {
-        InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
-        inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
+      for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
+        InlineInfoEntry inline_entry = inline_infos_.Get(depth + entry.inline_infos_start_index);
+        inline_info.SetMethodIndexAtDepth(depth, inline_entry.method_index);
+        inline_info.SetDexPcAtDepth(depth, inline_entry.dex_pc);
+        inline_info.SetInvokeTypeAtDepth(depth, inline_entry.invoke_type);
+        if (inline_entry.num_dex_registers == 0) {
+          // No dex map available.
+          inline_info.SetDexRegisterMapOffsetAtDepth(depth, StackMap::kNoDexRegisterMap);
+          DCHECK(inline_entry.live_dex_registers_mask == nullptr);
+        } else {
+          MemoryRegion register_region = dex_register_locations_region.Subregion(
+              next_dex_register_map_offset,
+              ComputeDexRegisterMapSize(inline_entry.num_dex_registers,
+                                        *inline_entry.live_dex_registers_mask));
+          next_dex_register_map_offset += register_region.size();
+          DexRegisterMap dex_register_map(register_region);
+          inline_info.SetDexRegisterMapOffsetAtDepth(
+            depth, register_region.start() - dex_register_locations_region.start());
+
+          FillInDexRegisterMap(dex_register_map,
+                               inline_entry.num_dex_registers,
+                               *inline_entry.live_dex_registers_mask,
+                               inline_entry.dex_register_locations_start_index);
+        }
       }
     } else {
       if (inline_info_size_ != 0) {
@@ -303,6 +344,28 @@
   }
 }
 
+void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map,
+                                          uint32_t num_dex_registers,
+                                          const BitVector& live_dex_registers_mask,
+                                          uint32_t start_index_in_dex_register_locations) const {
+  dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask);
+  // Set the dex register location mapping data.
+  for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
+       dex_register_number < num_dex_registers;
+       ++dex_register_number) {
+    if (live_dex_registers_mask.IsBitSet(dex_register_number)) {
+      size_t location_catalog_entry_index = dex_register_locations_.Get(
+          start_index_in_dex_register_locations + index_in_dex_register_locations);
+      dex_register_map.SetLocationCatalogEntryIndex(
+          index_in_dex_register_locations,
+          location_catalog_entry_index,
+          num_dex_registers,
+          location_catalog_entries_.Size());
+      ++index_in_dex_register_locations;
+    }
+  }
+}
+
 size_t StackMapStream::FindEntryWithTheSameDexMap() {
   size_t current_entry_index = stack_maps_.Size();
   auto entries_it = dex_map_hash_to_stack_map_indices_.find(current_entry_.dex_register_map_hash);
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 0c626be..0af983b 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -72,6 +72,7 @@
         number_of_stack_maps_with_inline_info_(0),
         dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter()),
         current_entry_(),
+        current_inline_info_(),
         stack_mask_size_(0),
         inline_info_size_(0),
         dex_register_maps_size_(0),
@@ -81,7 +82,9 @@
         stack_maps_start_(0),
         dex_register_maps_start_(0),
         inline_infos_start_(0),
-        needed_size_(0) {}
+        needed_size_(0),
+        current_dex_register_(0),
+        in_inline_frame_(false) {}
 
   // See runtime/stack_map.h to know what these fields contain.
   struct StackMapEntry {
@@ -99,7 +102,12 @@
   };
 
   struct InlineInfoEntry {
+    uint32_t dex_pc;
     uint32_t method_index;
+    InvokeType invoke_type;
+    uint32_t num_dex_registers;
+    BitVector* live_dex_registers_mask;
+    size_t dex_register_locations_start_index;
   };
 
   void BeginStackMapEntry(uint32_t dex_pc,
@@ -110,11 +118,13 @@
                           uint8_t inlining_depth);
   void EndStackMapEntry();
 
-  void AddDexRegisterEntry(uint16_t dex_register,
-                           DexRegisterLocation::Kind kind,
-                           int32_t value);
+  void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value);
 
-  void AddInlineInfoEntry(uint32_t method_index);
+  void BeginInlineInfoEntry(uint32_t method_index,
+                            uint32_t dex_pc,
+                            InvokeType invoke_type,
+                            uint32_t num_dex_registers);
+  void EndInlineInfoEntry();
 
   // Prepares the stream to fill in a memory region. Must be called before FillIn.
   // Returns the size (in bytes) needed to store this stream.
@@ -123,7 +133,8 @@
 
  private:
   size_t ComputeDexRegisterLocationCatalogSize() const;
-  size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const;
+  size_t ComputeDexRegisterMapSize(uint32_t num_dex_registers,
+                                   const BitVector& live_dex_registers_mask) const;
   size_t ComputeDexRegisterMapsSize() const;
   size_t ComputeInlineInfoSize() const;
 
@@ -131,6 +142,10 @@
   // or kNoSameDexMapFound if no such entry exists.
   size_t FindEntryWithTheSameDexMap();
   bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const;
+  void FillInDexRegisterMap(DexRegisterMap dex_register_map,
+                            uint32_t num_dex_registers,
+                            const BitVector& live_dex_registers_mask,
+                            uint32_t start_index_in_dex_register_locations) const;
 
   ArenaAllocator* allocator_;
   GrowableArray<StackMapEntry> stack_maps_;
@@ -155,6 +170,7 @@
   ArenaSafeMap<uint32_t, GrowableArray<uint32_t>> dex_map_hash_to_stack_map_indices_;
 
   StackMapEntry current_entry_;
+  InlineInfoEntry current_inline_info_;
   size_t stack_mask_size_;
   size_t inline_info_size_;
   size_t dex_register_maps_size_;
@@ -165,6 +181,8 @@
   size_t dex_register_maps_start_;
   size_t inline_infos_start_;
   size_t needed_size_;
+  uint32_t current_dex_register_;
+  bool in_inline_frame_;
 
   static constexpr uint32_t kNoSameDexMapFound = -1;
 
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 3291a77..98e14ea 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -41,8 +41,8 @@
   ArenaBitVector sp_mask(&arena, 0, false);
   size_t number_of_dex_registers = 2;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInStack, 0);         // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);       // Short location.
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Short location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -124,19 +124,22 @@
   sp_mask1.SetBit(2);
   sp_mask1.SetBit(4);
   size_t number_of_dex_registers = 2;
+  size_t number_of_dex_registers_in_inline_info = 0;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2);
-  stream.AddDexRegisterEntry(0, Kind::kInStack, 0);         // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);       // Large location.
-  stream.AddInlineInfoEntry(42);
-  stream.AddInlineInfoEntry(82);
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
+  stream.BeginInlineInfoEntry(82, 3, kDirect, number_of_dex_registers_in_inline_info);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(42, 2, kStatic, number_of_dex_registers_in_inline_info);
+  stream.EndInlineInfoEntry();
   stream.EndStackMapEntry();
 
   ArenaBitVector sp_mask2(&arena, 0, true);
   sp_mask2.SetBit(3);
   sp_mask1.SetBit(8);
   stream.BeginStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 18);     // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kInFpuRegister, 3);   // Short location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 18);     // Short location.
+  stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3);   // Short location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -211,8 +214,12 @@
     ASSERT_TRUE(stack_map.HasInlineInfo(code_info));
     InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
     ASSERT_EQ(2u, inline_info.GetDepth());
-    ASSERT_EQ(42u, inline_info.GetMethodReferenceIndexAtDepth(0));
-    ASSERT_EQ(82u, inline_info.GetMethodReferenceIndexAtDepth(1));
+    ASSERT_EQ(82u, inline_info.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(42u, inline_info.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(0));
+    ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(1));
+    ASSERT_EQ(kDirect, inline_info.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(kStatic, inline_info.GetInvokeTypeAtDepth(1));
   }
 
   // Second stack map.
@@ -277,8 +284,8 @@
   ArenaBitVector sp_mask(&arena, 0, false);
   uint32_t number_of_dex_registers = 2;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kNone, 0);            // No location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);       // Large location.
+  stream.AddDexRegisterEntry(Kind::kNone, 0);            // No location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -364,13 +371,13 @@
     // as using a single value (in the whole CodeInfo object) would
     // make this Dex register mapping data empty (see
     // art::DexRegisterMap::SingleEntrySizeInBits).
-    stream.AddDexRegisterEntry(i, Kind::kConstant, i % 2);  // Short location.
+    stream.AddDexRegisterEntry(Kind::kConstant, i % 2);  // Short location.
   }
   stream.EndStackMapEntry();
   // Create the second stack map (and its Dex register map).
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
   for (uint32_t i = 0; i < number_of_dex_registers; ++i) {
-    stream.AddDexRegisterEntry(i, Kind::kConstant, 0);  // Short location.
+    stream.AddDexRegisterEntry(Kind::kConstant, 0);  // Short location.
   }
   stream.EndStackMapEntry();
 
@@ -420,18 +427,18 @@
   uint32_t number_of_dex_registers = 2;
   // First stack map.
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 0);  // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);   // Large location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 0);  // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
   stream.EndStackMapEntry();
   // Second stack map, which should share the same dex register map.
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 0);  // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);   // Large location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 0);  // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
   stream.EndStackMapEntry();
   // Third stack map (doesn't share the dex register map).
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 2);  // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);   // Large location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 2);  // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -500,4 +507,175 @@
   ASSERT_FALSE(stack_map.HasInlineInfo(code_info));
 }
 
+TEST(StackMapTest, InlineTest) {
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  StackMapStream stream(&arena);
+
+  ArenaBitVector sp_mask1(&arena, 0, true);
+  sp_mask1.SetBit(2);
+  sp_mask1.SetBit(4);
+
+  // First stack map.
+  stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, 2, 2);
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);
+  stream.AddDexRegisterEntry(Kind::kConstant, 4);
+
+  stream.BeginInlineInfoEntry(42, 2, kStatic, 1);
+  stream.AddDexRegisterEntry(Kind::kInStack, 8);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(82, 3, kStatic, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 16);
+  stream.AddDexRegisterEntry(Kind::kConstant, 20);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 15);
+  stream.EndInlineInfoEntry();
+
+  stream.EndStackMapEntry();
+
+  // Second stack map.
+  stream.BeginStackMapEntry(2, 22, 0x3, &sp_mask1, 2, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 56);
+  stream.AddDexRegisterEntry(Kind::kConstant, 0);
+
+  stream.BeginInlineInfoEntry(42, 2, kDirect, 1);
+  stream.AddDexRegisterEntry(Kind::kInStack, 12);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(82, 3, kStatic, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 80);
+  stream.AddDexRegisterEntry(Kind::kConstant, 10);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 5);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(52, 5, kVirtual, 0);
+  stream.EndInlineInfoEntry();
+
+  stream.EndStackMapEntry();
+
+  // Third stack map.
+  stream.BeginStackMapEntry(4, 56, 0x3, &sp_mask1, 2, 0);
+  stream.AddDexRegisterEntry(Kind::kNone, 0);
+  stream.AddDexRegisterEntry(Kind::kConstant, 4);
+  stream.EndStackMapEntry();
+
+  // Fourth stack map.
+  stream.BeginStackMapEntry(6, 78, 0x3, &sp_mask1, 2, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 56);
+  stream.AddDexRegisterEntry(Kind::kConstant, 0);
+
+  stream.BeginInlineInfoEntry(42, 2, kVirtual, 0);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(52, 5, kInterface, 1);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 2);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(52, 10, kStatic, 2);
+  stream.AddDexRegisterEntry(Kind::kNone, 0);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 3);
+  stream.EndInlineInfoEntry();
+
+  stream.EndStackMapEntry();
+
+  size_t size = stream.PrepareForFillIn();
+  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  MemoryRegion region(memory, size);
+  stream.FillIn(region);
+
+  CodeInfo ci(region);
+
+  {
+    // Verify first stack map.
+    StackMap sm0 = ci.GetStackMapAt(0);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, 2);
+    ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0, 2, ci));
+    ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci));
+
+    InlineInfo if0 = ci.GetInlineInfoOf(sm0);
+    ASSERT_EQ(2u, if0.GetDepth());
+    ASSERT_EQ(2u, if0.GetDexPcAtDepth(0));
+    ASSERT_EQ(42u, if0.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(3u, if0.GetDexPcAtDepth(1));
+    ASSERT_EQ(82u, if0.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(1));
+
+    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, 1);
+    ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci));
+
+    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, 3);
+    ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0, 3, ci));
+    ASSERT_EQ(20, dex_registers2.GetConstant(1, 3, ci));
+    ASSERT_EQ(15, dex_registers2.GetMachineRegister(2, 3, ci));
+  }
+
+  {
+    // Verify second stack map.
+    StackMap sm1 = ci.GetStackMapAt(1);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1, 2);
+    ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci));
+    ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci));
+
+    InlineInfo if1 = ci.GetInlineInfoOf(sm1);
+    ASSERT_EQ(3u, if1.GetDepth());
+    ASSERT_EQ(2u, if1.GetDexPcAtDepth(0));
+    ASSERT_EQ(42u, if1.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(kDirect, if1.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(3u, if1.GetDexPcAtDepth(1));
+    ASSERT_EQ(82u, if1.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(kStatic, if1.GetInvokeTypeAtDepth(1));
+    ASSERT_EQ(5u, if1.GetDexPcAtDepth(2));
+    ASSERT_EQ(52u, if1.GetMethodIndexAtDepth(2));
+    ASSERT_EQ(kVirtual, if1.GetInvokeTypeAtDepth(2));
+
+    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, 1);
+    ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci));
+
+    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, 3);
+    ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0, 3, ci));
+    ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci));
+    ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci));
+
+    ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2));
+  }
+
+  {
+    // Verify third stack map.
+    StackMap sm2 = ci.GetStackMapAt(2);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2, 2);
+    ASSERT_FALSE(dex_registers0.IsDexRegisterLive(0));
+    ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci));
+    ASSERT_FALSE(sm2.HasInlineInfo(ci));
+  }
+
+  {
+    // Verify fourth stack map.
+    StackMap sm3 = ci.GetStackMapAt(3);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3, 2);
+    ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci));
+    ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci));
+
+    InlineInfo if2 = ci.GetInlineInfoOf(sm3);
+    ASSERT_EQ(3u, if2.GetDepth());
+    ASSERT_EQ(2u, if2.GetDexPcAtDepth(0));
+    ASSERT_EQ(42u, if2.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(kVirtual, if2.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(5u, if2.GetDexPcAtDepth(1));
+    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(kInterface, if2.GetInvokeTypeAtDepth(1));
+    ASSERT_EQ(10u, if2.GetDexPcAtDepth(2));
+    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(2));
+    ASSERT_EQ(kStatic, if2.GetInvokeTypeAtDepth(2));
+
+    ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0));
+
+    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, 1);
+    ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci));
+
+    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, 2);
+    ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0));
+    ASSERT_EQ(3, dex_registers2.GetMachineRegister(1, 2, ci));
+  }
+}
+
 }  // namespace art
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index c410660..eca6f5a 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -860,8 +860,6 @@
   // Set up call to Thread::Current()->pDeliverException.
   __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
   __ blx(R12);
-  // Call never returns.
-  __ bkpt(0);
 #undef __
 }
 
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 313f365..dee8287 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -398,6 +398,8 @@
                    Condition cond = AL) = 0;
   virtual void mls(Register rd, Register rn, Register rm, Register ra,
                    Condition cond = AL) = 0;
+  virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+                     Condition cond = AL) = 0;
   virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
                      Condition cond = AL) = 0;
 
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index 9579691..6e165fc 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -200,6 +200,13 @@
 }
 
 
+void Arm32Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
+                           Register rm, Condition cond) {
+  // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+  EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
+}
+
+
 void Arm32Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
                            Register rm, Condition cond) {
   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index b922d66..55ec7b4 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -90,6 +90,8 @@
            Condition cond = AL) OVERRIDE;
   void mls(Register rd, Register rn, Register rm, Register ra,
            Condition cond = AL) OVERRIDE;
+  void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+             Condition cond = AL) OVERRIDE;
   void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
              Condition cond = AL) OVERRIDE;
 
diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc
index 4a0ae0b..efd517b 100644
--- a/compiler/utils/arm/assembler_arm32_test.cc
+++ b/compiler/utils/arm/assembler_arm32_test.cc
@@ -293,12 +293,29 @@
     f();
   }
 
+  // NOTE: Only support simple test like "aaa=bbb"
+  bool EvalFilterString(std::string filter) {
+    if (filter.compare("") == 0) {
+      return false;
+    }
+
+    size_t equal_sign_index = filter.find('=');
+    if (equal_sign_index == std::string::npos) {
+      EXPECT_TRUE(false) << "Unsupported filter string.";
+    }
+
+    std::string lhs = filter.substr(0, equal_sign_index);
+    std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
+    return lhs.compare(rhs) == 0;
+  }
+
   void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
-                      bool without_pc,
-                      std::string fmt, std::ostringstream& oss) {
+                      bool without_pc, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
     for (auto reg : registers) {
       std::string after_reg = fmt;
+      std::string after_reg_filter = filter;
 
       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
       size_t reg_index;
@@ -308,14 +325,23 @@
         after_reg.replace(reg_index, strlen(reg_token), reg_string);
       }
 
+      while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
+        after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
+      }
+      if (EvalFilterString(after_reg_filter)) {
+        continue;
+      }
+
       ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
     }
   }
 
   void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
-                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
       std::string after_shift = fmt;
+      std::string after_shift_filter = filter;
 
       std::string shift_string = GetShiftString(shift);
       size_t shift_index;
@@ -323,30 +349,48 @@
         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
       }
 
+      while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
+        after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+      }
+      if (EvalFilterString(after_shift_filter)) {
+        continue;
+      }
+
       ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
     }
   }
 
   void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
-                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     for (arm::Condition c : GetConditions()) {
       std::string after_cond = fmt;
+      std::string after_cond_filter = filter;
 
       size_t cond_index = after_cond.find(COND_TOKEN);
       if (cond_index != std::string::npos) {
         after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
       }
 
+      cond_index = after_cond_filter.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+      if (EvalFilterString(after_cond_filter)) {
+        continue;
+      }
+
       ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
     }
   }
 
   template <typename... Args>
   void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
-                      std::string fmt, std::ostringstream& oss) {
+                      std::string fmt, std::string filter, std::ostringstream& oss) {
     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
     for (auto reg : registers) {
       std::string after_reg = fmt;
+      std::string after_reg_filter = filter;
 
       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
       size_t reg_index;
@@ -356,17 +400,26 @@
         after_reg.replace(reg_index, strlen(reg_token), reg_string);
       }
 
+      while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
+        after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
+      }
+      if (EvalFilterString(after_reg_filter)) {
+        continue;
+      }
+
       auto lambda = [&] (Args... args) { f(*reg, args...); };  // NOLINT [readability/braces] [4]
       TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
-          after_reg, oss);
+          after_reg, after_reg_filter, oss);
     }
   }
 
   template <typename... Args>
   void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
-                      bool without_pc, std::string fmt, std::ostringstream& oss) {
+                      bool without_pc, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
       std::string after_shift = fmt;
+      std::string after_shift_filter = filter;
 
       std::string shift_string = GetShiftString(shift);
       size_t shift_index;
@@ -374,26 +427,42 @@
         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
       }
 
+      while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
+        after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+      }
+      if (EvalFilterString(after_shift_filter)) {
+        continue;
+      }
+
       auto lambda = [&] (Args... args) { f(shift, args...); };  // NOLINT [readability/braces] [4]
       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
-          after_shift, oss);
+          after_shift, after_shift_filter, oss);
     }
   }
 
   template <typename... Args>
   void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
-                      std::string fmt, std::ostringstream& oss) {
+                      std::string fmt, std::string filter, std::ostringstream& oss) {
     for (arm::Condition c : GetConditions()) {
       std::string after_cond = fmt;
+      std::string after_cond_filter = filter;
 
       size_t cond_index = after_cond.find(COND_TOKEN);
       if (cond_index != std::string::npos) {
         after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
       }
 
+      cond_index = after_cond_filter.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+      if (EvalFilterString(after_cond_filter)) {
+        continue;
+      }
+
       auto lambda = [&] (Args... args) { f(c, args...); };  // NOLINT [readability/braces] [4]
       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
-          after_cond, oss);
+          after_cond, after_cond_filter, oss);
     }
   }
 
@@ -421,13 +490,13 @@
 
   template <typename... Args>
   void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
-                             std::string fmt, std::string test_name) {
+                             std::string fmt, std::string test_name, std::string filter) {
     first_ = false;
     WarnOnCombinations(CountHelper<Args...>(without_pc));
 
     std::ostringstream oss;
 
-    TemplateHelper(f, 0, without_pc, fmt, oss);
+    TemplateHelper(f, 0, without_pc, fmt, filter, oss);
 
     oss << "\n";  // Trailing newline.
 
@@ -436,26 +505,26 @@
 
   template <typename... Args>
   void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-                std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
+                std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
   }
 
   template <typename... Args>
   void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-      std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
+      std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
   }
 
   template <typename... Args>
   void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-      std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
+      std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
   }
 
   template <typename... Args>
   void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-      std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
+      std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
   }
 
  private:
@@ -565,15 +634,18 @@
 }
 
 TEST_F(AssemblerArm32Test, Mla) {
-  T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
+  T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
 }
 
-/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
 TEST_F(AssemblerArm32Test, Umull) {
   T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
-           "umull");
+           "umull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
 }
-*/
+
+TEST_F(AssemblerArm32Test, Smull) {
+  T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
+           "smull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
+}
 
 TEST_F(AssemblerArm32Test, Sdiv) {
   T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
@@ -655,9 +727,10 @@
   T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
 }
 
-/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
+/* TODO: Need better filter support.
 TEST_F(AssemblerArm32Test, Strex) {
-  RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
+  T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
+           "{reg1}={reg2}||{reg1}={reg3}");  // Skip the cases where reg1 == reg2 || reg1 == reg3.
 }
 */
 
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 3b42f63..75f2b77 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -238,6 +238,24 @@
 }
 
 
+void Thumb2Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
+                            Register rm, Condition cond) {
+  CheckCondition(cond);
+
+  uint32_t op1 = 0U /* 0b000; */;
+  uint32_t op2 = 0U /* 0b0000 */;
+  int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
+      op1 << 20 |
+      op2 << 4 |
+      static_cast<uint32_t>(rd_lo) << 12 |
+      static_cast<uint32_t>(rd_hi) << 8 |
+      static_cast<uint32_t>(rn) << 16 |
+      static_cast<uint32_t>(rm);
+
+  Emit32(encoding);
+}
+
+
 void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
                             Register rm, Condition cond) {
   CheckCondition(cond);
@@ -740,13 +758,6 @@
     return true;
   }
 
-  // Check for MOV with an ROR.
-  if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
-    if (so.GetImmediate() != 0) {
-      return true;
-    }
-  }
-
   bool rn_is_valid = true;
 
   // Check for single operand instructions and ADD/SUB.
@@ -792,6 +803,19 @@
     }
   }
 
+  // Check for register shift operand.
+  if (so.IsRegister() && so.IsShift()) {
+    if (opcode != MOV) {
+      return true;
+    }
+    // Check for MOV with an ROR.
+    if (so.GetShift() == ROR) {
+      if (so.GetImmediate() != 0) {
+        return true;
+      }
+    }
+  }
+
   // The instruction can be encoded in 16 bits.
   return false;
 }
@@ -1614,7 +1638,6 @@
     // branch the size may change if it so happens that other branches change size that change
     // the distance to the target and that distance puts this branch over the limit for 16 bits.
     if (size == Branch::k16Bit) {
-      DCHECK(!force_32bit_branches_);
       Emit16(0);          // Space for a 16 bit branch.
     } else {
       Emit32(0);            // Space for a 32 bit branch.
@@ -1622,7 +1645,7 @@
   } else {
     // Branch is to an unbound label.  Emit space for it.
     uint16_t branch_id = AddBranch(branch_type, pc, cond);    // Unresolved branch.
-    if (force_32bit_branches_ || force_32bit_) {
+    if (!CanRelocateBranches() || force_32bit_) {
       Emit16(static_cast<uint16_t>(label->position_));    // Emit current label link.
       Emit16(0);                   // another 16 bits.
     } else {
@@ -2258,7 +2281,7 @@
     uint32_t branch_location = branch->GetLocation();
     uint16_t next = buffer_.Load<uint16_t>(branch_location);       // Get next in chain.
     if (changed) {
-      DCHECK(!force_32bit_branches_);
+      DCHECK(CanRelocateBranches());
       MakeHoleForBranch(branch->GetLocation(), 2);
       if (branch->IsCompareAndBranch()) {
         // A cbz/cbnz instruction has changed size.  There is no valid encoding for
@@ -2718,21 +2741,21 @@
 
 
 void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
-  if (force_32bit_branches_) {
+  if (CanRelocateBranches()) {
+    cbz(r, label);
+  } else {
     cmp(r, ShifterOperand(0));
     b(label, EQ);
-  } else {
-    cbz(r, label);
   }
 }
 
 
 void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
-  if (force_32bit_branches_) {
+  if (CanRelocateBranches()) {
+    cbnz(r, label);
+  } else {
     cmp(r, ShifterOperand(0));
     b(label, NE);
-  } else {
-    cbnz(r, label);
   }
 }
 }  // namespace arm
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index e33c240..90d489f 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -31,8 +31,8 @@
 
 class Thumb2Assembler FINAL : public ArmAssembler {
  public:
-  explicit Thumb2Assembler(bool force_32bit_branches = false)
-      : force_32bit_branches_(force_32bit_branches),
+  explicit Thumb2Assembler(bool can_relocate_branches = true)
+      : can_relocate_branches_(can_relocate_branches),
         force_32bit_(false),
         it_cond_index_(kNoItCondition),
         next_condition_(AL) {
@@ -52,8 +52,8 @@
     return force_32bit_;
   }
 
-  bool IsForced32BitBranches() const {
-    return force_32bit_branches_;
+  bool CanRelocateBranches() const {
+    return can_relocate_branches_;
   }
 
   void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
@@ -112,6 +112,8 @@
            Condition cond = AL) OVERRIDE;
   void mls(Register rd, Register rn, Register rm, Register ra,
            Condition cond = AL) OVERRIDE;
+  void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+             Condition cond = AL) OVERRIDE;
   void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
              Condition cond = AL) OVERRIDE;
 
@@ -437,8 +439,12 @@
   void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc = false);
   void EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc = false);
 
-  bool force_32bit_branches_;  // Force the assembler to use 32 bit branch instructions.
-  bool force_32bit_;           // Force the assembler to use 32 bit thumb2 instructions.
+  // Whether the assembler can relocate branches. If false, unresolved branches will be
+  // emitted on 32bits.
+  bool can_relocate_branches_;
+
+  // Force the assembler to use 32 bit thumb2 instructions.
+  bool force_32bit_;
 
   // IfThen conditions.  Used to check that conditional instructions match the preceding IT.
   Condition it_conditions_[4];
@@ -554,12 +560,21 @@
     // size of the branch to change return true.  Otherwise return false.
     bool Resolve(uint32_t target) {
       target_ = target;
-      Size newsize = CalculateSize();
-      if (size_ != newsize) {
-        size_ = newsize;
-        return true;
+      if (assembler_->CanRelocateBranches()) {
+        Size new_size = CalculateSize();
+        if (size_ != new_size) {
+          size_ = new_size;
+          return true;
+        }
+        return false;
+      } else {
+        if (kIsDebugBuild) {
+          Size new_size = CalculateSize();
+          // Check that the size has not increased.
+          DCHECK(!(new_size == k32Bit && size_ == k16Bit));
+        }
+        return false;
       }
-      return false;
     }
 
     // Move a cbz/cbnz branch.  This is always forward.
@@ -575,6 +590,7 @@
     // size of the branch instruction.  It returns true if the branch
     // has changed size.
     bool Relocate(uint32_t oldlocation, int32_t delta) {
+      DCHECK(assembler_->CanRelocateBranches());
       if (location_ > oldlocation) {
         location_ += delta;
       }
@@ -587,9 +603,9 @@
       }
 
       // Calculate the new size.
-      Size newsize = CalculateSize();
-      if (size_ != newsize) {
-        size_ = newsize;
+      Size new_size = CalculateSize();
+      if (size_ != new_size) {
+        size_ = new_size;
         return true;
       }
       return false;
@@ -631,15 +647,13 @@
    private:
     // Calculate the size of the branch instruction based on its type and offset.
     Size CalculateSize() const {
-      if (assembler_->IsForced32BitBranches()) {
-        return k32Bit;
-      }
       if (target_ == kUnresolved) {
         if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) {
           return k32Bit;
         }
-        return k16Bit;
+        return assembler_->CanRelocateBranches() ? k16Bit : k32Bit;
       }
+      // When the target is resolved, we know the best encoding for it.
       int32_t delta = target_ - location_ - 4;
       if (delta < 0) {
         delta = -delta;
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index 5f5561a..733441b 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -89,23 +89,24 @@
   EXPECT_TRUE(CheckTools());
 }
 
+#define __ GetAssembler()->
 
 TEST_F(AssemblerThumb2Test, Sbfx) {
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 1);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 8);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 16);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 32);
+  __ sbfx(arm::R0, arm::R1, 0, 1);
+  __ sbfx(arm::R0, arm::R1, 0, 8);
+  __ sbfx(arm::R0, arm::R1, 0, 16);
+  __ sbfx(arm::R0, arm::R1, 0, 32);
 
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 1);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 8);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 16);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 24);
+  __ sbfx(arm::R0, arm::R1, 8, 1);
+  __ sbfx(arm::R0, arm::R1, 8, 8);
+  __ sbfx(arm::R0, arm::R1, 8, 16);
+  __ sbfx(arm::R0, arm::R1, 8, 24);
 
-  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 1);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 8);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 16);
+  __ sbfx(arm::R0, arm::R1, 16, 1);
+  __ sbfx(arm::R0, arm::R1, 16, 8);
+  __ sbfx(arm::R0, arm::R1, 16, 16);
 
-  GetAssembler()->sbfx(arm::R0, arm::R1, 31, 1);
+  __ sbfx(arm::R0, arm::R1, 31, 1);
 
   const char* expected =
       "sbfx r0, r1, #0, #1\n"
@@ -127,21 +128,21 @@
 }
 
 TEST_F(AssemblerThumb2Test, Ubfx) {
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32);
+  __ ubfx(arm::R0, arm::R1, 0, 1);
+  __ ubfx(arm::R0, arm::R1, 0, 8);
+  __ ubfx(arm::R0, arm::R1, 0, 16);
+  __ ubfx(arm::R0, arm::R1, 0, 32);
 
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24);
+  __ ubfx(arm::R0, arm::R1, 8, 1);
+  __ ubfx(arm::R0, arm::R1, 8, 8);
+  __ ubfx(arm::R0, arm::R1, 8, 16);
+  __ ubfx(arm::R0, arm::R1, 8, 24);
 
-  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16);
+  __ ubfx(arm::R0, arm::R1, 16, 1);
+  __ ubfx(arm::R0, arm::R1, 16, 8);
+  __ ubfx(arm::R0, arm::R1, 16, 16);
 
-  GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1);
+  __ ubfx(arm::R0, arm::R1, 31, 1);
 
   const char* expected =
       "ubfx r0, r1, #0, #1\n"
@@ -163,7 +164,7 @@
 }
 
 TEST_F(AssemblerThumb2Test, Vmstat) {
-  GetAssembler()->vmstat();
+  __ vmstat();
 
   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
 
@@ -171,10 +172,10 @@
 }
 
 TEST_F(AssemblerThumb2Test, ldrexd) {
-  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
-  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
-  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
-  GetAssembler()->ldrexd(arm::R5, arm::R3, arm::R7);
+  __ ldrexd(arm::R0, arm::R1, arm::R0);
+  __ ldrexd(arm::R0, arm::R1, arm::R1);
+  __ ldrexd(arm::R0, arm::R1, arm::R2);
+  __ ldrexd(arm::R5, arm::R3, arm::R7);
 
   const char* expected =
       "ldrexd r0, r1, [r0]\n"
@@ -185,10 +186,10 @@
 }
 
 TEST_F(AssemblerThumb2Test, strexd) {
-  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
-  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
-  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
-  GetAssembler()->strexd(arm::R9, arm::R5, arm::R3, arm::R7);
+  __ strexd(arm::R9, arm::R0, arm::R1, arm::R0);
+  __ strexd(arm::R9, arm::R0, arm::R1, arm::R1);
+  __ strexd(arm::R9, arm::R0, arm::R1, arm::R2);
+  __ strexd(arm::R9, arm::R5, arm::R3, arm::R7);
 
   const char* expected =
       "strexd r9, r0, r1, [r0]\n"
@@ -199,9 +200,9 @@
 }
 
 TEST_F(AssemblerThumb2Test, LdrdStrd) {
-  GetAssembler()->ldrd(arm::R0, arm::Address(arm::R2, 8));
-  GetAssembler()->ldrd(arm::R0, arm::Address(arm::R12));
-  GetAssembler()->strd(arm::R0, arm::Address(arm::R2, 8));
+  __ ldrd(arm::R0, arm::Address(arm::R2, 8));
+  __ ldrd(arm::R0, arm::Address(arm::R12));
+  __ strd(arm::R0, arm::Address(arm::R2, 8));
 
   const char* expected =
       "ldrd r0, r1, [r2, #8]\n"
@@ -211,7 +212,6 @@
 }
 
 TEST_F(AssemblerThumb2Test, eor) {
-#define __ GetAssembler()->
   __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0));
   __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1));
   __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0));
@@ -230,23 +230,47 @@
 TEST_F(AssemblerThumb2Test, sub) {
   __ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
   __ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
+  __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
+  __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
 
   const char* expected =
       "subs r1, r0, #42\n"
-      "subw r1, r0, #42\n";
+      "subw r1, r0, #42\n"
+      "subs r1, r0, r2, asr #31\n"
+      "sub r1, r0, r2, asr #31\n";
   DriverStr(expected, "sub");
 }
 
 TEST_F(AssemblerThumb2Test, add) {
   __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
   __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
+  __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
+  __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
 
   const char* expected =
       "adds r1, r0, #42\n"
-      "addw r1, r0, #42\n";
+      "addw r1, r0, #42\n"
+      "adds r1, r0, r2, asr #31\n"
+      "add r1, r0, r2, asr #31\n";
   DriverStr(expected, "add");
 }
 
+TEST_F(AssemblerThumb2Test, umull) {
+  __ umull(arm::R0, arm::R1, arm::R2, arm::R3);
+
+  const char* expected =
+      "umull r0, r1, r2, r3\n";
+  DriverStr(expected, "umull");
+}
+
+TEST_F(AssemblerThumb2Test, smull) {
+  __ smull(arm::R0, arm::R1, arm::R2, arm::R3);
+
+  const char* expected =
+      "smull r0, r1, r2, r3\n";
+  DriverStr(expected, "smull");
+}
+
 TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
   arm::StoreOperandType type = arm::kStoreWord;
   int32_t offset = 4092;
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 772fa9a..7738627 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -15,9 +15,11 @@
  */
 
 #include <dirent.h>
+#include <errno.h>
 #include <fstream>
-#include <sys/types.h>
 #include <map>
+#include <string.h>
+#include <sys/types.h>
 
 #include "gtest/gtest.h"
 #include "utils/arm/assembler_thumb2.h"
@@ -105,12 +107,14 @@
 
   // Assemble the .S
   snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
-  system(cmd);
+  int cmd_result = system(cmd);
+  ASSERT_EQ(cmd_result, 0) << strerror(errno);
 
   // Remove the $d symbols to prevent the disassembler dumping the instructions
   // as .word
   snprintf(cmd, sizeof(cmd), "%sobjcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), filename, filename);
-  system(cmd);
+  int cmd_result2 = system(cmd);
+  ASSERT_EQ(cmd_result2, 0) << strerror(errno);
 
   // Disassemble.
 
@@ -119,7 +123,8 @@
   if (kPrintResults) {
     // Print the results only, don't check. This is used to generate new output for inserting
     // into the .inc file.
-    system(cmd);
+    int cmd_result3 = system(cmd);
+    ASSERT_EQ(cmd_result3, 0) << strerror(errno);
   } else {
     // Check the results match the appropriate results in the .inc file.
     FILE *fp = popen(cmd, "r");
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 7488578..3c145d7 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -313,8 +313,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
      *
      * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
@@ -330,13 +329,10 @@
     .extern \cxx_name
 ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE]  @ pass caller Method*
-    mov    r3, r9                         @ pass Thread::Current
-    mov    r12, sp
-    str    r12, [sp, #-16]!               @ expand the frame and pass SP
+    mov    r2, r9                         @ pass Thread::Current
+    mov    r3, sp
     .cfi_adjust_cfa_offset 16
     bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
-    add    sp, #16                        @ strip the extra frame
     .cfi_adjust_cfa_offset -16
     mov    r12, r1                        @ save Method*->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index f8b0734..6b16a2e5 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -459,8 +459,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/x0 with the target Method*, arg0/x0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/x1.
      *
      * The helper will attempt to locate the target and return a 128-bit result in x0/x1 consisting
@@ -483,10 +482,9 @@
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
 
-    ldr    w2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE]  // pass caller Method*
-    mov    x3, xSELF                      // pass Thread::Current
-    mov    x4, sp
-    bl     \cxx_name                      // (method_idx, this, caller, Thread*, SP)
+    mov    x2, xSELF                      // pass Thread::Current
+    mov    x3, sp
+    bl     \cxx_name                      // (method_idx, this, Thread*, SP)
     mov    xIP0, x1                       // save Method*->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     cbz    x0, 1f                         // did we find the target? if not go to exception delivery
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index ee5c59f..92b180e 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -439,8 +439,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
      *
      * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
@@ -456,15 +455,13 @@
     .extern \cxx_name
 ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
-    lw    $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE+ARG_SLOT_SIZE($sp)    # pass caller Method*
-    addiu $t0, $sp, ARG_SLOT_SIZE         # save $sp (remove arg slots)
-    move  $a3, rSELF                      # pass Thread::Current
-    jal   \cxx_name                       # (method_idx, this, caller, Thread*, $sp)
-    sw    $t0, 16($sp)                    # pass $sp
-    move  $a0, $v0                        # save target Method*
+    move  $a2, rSELF                       # pass Thread::Current
+    jal   \cxx_name                        # (method_idx, this, Thread*, $sp)
+    addiu $a3, $sp, ARG_SLOT_SIZE          # pass $sp (remove arg slots)
+    move  $a0, $v0                         # save target Method*
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     beqz  $v0, 1f
-    move  $t9, $v1                        # save $v0->code_
+    move  $t9, $v1                         # save $v0->code_
     jalr  $zero, $t9
     nop
 1:
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index ff79b5d..b7320a6 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -529,10 +529,9 @@
     .extern \cxx_name
 ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
-    lwu   $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE($sp)  # pass caller Method*
-    move  $a3, rSELF                       # pass Thread::Current
-    jal   \cxx_name                        # (method_idx, this, caller, Thread*, $sp)
-    move  $a4, $sp                         # pass $sp
+    move  $a2, rSELF                       # pass Thread::Current
+    jal   \cxx_name                        # (method_idx, this, Thread*, $sp)
+    move  $a3, $sp                         # pass $sp
     move  $a0, $v0                         # save target Method*
     move  $t9, $v1                         # save $v0->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 6ebeba3..d62c1bc 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -278,8 +278,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3 and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
      *
      * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
@@ -297,19 +296,15 @@
     movl %esp, %edx  // remember SP
 
     // Outgoing argument set up
-    subl MACRO_LITERAL(12), %esp  // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
     PUSH edx                      // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    pushl 32+32(%edx)             // pass caller Method*
-    CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
     call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, Thread*, SP)
     movl %edx, %edi               // save code pointer in EDI
-    addl MACRO_LITERAL(36), %esp  // Pop arguments skip eax
-    CFI_ADJUST_CFA_OFFSET(-36)
+    addl MACRO_LITERAL(20), %esp  // Pop arguments skip eax
+    CFI_ADJUST_CFA_OFFSET(-20)
 
     // Restore FPRs.
     movsd 0(%esp), %xmm0
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index da4d92b..ddeb5b8 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -341,8 +341,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/rdi with the target Method*, arg0/rdi will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/rsi.
      *
      * The helper will attempt to locate the target and return a 128-bit result in rax/rdx consisting
@@ -362,11 +361,10 @@
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
 
-    movl FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE(%rsp), %edx  // pass caller Method*
-    movq %gs:THREAD_SELF_OFFSET, %rcx                      // pass Thread
-    movq %rsp, %r8                                         // pass SP
+    movq %gs:THREAD_SELF_OFFSET, %rdx                      // pass Thread
+    movq %rsp, %rcx                                        // pass SP
 
-    call VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, caller method*, Thread*, SP)
+    call VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, Thread*, SP)
                                                            // save the code pointer
     movq %rax, %rdi
     movq %rdx, %rax
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 0ae7863..859de4b 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -289,17 +289,17 @@
   CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
 
   const char* program_name = ProgramInvocationShortName();
-  write(STDERR_FILENO, program_name, strlen(program_name));
-  write(STDERR_FILENO, " ", 1);
-  write(STDERR_FILENO, &log_characters[log_severity], 1);
-  write(STDERR_FILENO, " ", 1);
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, program_name, strlen(program_name)));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, &log_characters[log_severity], 1));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1));
   // TODO: pid and tid.
-  write(STDERR_FILENO, file, strlen(file));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, file, strlen(file)));
   // TODO: line.
   UNUSED(line);
-  write(STDERR_FILENO, "] ", 2);
-  write(STDERR_FILENO, message, strlen(message));
-  write(STDERR_FILENO, "\n", 1);
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, "] ", 2));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, message, strlen(message)));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, "\n", 1));
 #endif
 }
 
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/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/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 9292cff..625e695 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -38,25 +38,34 @@
 
 namespace art {
 
-inline mirror::ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+inline mirror::ArtMethod* GetCalleeSaveMethodCaller(StackReference<mirror::ArtMethod>* sp,
+                                                    Runtime::CalleeSaveType type,
+                                                    bool do_caller_check = false)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  auto* refs_only_sp = self->GetManagedStack()->GetTopQuickFrame();
-  DCHECK_EQ(refs_only_sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(type));
+  DCHECK_EQ(sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(type));
 
   const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type);
   auto* caller_sp = reinterpret_cast<StackReference<mirror::ArtMethod>*>(
-          reinterpret_cast<uintptr_t>(refs_only_sp) + callee_frame_size);
+          reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
   auto* caller = caller_sp->AsMirrorPtr();
 
-  if (kIsDebugBuild) {
-    NthCallerVisitor visitor(self, 1, true);
+  if (kIsDebugBuild && do_caller_check) {
+    // Note that do_caller_check is optional, as this method can be called by
+    // stubs, and tests without a proper call stack.
+    NthCallerVisitor visitor(Thread::Current(), 1, true);
     visitor.WalkStack();
-    CHECK(caller == visitor.caller);
+    CHECK_EQ(caller, visitor.caller);
   }
 
   return caller;
 }
 
+inline mirror::ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return GetCalleeSaveMethodCaller(
+      self->GetManagedStack()->GetTopQuickFrame(), type, true /* do_caller_check */);
+}
+
 template <const bool kAccessCheck>
 ALWAYS_INLINE
 inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
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/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 46629f5..9148878 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -25,8 +25,7 @@
 
 namespace art {
 
-extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx,
-                                                             Thread* self)
+extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called to ensure static storage base is initialized for direct static field reads and writes.
   // A class may be accessing another class' fields when it doesn't have access, as access has been
@@ -36,8 +35,7 @@
   return ResolveVerifyAndClinit(type_idx, caller, self, true, false);
 }
 
-extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx,
-                                                    Thread* self)
+extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when method->dex_cache_resolved_types_[] misses.
   ScopedQuickEntrypointChecks sqec(self);
@@ -45,8 +43,7 @@
   return ResolveVerifyAndClinit(type_idx, caller, self, false, false);
 }
 
-extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
-                                                                   Thread* self)
+extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when caller isn't guaranteed to have access to a type and the dex cache may be
   // unpopulated.
@@ -55,8 +52,7 @@
   return ResolveVerifyAndClinit(type_idx, caller, self, false, true);
 }
 
-extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx,
-                                                    Thread* self)
+extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kRefsOnly);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2e7e2df..345b0ad 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -294,8 +294,13 @@
   static mirror::ArtMethod* GetCallingMethod(StackReference<mirror::ArtMethod>* sp)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
-    uint8_t* previous_sp = reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize;
-    return reinterpret_cast<StackReference<mirror::ArtMethod>*>(previous_sp)->AsMirrorPtr();
+    return GetCalleeSaveMethodCaller(sp, Runtime::kRefsAndArgs);
+  }
+
+  static uint32_t GetCallingDexPc(StackReference<mirror::ArtMethod>* sp)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
+    return GetCallingMethod(sp)->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
   }
 
   // For the given quick ref and args quick frame, return the caller's PC.
@@ -827,12 +832,13 @@
 
   // Compute details about the called method (avoid GCs)
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  mirror::ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
   InvokeType invoke_type;
   MethodReference called_method(nullptr, 0);
   const bool called_method_known_on_entry = !called->IsRuntimeMethod();
+  mirror::ArtMethod* caller = nullptr;
   if (!called_method_known_on_entry) {
-    uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
+    caller = QuickArgumentVisitor::GetCallingMethod(sp);
+    uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
     const DexFile::CodeItem* code;
     called_method.dex_file = caller->GetDexFile();
     code = caller->GetCodeItem();
@@ -1946,16 +1952,13 @@
 // to hold the mutator lock (see SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) annotations).
 
 template<InvokeType type, bool access_check>
-static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
-                                     mirror::ArtMethod* caller_method,
-                                     Thread* self, StackReference<mirror::ArtMethod>* sp);
-
-template<InvokeType type, bool access_check>
-static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
-                                     mirror::ArtMethod* caller_method,
-                                     Thread* self, StackReference<mirror::ArtMethod>* sp) {
+static TwoWordReturn artInvokeCommon(uint32_t method_idx,
+                                     mirror::Object* this_object,
+                                     Thread* self,
+                                     StackReference<mirror::ArtMethod>* sp) {
   ScopedQuickEntrypointChecks sqec(self);
   DCHECK_EQ(sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
+  mirror::ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
   mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
                                              type);
   if (UNLIKELY(method == nullptr)) {
@@ -1994,7 +1997,6 @@
   template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                          \
   TwoWordReturn artInvokeCommon<type, access_check>(uint32_t method_idx,                        \
                                                     mirror::Object* this_object,                \
-                                                    mirror::ArtMethod* caller_method,           \
                                                     Thread* self,                               \
                                                     StackReference<mirror::ArtMethod>* sp)      \
 
@@ -2012,58 +2014,58 @@
 
 // See comments in runtime_support_asm.S
 extern "C" TwoWordReturn artInvokeInterfaceTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    mirror::ArtMethod* caller_method, Thread* self,
+    uint32_t method_idx,
+    mirror::Object* this_object,
+    Thread* self,
     StackReference<mirror::ArtMethod>* sp)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kInterface, true>(method_idx, this_object,
-                                           caller_method, self, sp);
+  return artInvokeCommon<kInterface, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeDirectTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    mirror::ArtMethod* caller_method, Thread* self,
+    uint32_t method_idx,
+    mirror::Object* this_object,
+    Thread* self,
     StackReference<mirror::ArtMethod>* sp)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method,
-                                        self, sp);
+  return artInvokeCommon<kDirect, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeStaticTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    mirror::ArtMethod* caller_method, Thread* self,
+    uint32_t method_idx,
+    mirror::Object* this_object,
+    Thread* self,
     StackReference<mirror::ArtMethod>* sp)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method,
-                                        self, sp);
+  return artInvokeCommon<kStatic, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeSuperTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    mirror::ArtMethod* caller_method, Thread* self,
+    uint32_t method_idx,
+    mirror::Object* this_object,
+    Thread* self,
     StackReference<mirror::ArtMethod>* sp)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method,
-                                       self, sp);
+  return artInvokeCommon<kSuper, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeVirtualTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    mirror::ArtMethod* caller_method, Thread* self,
+    uint32_t method_idx,
+    mirror::Object* this_object,
+    Thread* self,
     StackReference<mirror::ArtMethod>* sp)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method,
-                                         self, sp);
+  return artInvokeCommon<kVirtual, true>(method_idx, this_object, self, sp);
 }
 
 // Determine target of interface dispatch. This object is known non-null.
 extern "C" TwoWordReturn artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_method,
                                                       mirror::Object* this_object,
-                                                      mirror::ArtMethod* caller_method,
                                                       Thread* self,
                                                       StackReference<mirror::ArtMethod>* sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
+  mirror::ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
   mirror::ArtMethod* method;
   if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
     method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
@@ -2075,12 +2077,7 @@
   } else {
     DCHECK(interface_method == Runtime::Current()->GetResolutionMethod());
 
-    // Find the caller PC.
-    constexpr size_t pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsAndArgs);
-    uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) + pc_offset);
-
-    // Map the caller PC to a dex PC.
-    uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
+    uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
     const DexFile::CodeItem* code = caller_method->GetCodeItem();
     CHECK_LT(dex_pc, code->insns_size_in_code_units_);
     const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index 5354fd8..3b0e6c1 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -302,7 +302,9 @@
   } while (length > 0);
 
   // Truncate the file to the new length.
-  ftruncate(fd, full_length);
+  if (ftruncate(fd, full_length) == -1) {
+    LOG(ERROR) << "Failed to truncate profile file " << full_name;
+  }
 
   // Now unlock the file, allowing another process in.
   err = flock(fd, LOCK_UN);
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/stack.cc b/runtime/stack.cc
index 800acaa..6795516 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -99,15 +99,45 @@
       cur_quick_frame_pc_(0),
       num_frames_(num_frames),
       cur_depth_(0),
+      current_inlining_depth_(0),
       context_(context) {
   DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
 }
 
+InlineInfo StackVisitor::GetCurrentInlineInfo() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::ArtMethod* outer_method = GetCurrentQuickFrame()->AsMirrorPtr();
+  uint32_t native_pc_offset = outer_method->NativeQuickPcOffset(cur_quick_frame_pc_);
+  CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  return code_info.GetInlineInfoOf(stack_map);
+}
+
+mirror::ArtMethod* StackVisitor::GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (cur_shadow_frame_ != nullptr) {
+    return cur_shadow_frame_->GetMethod();
+  } else if (cur_quick_frame_ != nullptr) {
+    if (IsInInlinedFrame()) {
+      size_t depth_in_stack_map = current_inlining_depth_ - 1;
+      return GetCurrentQuickFrame()->AsMirrorPtr()->GetDexCacheResolvedMethod(
+          GetCurrentInlineInfo().GetMethodIndexAtDepth(depth_in_stack_map));
+    } else {
+      return cur_quick_frame_->AsMirrorPtr();
+    }
+  } else {
+    return nullptr;
+  }
+}
+
 uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const {
   if (cur_shadow_frame_ != nullptr) {
     return cur_shadow_frame_->GetDexPC();
   } else if (cur_quick_frame_ != nullptr) {
-    return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+    if (IsInInlinedFrame()) {
+      size_t depth_in_stack_map = current_inlining_depth_ - 1;
+      return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map);
+    } else {
+      return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+    }
   } else {
     return 0;
   }
@@ -225,18 +255,27 @@
 
 bool StackVisitor::GetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
                                             uint32_t* val) const {
-  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
-  DCHECK(code_pointer != nullptr);
-  uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
-  CodeInfo code_info = m->GetOptimizedCodeInfo();
-  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  DCHECK_EQ(m, GetMethod());
   const DexFile::CodeItem* code_item = m->GetCodeItem();
   DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be null or how would we compile
                                                     // its instructions?
-  DCHECK_LT(vreg, code_item->registers_size_);
   uint16_t number_of_dex_registers = code_item->registers_size_;
-  DexRegisterMap dex_register_map =
-      code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+  DCHECK_LT(vreg, code_item->registers_size_);
+
+  mirror::ArtMethod* outer_method = GetCurrentQuickFrame()->AsMirrorPtr();
+  const void* code_pointer = outer_method->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+
+  uint32_t native_pc_offset = outer_method->NativeQuickPcOffset(cur_quick_frame_pc_);
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  size_t depth_in_stack_map = current_inlining_depth_ - 1;
+
+  DexRegisterMap dex_register_map = IsInInlinedFrame()
+      ? code_info.GetDexRegisterMapAtDepth(
+            depth_in_stack_map, code_info.GetInlineInfoOf(stack_map), number_of_dex_registers)
+      : code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+
   DexRegisterLocation::Kind location_kind =
       dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info);
   switch (location_kind) {
@@ -704,6 +743,26 @@
       mirror::ArtMethod* method = cur_quick_frame_->AsMirrorPtr();
       while (method != nullptr) {
         SanityCheckFrame();
+
+        if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
+            && method->IsOptimized(sizeof(void*))) {
+          CodeInfo code_info = method->GetOptimizedCodeInfo();
+          uint32_t native_pc_offset = method->NativeQuickPcOffset(cur_quick_frame_pc_);
+          StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+          if (stack_map.HasInlineInfo(code_info)) {
+            InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
+            DCHECK_EQ(current_inlining_depth_, 0u);
+            for (current_inlining_depth_ = inline_info.GetDepth();
+                 current_inlining_depth_ != 0;
+                 --current_inlining_depth_) {
+              bool should_continue = VisitFrame();
+              if (UNLIKELY(!should_continue)) {
+                return;
+              }
+            }
+          }
+        }
+
         bool should_continue = VisitFrame();
         if (UNLIKELY(!should_continue)) {
           return;
diff --git a/runtime/stack.h b/runtime/stack.h
index bf61016..5b43848 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -36,9 +36,10 @@
 }  // namespace mirror
 
 class Context;
-class ShadowFrame;
 class HandleScope;
+class InlineInfo;
 class ScopedObjectAccess;
+class ShadowFrame;
 class StackVisitor;
 class Thread;
 
@@ -430,15 +431,7 @@
   void WalkStack(bool include_transitions = false)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (cur_shadow_frame_ != nullptr) {
-      return cur_shadow_frame_->GetMethod();
-    } else if (cur_quick_frame_ != nullptr) {
-      return cur_quick_frame_->AsMirrorPtr();
-    } else {
-      return nullptr;
-    }
-  }
+  mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsShadowFrame() const {
     return cur_shadow_frame_ != nullptr;
@@ -611,7 +604,7 @@
   }
 
   bool IsInInlinedFrame() const {
-    return false;
+    return current_inlining_depth_ != 0;
   }
 
   uintptr_t GetCurrentQuickFramePc() const {
@@ -703,6 +696,8 @@
 
   void SanityCheckFrame() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  InlineInfo GetCurrentInlineInfo() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   Thread* const thread_;
   const StackWalkKind walk_kind_;
   ShadowFrame* cur_shadow_frame_;
@@ -712,6 +707,9 @@
   size_t num_frames_;
   // Depth of the frame we're currently at.
   size_t cur_depth_;
+  // Current inlining depth of the method we are currently at.
+  // 0 if there is no inlined frame.
+  size_t current_inlining_depth_;
 
  protected:
   Context* const context_;
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 11e7e44..6a0c07d 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -257,21 +257,48 @@
     DumpStackMapHeader(os, i);
     if (stack_map.HasDexRegisterMap(*this)) {
       DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-      // TODO: Display the bit mask of live Dex registers.
-      for (size_t j = 0; j < number_of_dex_registers; ++j) {
-        if (dex_register_map.IsDexRegisterLive(j)) {
-          size_t location_catalog_entry_index = dex_register_map.GetLocationCatalogEntryIndex(
-              j, number_of_dex_registers, number_of_location_catalog_entries);
-          DexRegisterLocation location =
-              dex_register_map.GetDexRegisterLocation(j, number_of_dex_registers, *this);
-          DumpRegisterMapping(
-              os, j, location, "v",
-              "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
-        }
-      }
+      dex_register_map.Dump(os, *this, number_of_dex_registers);
     }
   }
-  // TODO: Dump the stack map's inline information.
+  // 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 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();
+  // TODO: Display the bit mask of live Dex registers.
+  for (size_t j = 0; j < number_of_dex_registers; ++j) {
+    if (IsDexRegisterLive(j)) {
+      size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
+          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",
+          "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
+    }
+  }
+}
+
+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";
+
+  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";
+    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]);
+    }
+  }
 }
 
 }  // namespace art
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index f68cafe..f07fb74 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -39,47 +39,6 @@
  * their own fields.
  */
 
-/**
- * Inline information for a specific PC. The information is of the form:
- * [inlining_depth, [method_dex reference]+]
- */
-class InlineInfo {
- public:
-  explicit InlineInfo(MemoryRegion region) : region_(region) {}
-
-  uint8_t GetDepth() const {
-    return region_.LoadUnaligned<uint8_t>(kDepthOffset);
-  }
-
-  void SetDepth(uint8_t depth) {
-    region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
-  }
-
-  uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
-    return region_.LoadUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize());
-  }
-
-  void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
-    region_.StoreUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
-  }
-
-  static size_t SingleEntrySize() {
-    return sizeof(uint32_t);
-  }
-
- private:
-  // TODO: Instead of plain types such as "uint8_t", introduce
-  // typedefs (and document the memory layout of InlineInfo).
-  static constexpr int kDepthOffset = 0;
-  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
-
-  MemoryRegion region_;
-
-  friend class CodeInfo;
-  friend class StackMap;
-  friend class StackMapStream;
-};
-
 // Dex register location container used by DexRegisterMap and StackMapStream.
 class DexRegisterLocation {
  public:
@@ -506,7 +465,8 @@
                       const CodeInfo& code_info) const {
     DexRegisterLocation location =
         GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info);
-    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
+    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
+        << DexRegisterLocation::PrettyDescriptor(location.GetKind());
     return location.GetValue();
   }
 
@@ -641,6 +601,8 @@
     return region_.size();
   }
 
+  void Dump(std::ostream& o, const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
+
  private:
   // Return the index in the Dex register map corresponding to the Dex
   // register number `dex_register_number`.
@@ -675,9 +637,6 @@
  * The information is of the form:
  * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
  * stack_mask].
- *
- * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
- * stack size of a method.
  */
 class StackMap {
  public:
@@ -759,6 +718,90 @@
   friend class StackMapStream;
 };
 
+/**
+ * Inline information for a specific PC. The information is of the form:
+ * [inlining_depth, [dex_pc, method_index, dex_register_map_offset]+]
+ */
+class InlineInfo {
+ public:
+  explicit InlineInfo(MemoryRegion region) : region_(region) {}
+
+  uint8_t GetDepth() const {
+    return region_.LoadUnaligned<uint8_t>(kDepthOffset);
+  }
+
+  void SetDepth(uint8_t depth) {
+    region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
+  }
+
+  uint32_t GetMethodIndexAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
+  }
+
+  void SetMethodIndexAtDepth(uint8_t depth, uint32_t index) {
+    region_.StoreUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
+  }
+
+  uint32_t GetDexPcAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
+  }
+
+  void SetDexPcAtDepth(uint8_t depth, uint32_t dex_pc) {
+    region_.StoreUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
+  }
+
+  uint8_t GetInvokeTypeAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint8_t>(
+        kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
+  }
+
+  void SetInvokeTypeAtDepth(uint8_t depth, uint8_t invoke_type) {
+    region_.StoreUnaligned<uint8_t>(
+        kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
+  }
+
+  uint32_t GetDexRegisterMapOffsetAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
+  }
+
+  void SetDexRegisterMapOffsetAtDepth(uint8_t depth, uint32_t offset) {
+    region_.StoreUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
+  }
+
+  bool HasDexRegisterMapAtDepth(uint8_t depth) const {
+    return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
+  }
+
+  static size_t SingleEntrySize() {
+    return kFixedEntrySize;
+  }
+
+  void Dump(std::ostream& os, const CodeInfo& info, uint16_t* number_of_dex_registers) const;
+
+ private:
+  // TODO: Instead of plain types such as "uint8_t", introduce
+  // typedefs (and document the memory layout of InlineInfo).
+  static constexpr int kDepthOffset = 0;
+  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
+
+  static constexpr int kMethodIndexOffset = 0;
+  static constexpr int kDexPcOffset = kMethodIndexOffset + sizeof(uint32_t);
+  static constexpr int kInvokeTypeOffset = kDexPcOffset + sizeof(uint32_t);
+  static constexpr int kDexRegisterMapOffset = kInvokeTypeOffset + sizeof(uint8_t);
+  static constexpr int kFixedEntrySize = kDexRegisterMapOffset + sizeof(uint32_t);
+
+  MemoryRegion region_;
+
+  friend class CodeInfo;
+  friend class StackMap;
+  friend class StackMapStream;
+};
 
 /**
  * Wrapper around all compiler information collected for a method.
@@ -960,6 +1003,17 @@
     return DexRegisterMap(region_.Subregion(offset, size));
   }
 
+  // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
+  DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
+                                          InlineInfo inline_info,
+                                          uint32_t number_of_dex_registers) const {
+    DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
+    uint32_t offset =
+        GetDexRegisterMapsOffset() + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
+    size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
+    return DexRegisterMap(region_.Subregion(offset, size));
+  }
+
   InlineInfo GetInlineInfoOf(StackMap stack_map) const {
     DCHECK(stack_map.HasInlineInfo(*this));
     uint32_t offset = stack_map.GetInlineDescriptorOffset(*this) + GetDexRegisterMapsOffset();
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 24e9600..db2fc9b 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -327,5 +327,7 @@
   .loadLibrary = &native_bridge_loadLibrary,
   .getTrampoline = &native_bridge_getTrampoline,
   .isSupported = &native_bridge_isSupported,
-  .getAppEnv = &native_bridge_getAppEnv
+  .getAppEnv = &native_bridge_getAppEnv,
+  .isCompatibleWith = nullptr,
+  .getSignalHandler = nullptr
 };
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
new file mode 100644
index 0000000..b2d7e55
--- /dev/null
+++ b/test/137-cfi/cfi.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if __linux__
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#endif
+
+#include "jni.h"
+
+#include <backtrace/Backtrace.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "utils.h"
+
+namespace art {
+
+// For testing debuggerd. We do not have expected-death tests, so can't test this by default.
+// Code for this is copied from SignalTest.
+static constexpr bool kCauseSegfault = false;
+char* go_away_compiler_cfi = nullptr;
+
+static void CauseSegfault() {
+#if defined(__arm__) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+  // On supported architectures we cause a real SEGV.
+  *go_away_compiler_cfi = 'a';
+#else
+  // On other architectures we simulate SEGV.
+  kill(getpid(), SIGSEGV);
+#endif
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) {
+  // Keep pausing.
+  for (;;) {
+    pause();
+  }
+}
+
+// Helper to look for a sequence in the stack trace.
+#if __linux__
+static bool CheckStack(Backtrace* bt, const std::vector<std::string>& seq) {
+  size_t cur_search_index = 0;  // The currently active index in seq.
+  CHECK_GT(seq.size(), 0U);
+
+  for (Backtrace::const_iterator it = bt->begin(); it != bt->end(); ++it) {
+    if (BacktraceMap::IsValid(it->map)) {
+      LOG(INFO) << "Got " << it->func_name << ", looking for " << seq[cur_search_index];
+      if (it->func_name == seq[cur_search_index]) {
+        cur_search_index++;
+        if (cur_search_index == seq.size()) {
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+#endif
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jobject, jint, jboolean) {
+#if __linux__
+  // TODO: What to do on Valgrind?
+
+  std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
+  if (!bt->Unwind(0, nullptr)) {
+    return JNI_FALSE;
+  } else if (bt->NumFrames() == 0) {
+    return JNI_FALSE;
+  }
+
+  // We cannot really parse an exact stack, as the optimizing compiler may inline some functions.
+  // This is also risky, as deduping might play a trick on us, so the test needs to make sure that
+  // only unique functions are being expected.
+  std::vector<std::string> seq = {
+      "Java_Main_unwindInProcess",                   // This function.
+      "boolean Main.unwindInProcess(int, boolean)",  // The corresponding Java native method frame.
+      "void Main.main(java.lang.String[])"           // The Java entry method.
+  };
+
+  bool result = CheckStack(bt.get(), seq);
+  if (!kCauseSegfault) {
+    return result ? JNI_TRUE : JNI_FALSE;
+  } else {
+    LOG(INFO) << "Result of check-stack: " << result;
+  }
+#endif
+
+  if (kCauseSegfault) {
+    CauseSegfault();
+  }
+
+  return JNI_FALSE;
+}
+
+#if __linux__
+static constexpr int kSleepTimeMicroseconds = 50000;            // 0.05 seconds
+static constexpr int kMaxTotalSleepTimeMicroseconds = 1000000;  // 1 second
+
+// Wait for a sigstop. This code is copied from libbacktrace.
+int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed ATTRIBUTE_UNUSED) {
+  for (;;) {
+    int status;
+    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
+    if (n == -1) {
+      PLOG(WARNING) << "waitpid failed: tid " << tid;
+      break;
+    } else if (n == tid) {
+      if (WIFSTOPPED(status)) {
+        return WSTOPSIG(status);
+      } else {
+        PLOG(ERROR) << "unexpected waitpid response: n=" << n << ", status=" << std::hex << status;
+        break;
+      }
+    }
+
+    if (*total_sleep_time_usec > kMaxTotalSleepTimeMicroseconds) {
+      PLOG(WARNING) << "timed out waiting for stop signal: tid=" << tid;
+      break;
+    }
+
+    usleep(kSleepTimeMicroseconds);
+    *total_sleep_time_usec += kSleepTimeMicroseconds;
+  }
+
+  return -1;
+}
+#endif
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jobject, jint pid_int) {
+#if __linux__
+  // TODO: What to do on Valgrind?
+  pid_t pid = static_cast<pid_t>(pid_int);
+
+  // OK, this is painful. debuggerd uses ptrace to unwind other processes.
+
+  if (ptrace(PTRACE_ATTACH, pid, 0, 0)) {
+    // Were not able to attach, bad.
+    PLOG(ERROR) << "Failed to attach.";
+    kill(pid, SIGCONT);
+    return JNI_FALSE;
+  }
+
+  kill(pid, SIGSTOP);
+
+  bool detach_failed = false;
+  int total_sleep_time_usec = 0;
+  int signal = wait_for_sigstop(pid, &total_sleep_time_usec, &detach_failed);
+  if (signal == -1) {
+    LOG(WARNING) << "wait_for_sigstop failed.";
+  }
+
+  std::unique_ptr<Backtrace> bt(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+  bool result = true;
+  if (!bt->Unwind(0, nullptr)) {
+    result = false;
+  } else if (bt->NumFrames() == 0) {
+    result = false;
+  }
+
+  if (result) {
+    // See comment in unwindInProcess for non-exact stack matching.
+    std::vector<std::string> seq = {
+        // "Java_Main_sleep",                        // The sleep function being executed in the
+                                                     // other runtime.
+                                                     // Note: For some reason, the name isn't
+                                                     // resolved, so don't look for it right now.
+        "boolean Main.sleep(int, boolean, double)",  // The corresponding Java native method frame.
+        "void Main.main(java.lang.String[])"         // The Java entry method.
+    };
+
+    result = CheckStack(bt.get(), seq);
+  }
+
+  if (ptrace(PTRACE_DETACH, pid, 0, 0) != 0) {
+    PLOG(ERROR) << "Detach failed";
+  }
+
+  // Continue the process so we can kill it on the Java side.
+  kill(pid, SIGCONT);
+
+  return result ? JNI_TRUE : JNI_FALSE;
+#else
+  return JNI_FALSE;
+#endif
+}
+
+}  // namespace art
diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/137-cfi/expected.txt
diff --git a/test/137-cfi/info.txt b/test/137-cfi/info.txt
new file mode 100644
index 0000000..7d59605
--- /dev/null
+++ b/test/137-cfi/info.txt
@@ -0,0 +1 @@
+Test that unwinding with CFI info works.
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
new file mode 100644
index 0000000..e184e66
--- /dev/null
+++ b/test/137-cfi/src/Main.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+  // Whether to test local unwinding. Libunwind uses linker info to find executables. As we do
+  // not dlopen at the moment, this doesn't work, so keep it off for now.
+  public final static boolean TEST_LOCAL_UNWINDING = false;
+
+  // Unwinding another process, modelling debuggerd. This doesn't use the linker, so should work
+  // no matter whether we're using dlopen or not.
+  public final static boolean TEST_REMOTE_UNWINDING = true;
+
+  private boolean secondary;
+
+  public Main(boolean secondary) {
+      this.secondary = secondary;
+  }
+
+  public static void main(String[] args) throws Exception {
+      boolean secondary = false;
+      if (args.length > 0 && args[args.length - 1].equals("--secondary")) {
+          secondary = true;
+      }
+      new Main(secondary).run();
+  }
+
+  static {
+      System.loadLibrary("arttest");
+  }
+
+  private void run() {
+      if (secondary) {
+          if (!TEST_REMOTE_UNWINDING) {
+              throw new RuntimeException("Should not be running secondary!");
+          }
+          runSecondary();
+      } else {
+          runPrimary();
+      }
+  }
+
+  private void runSecondary() {
+      foo(true);
+      throw new RuntimeException("Didn't expect to get back...");
+  }
+
+  private void runPrimary() {
+      // First do the in-process unwinding.
+      if (TEST_LOCAL_UNWINDING && !foo(false)) {
+          System.out.println("Unwinding self failed.");
+      }
+
+      if (!TEST_REMOTE_UNWINDING) {
+          // Skip the remote step.
+          return;
+      }
+
+      // Fork the secondary.
+      String[] cmdline = getCmdLine();
+      String[] secCmdLine = new String[cmdline.length + 1];
+      System.arraycopy(cmdline, 0, secCmdLine, 0, cmdline.length);
+      secCmdLine[secCmdLine.length - 1] = "--secondary";
+      Process p = exec(secCmdLine);
+
+      try {
+          int pid = getPid(p);
+          if (pid <= 0) {
+              throw new RuntimeException("Couldn't parse process");
+          }
+
+          // Wait a bit, so the forked process has time to run until its sleep phase.
+          try {
+              Thread.sleep(5000);
+          } catch (Exception e) {
+              throw new RuntimeException(e);
+          }
+
+          if (!unwindOtherProcess(pid)) {
+              System.out.println("Unwinding other process failed.");
+          }
+      } finally {
+          // Kill the forked process.
+          p.destroy();
+      }
+  }
+
+  private static Process exec(String[] args) {
+      try {
+          return Runtime.getRuntime().exec(args);
+      } catch (Exception exc) {
+          throw new RuntimeException(exc);
+      }
+  }
+
+  private static int getPid(Process p) {
+      // Could do reflection for the private pid field, but String parsing is easier.
+      String s = p.toString();
+      if (s.startsWith("Process[pid=")) {
+          return Integer.parseInt(s.substring("Process[pid=".length(), s.length() - 1));
+      } else {
+          return -1;
+      }
+  }
+
+  // Read /proc/self/cmdline to find the invocation command line (so we can fork another runtime).
+  private static String[] getCmdLine() {
+      try {
+          BufferedReader in = new BufferedReader(new FileReader("/proc/self/cmdline"));
+          String s = in.readLine();
+          in.close();
+          return s.split("\0");
+      } catch (Exception exc) {
+          throw new RuntimeException(exc);
+      }
+  }
+
+  public boolean foo(boolean b) {
+      return bar(b);
+  }
+
+  public boolean bar(boolean b) {
+      if (b) {
+          return sleep(2, b, 1.0);
+      } else {
+          return unwindInProcess(1, b);
+      }
+  }
+
+  // Native functions. Note: to avoid deduping, they must all have different signatures.
+
+  public native boolean sleep(int i, boolean b, double dummy);
+
+  public native boolean unwindInProcess(int i, boolean b);
+  public native boolean unwindOtherProcess(int pid);
+}
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 7ce2868..447b9b8 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -625,65 +625,67 @@
     assertCharEquals((char)0, $opt$IntToChar(-2147483648));  // -(2^31)
   }
 
+  // A dummy value to defeat inlining of these routines.
+  static boolean doThrow = false;
 
   // These methods produce int-to-long Dex instructions.
-  static long $opt$ByteToLong(byte a) { return (long)a; }
-  static long $opt$ShortToLong(short a) { return (long)a; }
-  static long $opt$IntToLong(int a) { return (long)a; }
-  static long $opt$CharToLong(int a) { return (long)a; }
+  static long $opt$ByteToLong(byte a) { if (doThrow) throw new Error(); return (long)a; }
+  static long $opt$ShortToLong(short a) { if (doThrow) throw new Error(); return (long)a; }
+  static long $opt$IntToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
+  static long $opt$CharToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
 
   // These methods produce int-to-float Dex instructions.
-  static float $opt$ByteToFloat(byte a) { return (float)a; }
-  static float $opt$ShortToFloat(short a) { return (float)a; }
-  static float $opt$IntToFloat(int a) { return (float)a; }
-  static float $opt$CharToFloat(char a) { return (float)a; }
+  static float $opt$ByteToFloat(byte a) { if (doThrow) throw new Error(); return (float)a; }
+  static float $opt$ShortToFloat(short a) { if (doThrow) throw new Error(); return (float)a; }
+  static float $opt$IntToFloat(int a) { if (doThrow) throw new Error(); return (float)a; }
+  static float $opt$CharToFloat(char a) { if (doThrow) throw new Error(); return (float)a; }
 
   // These methods produce int-to-double Dex instructions.
-  static double $opt$ByteToDouble(byte a) { return (double)a; }
-  static double $opt$ShortToDouble(short a) { return (double)a; }
-  static double $opt$IntToDouble(int a) { return (double)a; }
-  static double $opt$CharToDouble(int a) { return (double)a; }
+  static double $opt$ByteToDouble(byte a) { if (doThrow) throw new Error(); return (double)a; }
+  static double $opt$ShortToDouble(short a) { if (doThrow) throw new Error(); return (double)a; }
+  static double $opt$IntToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
+  static double $opt$CharToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
 
   // These methods produce long-to-int Dex instructions.
-  static int $opt$LongToInt(long a) { return (int)a; }
-  static int $opt$LongLiteralToInt() { return (int)42L; }
+  static int $opt$LongToInt(long a) { if (doThrow) throw new Error(); return (int)a; }
+  static int $opt$LongLiteralToInt() { if (doThrow) throw new Error(); return (int)42L; }
 
   // This method produces a long-to-float Dex instruction.
-  static float $opt$LongToFloat(long a) { return (float)a; }
+  static float $opt$LongToFloat(long a) { if (doThrow) throw new Error(); return (float)a; }
 
   // This method produces a long-to-double Dex instruction.
-  static double $opt$LongToDouble(long a) { return (double)a; }
+  static double $opt$LongToDouble(long a) { if (doThrow) throw new Error(); return (double)a; }
 
   // This method produces a float-to-int Dex instruction.
-  static int $opt$FloatToInt(float a) { return (int)a; }
+  static int $opt$FloatToInt(float a) { if (doThrow) throw new Error(); return (int)a; }
 
   // This method produces a float-to-long Dex instruction.
-  static long $opt$FloatToLong(float a){ return (long)a; }
+  static long $opt$FloatToLong(float a){ if (doThrow) throw new Error(); return (long)a; }
 
   // This method produces a float-to-double Dex instruction.
-  static double $opt$FloatToDouble(float a) { return (double)a; }
+  static double $opt$FloatToDouble(float a) { if (doThrow) throw new Error(); return (double)a; }
 
   // This method produces a double-to-int Dex instruction.
-  static int $opt$DoubleToInt(double a){ return (int)a; }
+  static int $opt$DoubleToInt(double a){ if (doThrow) throw new Error(); return (int)a; }
 
   // This method produces a double-to-long Dex instruction.
-  static long $opt$DoubleToLong(double a){ return (long)a; }
+  static long $opt$DoubleToLong(double a){ if (doThrow) throw new Error(); return (long)a; }
 
   // This method produces a double-to-float Dex instruction.
-  static float $opt$DoubleToFloat(double a) { return (float)a; }
+  static float $opt$DoubleToFloat(double a) { if (doThrow) throw new Error(); return (float)a; }
 
   // These methods produce int-to-byte Dex instructions.
-  static byte $opt$ShortToByte(short a) { return (byte)a; }
-  static byte $opt$IntToByte(int a) { return (byte)a; }
-  static byte $opt$CharToByte(char a) { return (byte)a; }
+  static byte $opt$ShortToByte(short a) { if (doThrow) throw new Error(); return (byte)a; }
+  static byte $opt$IntToByte(int a) { if (doThrow) throw new Error(); return (byte)a; }
+  static byte $opt$CharToByte(char a) { if (doThrow) throw new Error(); return (byte)a; }
 
   // These methods produce int-to-short Dex instructions.
-  static short $opt$ByteToShort(byte a) { return (short)a; }
-  static short $opt$IntToShort(int a) { return (short)a; }
-  static short $opt$CharToShort(char a) { return (short)a; }
+  static short $opt$ByteToShort(byte a) { if (doThrow) throw new Error(); return (short)a; }
+  static short $opt$IntToShort(int a) { if (doThrow) throw new Error(); return (short)a; }
+  static short $opt$CharToShort(char a) { if (doThrow) throw new Error(); return (short)a; }
 
   // These methods produce int-to-char Dex instructions.
-  static char $opt$ByteToChar(byte a) { return (char)a; }
-  static char $opt$ShortToChar(short a) { return (char)a; }
-  static char $opt$IntToChar(int a) { return (char)a; }
+  static char $opt$ByteToChar(byte a) { if (doThrow) throw new Error(); return (char)a; }
+  static char $opt$ShortToChar(short a) { if (doThrow) throw new Error(); return (char)a; }
+  static char $opt$IntToChar(int a) { if (doThrow) throw new Error(); return (char)a; }
 }
diff --git a/test/441-checker-inliner/src/Main.java b/test/441-checker-inliner/src/Main.java
index 631b140..8894d4e 100644
--- a/test/441-checker-inliner/src/Main.java
+++ b/test/441-checker-inliner/src/Main.java
@@ -17,9 +17,9 @@
 public class Main {
 
   // CHECK-START: void Main.InlineVoid() inliner (before)
-  // CHECK-DAG:     [[Const42:i\d+]] IntConstant 42
+  // CHECK-DAG:     <<Const42:i\d+>> IntConstant 42
   // CHECK-DAG:                      InvokeStaticOrDirect
-  // CHECK-DAG:                      InvokeStaticOrDirect [ [[Const42]] ]
+  // CHECK-DAG:                      InvokeStaticOrDirect [<<Const42>>]
 
   // CHECK-START: void Main.InlineVoid() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
@@ -30,94 +30,94 @@
   }
 
   // CHECK-START: int Main.InlineParameter(int) inliner (before)
-  // CHECK-DAG:     [[Param:i\d+]]  ParameterValue
-  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect [ [[Param]] ]
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  // CHECK-DAG:     <<Param:i\d+>>  ParameterValue
+  // CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<Param>>]
+  // CHECK-DAG:                     Return [<<Result>>]
 
   // CHECK-START: int Main.InlineParameter(int) inliner (after)
-  // CHECK-DAG:     [[Param:i\d+]]  ParameterValue
-  // CHECK-DAG:                     Return [ [[Param]] ]
+  // CHECK-DAG:     <<Param:i\d+>>  ParameterValue
+  // CHECK-DAG:                     Return [<<Param>>]
 
   public static int InlineParameter(int a) {
     return returnParameter(a);
   }
 
   // CHECK-START: long Main.InlineWideParameter(long) inliner (before)
-  // CHECK-DAG:     [[Param:j\d+]]  ParameterValue
-  // CHECK-DAG:     [[Result:j\d+]] InvokeStaticOrDirect [ [[Param]] ]
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  // CHECK-DAG:     <<Param:j\d+>>  ParameterValue
+  // CHECK-DAG:     <<Result:j\d+>> InvokeStaticOrDirect [<<Param>>]
+  // CHECK-DAG:                     Return [<<Result>>]
 
   // CHECK-START: long Main.InlineWideParameter(long) inliner (after)
-  // CHECK-DAG:     [[Param:j\d+]]  ParameterValue
-  // CHECK-DAG:                     Return [ [[Param]] ]
+  // CHECK-DAG:     <<Param:j\d+>>  ParameterValue
+  // CHECK-DAG:                     Return [<<Param>>]
 
   public static long InlineWideParameter(long a) {
     return returnWideParameter(a);
   }
 
   // CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (before)
-  // CHECK-DAG:     [[Param:l\d+]]  ParameterValue
-  // CHECK-DAG:     [[Result:l\d+]] InvokeStaticOrDirect [ [[Param]] ]
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  // CHECK-DAG:     <<Param:l\d+>>  ParameterValue
+  // CHECK-DAG:     <<Result:l\d+>> InvokeStaticOrDirect [<<Param>>]
+  // CHECK-DAG:                     Return [<<Result>>]
 
   // CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (after)
-  // CHECK-DAG:     [[Param:l\d+]]  ParameterValue
-  // CHECK-DAG:                     Return [ [[Param]] ]
+  // CHECK-DAG:     <<Param:l\d+>>  ParameterValue
+  // CHECK-DAG:                     Return [<<Param>>]
 
   public static Object InlineReferenceParameter(Object o) {
     return returnReferenceParameter(o);
   }
 
   // CHECK-START: int Main.InlineInt() inliner (before)
-  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  // CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [<<Result>>]
 
   // CHECK-START: int Main.InlineInt() inliner (after)
-  // CHECK-DAG:     [[Const4:i\d+]] IntConstant 4
-  // CHECK-DAG:                     Return [ [[Const4]] ]
+  // CHECK-DAG:     <<Const4:i\d+>> IntConstant 4
+  // CHECK-DAG:                     Return [<<Const4>>]
 
   public static int InlineInt() {
     return returnInt();
   }
 
   // CHECK-START: long Main.InlineWide() inliner (before)
-  // CHECK-DAG:     [[Result:j\d+]] InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  // CHECK-DAG:     <<Result:j\d+>> InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [<<Result>>]
 
   // CHECK-START: long Main.InlineWide() inliner (after)
-  // CHECK-DAG:     [[Const8:j\d+]] LongConstant 8
-  // CHECK-DAG:                     Return [ [[Const8]] ]
+  // CHECK-DAG:     <<Const8:j\d+>> LongConstant 8
+  // CHECK-DAG:                     Return [<<Const8>>]
 
   public static long InlineWide() {
     return returnWide();
   }
 
   // CHECK-START: int Main.InlineAdd() inliner (before)
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  // CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  // CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  // CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [<<Result>>]
 
   // CHECK-START: int Main.InlineAdd() inliner (after)
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]    Add [ [[Const3]] [[Const5]] ]
-  // CHECK-DAG:                     Return [ [[Add]] ]
+  // CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  // CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  // CHECK-DAG:     <<Add:i\d+>>    Add [<<Const3>>,<<Const5>>]
+  // CHECK-DAG:                     Return [<<Add>>]
 
   public static int InlineAdd() {
     return returnAdd(3, 5);
   }
 
   // CHECK-START: int Main.InlineFieldAccess() inliner (before)
-  // CHECK-DAG:     [[After:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[After]] ]
+  // CHECK-DAG:     <<After:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [<<After>>]
 
   // CHECK-START: int Main.InlineFieldAccess() inliner (after)
-  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
-  // CHECK-DAG:     [[Before:i\d+]] StaticFieldGet
-  // CHECK-DAG:     [[After:i\d+]]  Add [ [[Before]] [[Const1]] ]
-  // CHECK-DAG:                     StaticFieldSet [ {{l\d+}} [[After]] ]
-  // CHECK-DAG:                     Return [ [[After]] ]
+  // CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
+  // CHECK-DAG:     <<Before:i\d+>> StaticFieldGet
+  // CHECK-DAG:     <<After:i\d+>>  Add [<<Before>>,<<Const1>>]
+  // CHECK-DAG:                     StaticFieldSet [{{l\d+}},<<After>>]
+  // CHECK-DAG:                     Return [<<After>>]
 
   // CHECK-START: int Main.InlineFieldAccess() inliner (after)
   // CHECK-NOT:                     InvokeStaticOrDirect
@@ -127,22 +127,22 @@
   }
 
   // CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (before)
-  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]    InvokeStaticOrDirect [ [[Const1]] [[Const3]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]    InvokeStaticOrDirect [ [[Const5]] [[Const3]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]    Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                     Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
+  // CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  // CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  // CHECK-DAG:     <<Add:i\d+>>    InvokeStaticOrDirect [<<Const1>>,<<Const3>>]
+  // CHECK-DAG:     <<Sub:i\d+>>    InvokeStaticOrDirect [<<Const5>>,<<Const3>>]
+  // CHECK-DAG:     <<Phi:i\d+>>    Phi [<<Add>>,<<Sub>>]
+  // CHECK-DAG:                     Return [<<Phi>>]
 
   // CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
-  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]    Add [ [[Const1]] [[Const3]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]    Sub [ [[Const5]] [[Const3]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]    Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                     Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
+  // CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  // CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  // CHECK-DAG:     <<Add:i\d+>>    Add [<<Const1>>,<<Const3>>]
+  // CHECK-DAG:     <<Sub:i\d+>>    Sub [<<Const5>>,<<Const3>>]
+  // CHECK-DAG:     <<Phi:i\d+>>    Phi [<<Add>>,<<Sub>>]
+  // CHECK-DAG:                     Return [<<Phi>>]
 
   public static int InlineWithControlFlow(boolean cond) {
     int x, const1, const3, const5;
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 6b21fed..c258db9 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -16,6 +16,12 @@
 
 public class Main {
 
+  public static void assertFalse(boolean condition) {
+    if (condition) {
+      throw new Error();
+    }
+  }
+
   public static void assertIntEquals(int expected, int result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
@@ -28,19 +34,31 @@
     }
   }
 
+  public static void assertFloatEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertDoubleEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
   /**
    * Tiny three-register program exercising int constant folding
    * on negation.
    */
 
   // CHECK-START: int Main.IntNegation() constant_folding (before)
-  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Const42]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Const42:i\d+>>  IntConstant 42
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Const42>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   // CHECK-START: int Main.IntNegation() constant_folding (after)
-  // CHECK-DAG:     [[ConstN42:i\d+]] IntConstant -42
-  // CHECK-DAG:                       Return [ [[ConstN42]] ]
+  // CHECK-DAG:     <<ConstN42:i\d+>> IntConstant -42
+  // CHECK-DAG:                       Return [<<ConstN42>>]
 
   public static int IntNegation() {
     int x, y;
@@ -55,14 +73,14 @@
    */
 
   // CHECK-START: int Main.IntAddition1() constant_folding (before)
-  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[Const1]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  // CHECK-DAG:     <<Const1:i\d+>>  IntConstant 1
+  // CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  // CHECK-DAG:     <<Add:i\d+>>     Add [<<Const1>>,<<Const2>>]
+  // CHECK-DAG:                      Return [<<Add>>]
 
   // CHECK-START: int Main.IntAddition1() constant_folding (after)
-  // CHECK-DAG:     [[Const3:i\d+]]  IntConstant 3
-  // CHECK-DAG:                      Return [ [[Const3]] ]
+  // CHECK-DAG:     <<Const3:i\d+>>  IntConstant 3
+  // CHECK-DAG:                      Return [<<Const3>>]
 
   public static int IntAddition1() {
     int a, b, c;
@@ -78,18 +96,18 @@
   */
 
   // CHECK-START: int Main.IntAddition2() constant_folding (before)
-  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Const5:i\d+]]  IntConstant 5
-  // CHECK-DAG:     [[Const6:i\d+]]  IntConstant 6
-  // CHECK-DAG:     [[Add1:i\d+]]    Add [ [[Const1]] [[Const2]] ]
-  // CHECK-DAG:     [[Add2:i\d+]]    Add [ [[Const5]] [[Const6]] ]
-  // CHECK-DAG:     [[Add3:i\d+]]    Add [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                      Return [ [[Add3]] ]
+  // CHECK-DAG:     <<Const1:i\d+>>  IntConstant 1
+  // CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  // CHECK-DAG:     <<Const5:i\d+>>  IntConstant 5
+  // CHECK-DAG:     <<Const6:i\d+>>  IntConstant 6
+  // CHECK-DAG:     <<Add1:i\d+>>    Add [<<Const1>>,<<Const2>>]
+  // CHECK-DAG:     <<Add2:i\d+>>    Add [<<Const5>>,<<Const6>>]
+  // CHECK-DAG:     <<Add3:i\d+>>    Add [<<Add1>>,<<Add2>>]
+  // CHECK-DAG:                      Return [<<Add3>>]
 
   // CHECK-START: int Main.IntAddition2() constant_folding (after)
-  // CHECK-DAG:     [[Const14:i\d+]] IntConstant 14
-  // CHECK-DAG:                      Return [ [[Const14]] ]
+  // CHECK-DAG:     <<Const14:i\d+>> IntConstant 14
+  // CHECK-DAG:                      Return [<<Const14>>]
 
   public static int IntAddition2() {
     int a, b, c;
@@ -109,14 +127,14 @@
    */
 
   // CHECK-START: int Main.IntSubtraction() constant_folding (before)
-  // CHECK-DAG:     [[Const6:i\d+]]  IntConstant 6
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[Const6]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Const6:i\d+>>  IntConstant 6
+  // CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  // CHECK-DAG:     <<Sub:i\d+>>     Sub [<<Const6>>,<<Const2>>]
+  // CHECK-DAG:                      Return [<<Sub>>]
 
   // CHECK-START: int Main.IntSubtraction() constant_folding (after)
-  // CHECK-DAG:     [[Const4:i\d+]]  IntConstant 4
-  // CHECK-DAG:                      Return [ [[Const4]] ]
+  // CHECK-DAG:     <<Const4:i\d+>>  IntConstant 4
+  // CHECK-DAG:                      Return [<<Const4>>]
 
   public static int IntSubtraction() {
     int a, b, c;
@@ -132,14 +150,14 @@
    */
 
   // CHECK-START: long Main.LongAddition() constant_folding (before)
-  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
-  // CHECK-DAG:     [[Const2:j\d+]]  LongConstant 2
-  // CHECK-DAG:     [[Add:j\d+]]     Add [ [[Const1]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  // CHECK-DAG:     <<Const1:j\d+>>  LongConstant 1
+  // CHECK-DAG:     <<Const2:j\d+>>  LongConstant 2
+  // CHECK-DAG:     <<Add:j\d+>>     Add [<<Const1>>,<<Const2>>]
+  // CHECK-DAG:                      Return [<<Add>>]
 
   // CHECK-START: long Main.LongAddition() constant_folding (after)
-  // CHECK-DAG:     [[Const3:j\d+]]  LongConstant 3
-  // CHECK-DAG:                      Return [ [[Const3]] ]
+  // CHECK-DAG:     <<Const3:j\d+>>  LongConstant 3
+  // CHECK-DAG:                      Return [<<Const3>>]
 
   public static long LongAddition() {
     long a, b, c;
@@ -155,14 +173,14 @@
    */
 
   // CHECK-START: long Main.LongSubtraction() constant_folding (before)
-  // CHECK-DAG:     [[Const6:j\d+]]  LongConstant 6
-  // CHECK-DAG:     [[Const2:j\d+]]  LongConstant 2
-  // CHECK-DAG:     [[Sub:j\d+]]     Sub [ [[Const6]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Const6:j\d+>>  LongConstant 6
+  // CHECK-DAG:     <<Const2:j\d+>>  LongConstant 2
+  // CHECK-DAG:     <<Sub:j\d+>>     Sub [<<Const6>>,<<Const2>>]
+  // CHECK-DAG:                      Return [<<Sub>>]
 
   // CHECK-START: long Main.LongSubtraction() constant_folding (after)
-  // CHECK-DAG:     [[Const4:j\d+]]  LongConstant 4
-  // CHECK-DAG:                      Return [ [[Const4]] ]
+  // CHECK-DAG:     <<Const4:j\d+>>  LongConstant 4
+  // CHECK-DAG:                      Return [<<Const4>>]
 
   public static long LongSubtraction() {
     long a, b, c;
@@ -177,14 +195,14 @@
    */
 
   // CHECK-START: int Main.StaticCondition() constant_folding (before)
-  // CHECK-DAG:     [[Const7:i\d+]]  IntConstant 7
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Cond:z\d+]]    GreaterThanOrEqual [ [[Const7]] [[Const2]] ]
-  // CHECK-DAG:                      If [ [[Cond]] ]
+  // CHECK-DAG:     <<Const7:i\d+>>  IntConstant 7
+  // CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  // CHECK-DAG:     <<Cond:z\d+>>    GreaterThanOrEqual [<<Const7>>,<<Const2>>]
+  // CHECK-DAG:                      If [<<Cond>>]
 
   // CHECK-START: int Main.StaticCondition() constant_folding (after)
-  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
-  // CHECK-DAG:                      If [ [[Const1]] ]
+  // CHECK-DAG:     <<Const1:i\d+>>  IntConstant 1
+  // CHECK-DAG:                      If [<<Const1>>]
 
   public static int StaticCondition() {
     int a, b, c;
@@ -207,18 +225,18 @@
    */
 
   // CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (before)
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Const5:i\d+]]  IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[Const5]] [[Const2]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[Const5]] [[Const2]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  // CHECK-DAG:     <<Const5:i\d+>>  IntConstant 5
+  // CHECK-DAG:     <<Add:i\d+>>     Add [<<Const5>>,<<Const2>>]
+  // CHECK-DAG:     <<Sub:i\d+>>     Sub [<<Const5>>,<<Const2>>]
+  // CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Add>>,<<Sub>>]
+  // CHECK-DAG:                      Return [<<Phi>>]
 
   // CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (after)
-  // CHECK-DAG:     [[Const3:i\d+]]  IntConstant 3
-  // CHECK-DAG:     [[Const7:i\d+]]  IntConstant 7
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Const7]] [[Const3]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Const3:i\d+>>  IntConstant 3
+  // CHECK-DAG:     <<Const7:i\d+>>  IntConstant 7
+  // CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Const7>>,<<Const3>>]
+  // CHECK-DAG:                      Return [<<Phi>>]
 
   public static int JumpsAndConditionals(boolean cond) {
     int a, b, c;
@@ -236,177 +254,393 @@
    */
 
   // CHECK-START: int Main.And0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[And:i\d+]]      And [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[And]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<And:i\d+>>      And [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<And>>]
 
   // CHECK-START: int Main.And0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
   // CHECK-NOT:                       And
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static int And0(int arg) {
     return arg & 0;
   }
 
   // CHECK-START: long Main.Mul0(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Mul:j\d+]]      Mul [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Mul]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  // CHECK-DAG:     <<Mul:j\d+>>      Mul [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Mul>>]
 
   // CHECK-START: long Main.Mul0(long) constant_folding (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
   // CHECK-NOT:                       Mul
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static long Mul0(long arg) {
     return arg * 0;
   }
 
   // CHECK-START: int Main.OrAllOnes(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF:i\d+]]   IntConstant -1
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Arg]] [[ConstF]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstF:i\d+>>   IntConstant -1
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Arg>>,<<ConstF>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.OrAllOnes(int) constant_folding (after)
-  // CHECK-DAG:     [[ConstF:i\d+]]   IntConstant -1
+  // CHECK-DAG:     <<ConstF:i\d+>>   IntConstant -1
   // CHECK-NOT:                       Or
-  // CHECK-DAG:                       Return [ [[ConstF]] ]
+  // CHECK-DAG:                       Return [<<ConstF>>]
 
   public static int OrAllOnes(int arg) {
     return arg | -1;
   }
 
   // CHECK-START: long Main.Rem0(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]           ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]        LongConstant 0
-  // CHECK-DAG:     [[DivZeroCheck:j\d+]]  DivZeroCheck [ [[Arg]] ]
-  // CHECK-DAG:     [[Rem:j\d+]]           Rem [ [[Const0]] [[DivZeroCheck]] ]
-  // CHECK-DAG:                            Return [ [[Rem]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>           ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
+  // CHECK-DAG:     <<DivZeroCheck:j\d+>>  DivZeroCheck [<<Arg>>]
+  // CHECK-DAG:     <<Rem:j\d+>>           Rem [<<Const0>>,<<DivZeroCheck>>]
+  // CHECK-DAG:                            Return [<<Rem>>]
 
   // CHECK-START: long Main.Rem0(long) constant_folding (after)
-  // CHECK-DAG:     [[Const0:j\d+]]        LongConstant 0
+  // CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
   // CHECK-NOT:                            Rem
-  // CHECK-DAG:                            Return [ [[Const0]] ]
+  // CHECK-DAG:                            Return [<<Const0>>]
 
   public static long Rem0(long arg) {
     return 0 % arg;
   }
 
   // CHECK-START: int Main.Rem1(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Rem:i\d+]]      Rem [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       Return [ [[Rem]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Rem:i\d+>>      Rem [<<Arg>>,<<Const1>>]
+  // CHECK-DAG:                       Return [<<Rem>>]
 
   // CHECK-START: int Main.Rem1(int) constant_folding (after)
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
   // CHECK-NOT:                       Rem
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static int Rem1(int arg) {
     return arg % 1;
   }
 
   // CHECK-START: long Main.RemN1(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]           ParameterValue
-  // CHECK-DAG:     [[ConstN1:j\d+]]       LongConstant -1
-  // CHECK-DAG:     [[DivZeroCheck:j\d+]]  DivZeroCheck [ [[Arg]] ]
-  // CHECK-DAG:     [[Rem:j\d+]]           Rem [ [[Arg]] [[DivZeroCheck]] ]
-  // CHECK-DAG:                            Return [ [[Rem]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>           ParameterValue
+  // CHECK-DAG:     <<ConstN1:j\d+>>       LongConstant -1
+  // CHECK-DAG:     <<DivZeroCheck:j\d+>>  DivZeroCheck [<<ConstN1>>]
+  // CHECK-DAG:     <<Rem:j\d+>>           Rem [<<Arg>>,<<DivZeroCheck>>]
+  // CHECK-DAG:                            Return [<<Rem>>]
 
   // CHECK-START: long Main.RemN1(long) constant_folding (after)
-  // CHECK-DAG:     [[Const0:j\d+]]        LongConstant 0
+  // CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
   // CHECK-NOT:                            Rem
-  // CHECK-DAG:                            Return [ [[Const0]] ]
+  // CHECK-DAG:                            Return [<<Const0>>]
 
   public static long RemN1(long arg) {
     return arg % -1;
   }
 
   // CHECK-START: int Main.Shl0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Shl:i\d+]]      Shl [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Shl]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Shl>>]
 
   // CHECK-START: int Main.Shl0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
   // CHECK-NOT:                       Shl
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static int Shl0(int arg) {
     return 0 << arg;
   }
 
   // CHECK-START: long Main.Shr0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Shr:j\d+]]      Shr [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Shr]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  // CHECK-DAG:     <<Shr:j\d+>>      Shr [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Shr>>]
 
   // CHECK-START: long Main.Shr0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
   // CHECK-NOT:                       Shr
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static long Shr0(int arg) {
     return (long)0 >> arg;
   }
 
   // CHECK-START: long Main.SubSameLong(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Arg>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: long Main.SubSameLong(long) constant_folding (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
   // CHECK-NOT:                       Sub
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static long SubSameLong(long arg) {
     return arg - arg;
   }
 
   // CHECK-START: int Main.UShr0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[UShr:i\d+]]     UShr [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[UShr]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<UShr:i\d+>>     UShr [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<UShr>>]
 
   // CHECK-START: int Main.UShr0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
   // CHECK-NOT:                       UShr
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static int UShr0(int arg) {
     return 0 >>> arg;
   }
 
   // CHECK-START: int Main.XorSameInt(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Xor:i\d+]]      Xor [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Xor]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Xor:i\d+>>      Xor [<<Arg>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Xor>>]
 
   // CHECK-START: int Main.XorSameInt(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
   // CHECK-NOT:                       Xor
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  // CHECK-DAG:                       Return [<<Const0>>]
 
   public static int XorSameInt(int arg) {
     return arg ^ arg;
   }
 
+  // CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (before)
+  // CHECK-DAG:     <<Arg:f\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstNan:f\d+>> FloatConstant nan
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:                       IntConstant 1
+  // CHECK-DAG:     <<Cmp:i\d+>>      Compare [<<Arg>>,<<ConstNan>>]
+  // CHECK-DAG:     <<Le:z\d+>>       LessThanOrEqual [<<Cmp>>,<<Const0>>]
+  // CHECK-DAG:                       If [<<Le>>]
+
+  // CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (after)
+  // CHECK-DAG:                       ParameterValue
+  // CHECK-DAG:                       FloatConstant nan
+  // CHECK-DAG:                       IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:                       If [<<Const1>>]
+
+  // CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (after)
+  // CHECK-NOT:                       Compare
+  // CHECK-NOT:                       LessThanOrEqual
+
+  public static boolean CmpFloatGreaterThanNaN(float arg) {
+    return arg > Float.NaN;
+  }
+
+  // CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (before)
+  // CHECK-DAG:     <<Arg:d\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstNan:d\d+>> DoubleConstant nan
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:                       IntConstant 1
+  // CHECK-DAG:     <<Cmp:i\d+>>      Compare [<<Arg>>,<<ConstNan>>]
+  // CHECK-DAG:     <<Ge:z\d+>>       GreaterThanOrEqual [<<Cmp>>,<<Const0>>]
+  // CHECK-DAG:                       If [<<Ge>>]
+
+  // CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (after)
+  // CHECK-DAG:                       ParameterValue
+  // CHECK-DAG:                       DoubleConstant nan
+  // CHECK-DAG:                       IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:                       If [<<Const1>>]
+
+  // CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (after)
+  // CHECK-NOT:                       Compare
+  // CHECK-NOT:                       GreaterThanOrEqual
+
+  public static boolean CmpDoubleLessThanNaN(double arg) {
+    return arg < Double.NaN;
+  }
+
+  // CHECK-START: int Main.ReturnInt33() constant_folding (before)
+  // CHECK-DAG:     <<Const33:j\d+>>  LongConstant 33
+  // CHECK-DAG:     <<Convert:i\d+>>  TypeConversion [<<Const33>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: int Main.ReturnInt33() constant_folding (after)
+  // CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  // CHECK-DAG:                       Return [<<Const33>>]
+
+  public static int ReturnInt33() {
+    long imm = 33L;
+    return (int) imm;
+  }
+
+  // CHECK-START: int Main.ReturnIntMax() constant_folding (before)
+  // CHECK-DAG:     <<ConstMax:f\d+>> FloatConstant 1e+34
+  // CHECK-DAG:     <<Convert:i\d+>>  TypeConversion [<<ConstMax>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: int Main.ReturnIntMax() constant_folding (after)
+  // CHECK-DAG:     <<ConstMax:i\d+>> IntConstant 2147483647
+  // CHECK-DAG:                       Return [<<ConstMax>>]
+
+  public static int ReturnIntMax() {
+    float imm = 1.0e34f;
+    return (int) imm;
+  }
+
+  // CHECK-START: int Main.ReturnInt0() constant_folding (before)
+  // CHECK-DAG:     <<ConstNaN:d\d+>> DoubleConstant nan
+  // CHECK-DAG:     <<Convert:i\d+>>  TypeConversion [<<ConstNaN>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: int Main.ReturnInt0() constant_folding (after)
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:                       Return [<<Const0>>]
+
+  public static int ReturnInt0() {
+    double imm = Double.NaN;
+    return (int) imm;
+  }
+
+  // CHECK-START: long Main.ReturnLong33() constant_folding (before)
+  // CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  // CHECK-DAG:     <<Convert:j\d+>>  TypeConversion [<<Const33>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: long Main.ReturnLong33() constant_folding (after)
+  // CHECK-DAG:     <<Const33:j\d+>>  LongConstant 33
+  // CHECK-DAG:                       Return [<<Const33>>]
+
+  public static long ReturnLong33() {
+    int imm = 33;
+    return (long) imm;
+  }
+
+  // CHECK-START: long Main.ReturnLong34() constant_folding (before)
+  // CHECK-DAG:     <<Const34:f\d+>>  FloatConstant 34
+  // CHECK-DAG:     <<Convert:j\d+>>  TypeConversion [<<Const34>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: long Main.ReturnLong34() constant_folding (after)
+  // CHECK-DAG:     <<Const34:j\d+>>  LongConstant 34
+  // CHECK-DAG:                       Return [<<Const34>>]
+
+  public static long ReturnLong34() {
+    float imm = 34.0f;
+    return (long) imm;
+  }
+
+  // CHECK-START: long Main.ReturnLong0() constant_folding (before)
+  // CHECK-DAG:     <<ConstNaN:d\d+>> DoubleConstant nan
+  // CHECK-DAG:     <<Convert:j\d+>>  TypeConversion [<<ConstNaN>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: long Main.ReturnLong0() constant_folding (after)
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  // CHECK-DAG:                       Return [<<Const0>>]
+
+  public static long ReturnLong0() {
+    double imm = -Double.NaN;
+    return (long) imm;
+  }
+
+  // CHECK-START: float Main.ReturnFloat33() constant_folding (before)
+  // CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  // CHECK-DAG:     <<Convert:f\d+>>  TypeConversion [<<Const33>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: float Main.ReturnFloat33() constant_folding (after)
+  // CHECK-DAG:     <<Const33:f\d+>>  FloatConstant 33
+  // CHECK-DAG:                       Return [<<Const33>>]
+
+  public static float ReturnFloat33() {
+    int imm = 33;
+    return (float) imm;
+  }
+
+  // CHECK-START: float Main.ReturnFloat34() constant_folding (before)
+  // CHECK-DAG:     <<Const34:j\d+>>  LongConstant 34
+  // CHECK-DAG:     <<Convert:f\d+>>  TypeConversion [<<Const34>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: float Main.ReturnFloat34() constant_folding (after)
+  // CHECK-DAG:     <<Const34:f\d+>>  FloatConstant 34
+  // CHECK-DAG:                       Return [<<Const34>>]
+
+  public static float ReturnFloat34() {
+    long imm = 34L;
+    return (float) imm;
+  }
+
+  // CHECK-START: float Main.ReturnFloat99P25() constant_folding (before)
+  // CHECK-DAG:     <<Const:d\d+>>    DoubleConstant 99.25
+  // CHECK-DAG:     <<Convert:f\d+>>  TypeConversion [<<Const>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: float Main.ReturnFloat99P25() constant_folding (after)
+  // CHECK-DAG:     <<Const:f\d+>>    FloatConstant 99.25
+  // CHECK-DAG:                       Return [<<Const>>]
+
+  public static float ReturnFloat99P25() {
+    double imm = 99.25;
+    return (float) imm;
+  }
+
+  // CHECK-START: double Main.ReturnDouble33() constant_folding (before)
+  // CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  // CHECK-DAG:     <<Convert:d\d+>>  TypeConversion [<<Const33>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: double Main.ReturnDouble33() constant_folding (after)
+  // CHECK-DAG:     <<Const33:d\d+>>  DoubleConstant 33
+  // CHECK-DAG:                       Return [<<Const33>>]
+
+  public static double ReturnDouble33() {
+    int imm = 33;
+    return (double) imm;
+  }
+
+  // CHECK-START: double Main.ReturnDouble34() constant_folding (before)
+  // CHECK-DAG:     <<Const34:j\d+>>  LongConstant 34
+  // CHECK-DAG:     <<Convert:d\d+>>  TypeConversion [<<Const34>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: double Main.ReturnDouble34() constant_folding (after)
+  // CHECK-DAG:     <<Const34:d\d+>>  DoubleConstant 34
+  // CHECK-DAG:                       Return [<<Const34>>]
+
+  public static double ReturnDouble34() {
+    long imm = 34L;
+    return (double) imm;
+  }
+
+  // CHECK-START: double Main.ReturnDouble99P25() constant_folding (before)
+  // CHECK-DAG:     <<Const:f\d+>>    FloatConstant 99.25
+  // CHECK-DAG:     <<Convert:d\d+>>  TypeConversion [<<Const>>]
+  // CHECK-DAG:                       Return [<<Convert>>]
+
+  // CHECK-START: double Main.ReturnDouble99P25() constant_folding (after)
+  // CHECK-DAG:     <<Const:d\d+>>    DoubleConstant 99.25
+  // CHECK-DAG:                       Return [<<Const>>]
+
+  public static double ReturnDouble99P25() {
+    float imm = 99.25f;
+    return (double) imm;
+  }
+
   public static void main(String[] args) {
     assertIntEquals(IntNegation(), -42);
     assertIntEquals(IntAddition1(), 3);
@@ -417,17 +651,31 @@
     assertIntEquals(StaticCondition(), 5);
     assertIntEquals(JumpsAndConditionals(true), 7);
     assertIntEquals(JumpsAndConditionals(false), 3);
-    int random = 123456;  // Chosen randomly.
-    assertIntEquals(And0(random), 0);
-    assertLongEquals(Mul0(random), 0);
-    assertIntEquals(OrAllOnes(random), -1);
-    assertLongEquals(Rem0(random), 0);
-    assertIntEquals(Rem1(random), 0);
-    assertLongEquals(RemN1(random), 0);
-    assertIntEquals(Shl0(random), 0);
-    assertLongEquals(Shr0(random), 0);
-    assertLongEquals(SubSameLong(random), 0);
-    assertIntEquals(UShr0(random), 0);
-    assertIntEquals(XorSameInt(random), 0);
+    int arbitrary = 123456;  // Value chosen arbitrarily.
+    assertIntEquals(And0(arbitrary), 0);
+    assertLongEquals(Mul0(arbitrary), 0);
+    assertIntEquals(OrAllOnes(arbitrary), -1);
+    assertLongEquals(Rem0(arbitrary), 0);
+    assertIntEquals(Rem1(arbitrary), 0);
+    assertLongEquals(RemN1(arbitrary), 0);
+    assertIntEquals(Shl0(arbitrary), 0);
+    assertLongEquals(Shr0(arbitrary), 0);
+    assertLongEquals(SubSameLong(arbitrary), 0);
+    assertIntEquals(UShr0(arbitrary), 0);
+    assertIntEquals(XorSameInt(arbitrary), 0);
+    assertFalse(CmpFloatGreaterThanNaN(arbitrary));
+    assertFalse(CmpDoubleLessThanNaN(arbitrary));
+    assertIntEquals(ReturnInt33(), 33);
+    assertIntEquals(ReturnIntMax(), 2147483647);
+    assertIntEquals(ReturnInt0(), 0);
+    assertLongEquals(ReturnLong33(), 33);
+    assertLongEquals(ReturnLong34(), 34);
+    assertLongEquals(ReturnLong0(), 0);
+    assertFloatEquals(ReturnFloat33(), 33);
+    assertFloatEquals(ReturnFloat34(), 34);
+    assertFloatEquals(ReturnFloat99P25(), 99.25f);
+    assertDoubleEquals(ReturnDouble33(), 33);
+    assertDoubleEquals(ReturnDouble34(), 34);
+    assertDoubleEquals(ReturnDouble99P25(), 99.25);
   }
 }
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index 91ac2ed..96918d3 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -17,13 +17,13 @@
 public class Main {
 
   // CHECK-START: int Main.div() licm (before)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  // CHECK-DAG: Div loop:{{B\d+}}
 
   // CHECK-START: int Main.div() licm (after)
-  // CHECK-NOT: Div ( loop_header:{{B\d+}} )
+  // CHECK-NOT: Div loop:{{B\d+}}
 
   // CHECK-START: int Main.div() licm (after)
-  // CHECK-DAG: Div ( loop_header:null )
+  // CHECK-DAG: Div loop:none
 
   public static int div() {
     int result = 0;
@@ -34,13 +34,13 @@
   }
 
   // CHECK-START: int Main.innerDiv() licm (before)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  // CHECK-DAG: Div loop:{{B\d+}}
 
   // CHECK-START: int Main.innerDiv() licm (after)
-  // CHECK-NOT: Div ( loop_header:{{B\d+}} )
+  // CHECK-NOT: Div loop:{{B\d+}}
 
   // CHECK-START: int Main.innerDiv() licm (after)
-  // CHECK-DAG: Div ( loop_header:null )
+  // CHECK-DAG: Div loop:none
 
   public static int innerDiv() {
     int result = 0;
@@ -53,10 +53,10 @@
   }
 
   // CHECK-START: int Main.innerDiv2() licm (before)
-  // CHECK-DAG: Mul ( loop_header:{{B4}} )
+  // CHECK-DAG: Mul loop:B4
 
   // CHECK-START: int Main.innerDiv2() licm (after)
-  // CHECK-DAG: Mul ( loop_header:{{B2}} )
+  // CHECK-DAG: Mul loop:B2
 
   public static int innerDiv2() {
     int result = 0;
@@ -72,10 +72,10 @@
   }
 
   // CHECK-START: int Main.innerDiv3(int, int) licm (before)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  // CHECK-DAG: Div loop:{{B\d+}}
 
   // CHECK-START: int Main.innerDiv3(int, int) licm (after)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  // CHECK-DAG: Div loop:{{B\d+}}
 
   public static int innerDiv3(int a, int b) {
     int result = 0;
@@ -88,16 +88,16 @@
   }
 
   // CHECK-START: int Main.arrayLength(int[]) licm (before)
-  // CHECK-DAG: [[NullCheck:l\d+]] NullCheck ( loop_header:{{B\d+}} )
-  // CHECK-DAG:                    ArrayLength [ [[NullCheck]] ] ( loop_header:{{B\d+}} )
+  // CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:{{B\d+}}
+  // CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:{{B\d+}}
 
   // CHECK-START: int Main.arrayLength(int[]) licm (after)
-  // CHECK-NOT:                    NullCheck ( loop_header:{{B\d+}} )
-  // CHECK-NOT:                    ArrayLength ( loop_header:{{B\d+}} )
+  // CHECK-NOT:                    NullCheck loop:{{B\d+}}
+  // CHECK-NOT:                    ArrayLength loop:{{B\d+}}
 
   // CHECK-START: int Main.arrayLength(int[]) licm (after)
-  // CHECK-DAG: [[NullCheck:l\d+]] NullCheck ( loop_header:null )
-  // CHECK-DAG:                    ArrayLength [ [[NullCheck]] ] ( loop_header:null )
+  // CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:none
+  // CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:none
 
   public static int arrayLength(int[] array) {
     int result = 0;
diff --git a/test/446-checker-inliner2/src/Main.java b/test/446-checker-inliner2/src/Main.java
index ecf071e..9ed66d6 100644
--- a/test/446-checker-inliner2/src/Main.java
+++ b/test/446-checker-inliner2/src/Main.java
@@ -17,15 +17,15 @@
 public class Main {
 
   // CHECK-START: int Main.inlineInstanceCall(Main) inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
-  // CHECK-DAG:     [[Field:i\d+]]   InstanceFieldGet
-  // CHECK-DAG:                      Return [ [[Field]] ]
+  // CHECK-DAG:     <<Field:i\d+>>   InstanceFieldGet
+  // CHECK-DAG:                      Return [<<Field>>]
 
   public static int inlineInstanceCall(Main m) {
     return m.foo();
@@ -38,15 +38,15 @@
   int field = 42;
 
   // CHECK-START: int Main.inlineNestedCall() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.inlineNestedCall() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: int Main.inlineNestedCall() inliner (after)
-  // CHECK-DAG:     [[Const38:i\d+]] IntConstant 38
-  // CHECK-DAG:                      Return [ [[Const38]] ]
+  // CHECK-DAG:     <<Const38:i\d+>> IntConstant 38
+  // CHECK-DAG:                      Return [<<Const38>>]
 
   public static int inlineNestedCall() {
     return nestedCall();
diff --git a/test/447-checker-inliner3/src/Main.java b/test/447-checker-inliner3/src/Main.java
index db4b236..9d022b9 100644
--- a/test/447-checker-inliner3/src/Main.java
+++ b/test/447-checker-inliner3/src/Main.java
@@ -17,8 +17,8 @@
 public class Main {
 
   // CHECK-START: int Main.inlineIfThenElse() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.inlineIfThenElse() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index efb7b83..742210c 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -51,14 +51,14 @@
    */
 
   // CHECK-START: long Main.Add0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]  LongConstant 0
-  // CHECK-DAG:     [[Add:j\d+]]     Add [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>  LongConstant 0
+  // CHECK-DAG:     <<Add:j\d+>>     Add [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                      Return [<<Add>>]
 
   // CHECK-START: long Main.Add0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  // CHECK-DAG:                      Return [<<Arg>>]
 
   // CHECK-START: long Main.Add0(long) instruction_simplifier (after)
   // CHECK-NOT:                        Add
@@ -68,14 +68,14 @@
   }
 
   // CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[ConstF:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[And:i\d+]]     And [ [[Arg]] [[ConstF]] ]
-  // CHECK-DAG:                      Return [ [[And]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<ConstF:i\d+>>  IntConstant -1
+  // CHECK-DAG:     <<And:i\d+>>     And [<<Arg>>,<<ConstF>>]
+  // CHECK-DAG:                      Return [<<And>>]
 
   // CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  // CHECK-DAG:                      Return [<<Arg>>]
 
   // CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
   // CHECK-NOT:                      And
@@ -85,14 +85,14 @@
   }
 
   // CHECK-START: long Main.Div1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
-  // CHECK-DAG:     [[Div:j\d+]]     Div [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                      Return [ [[Div]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Const1:j\d+>>  LongConstant 1
+  // CHECK-DAG:     <<Div:j\d+>>     Div [<<Arg>>,<<Const1>>]
+  // CHECK-DAG:                      Return [<<Div>>]
 
   // CHECK-START: long Main.Div1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  // CHECK-DAG:                      Return [<<Arg>>]
 
   // CHECK-START: long Main.Div1(long) instruction_simplifier (after)
   // CHECK-NOT:                      Div
@@ -102,15 +102,15 @@
   }
 
   // CHECK-START: int Main.DivN1(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstN1:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[Div:i\d+]]      Div [ [[Arg]] [[ConstN1]] ]
-  // CHECK-DAG:                       Return [ [[Div]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstN1:i\d+>>  IntConstant -1
+  // CHECK-DAG:     <<Div:i\d+>>      Div [<<Arg>>,<<ConstN1>>]
+  // CHECK-DAG:                       Return [<<Div>>]
 
   // CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   // CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
   // CHECK-NOT:                       Div
@@ -120,14 +120,14 @@
   }
 
   // CHECK-START: long Main.Mul1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
-  // CHECK-DAG:     [[Mul:j\d+]]     Mul [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                      Return [ [[Mul]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Const1:j\d+>>  LongConstant 1
+  // CHECK-DAG:     <<Mul:j\d+>>     Mul [<<Arg>>,<<Const1>>]
+  // CHECK-DAG:                      Return [<<Mul>>]
 
   // CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  // CHECK-DAG:                      Return [<<Arg>>]
 
   // CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
   // CHECK-NOT:                       Mul
@@ -137,15 +137,15 @@
   }
 
   // CHECK-START: int Main.MulN1(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstN1:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[Mul:i\d+]]      Mul [ [[Arg]] [[ConstN1]] ]
-  // CHECK-DAG:                       Return [ [[Mul]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstN1:i\d+>>  IntConstant -1
+  // CHECK-DAG:     <<Mul:i\d+>>      Mul [<<Arg>>,<<ConstN1>>]
+  // CHECK-DAG:                       Return [<<Mul>>]
 
   // CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   // CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
   // CHECK-NOT:                       Mul
@@ -155,16 +155,16 @@
   }
 
   // CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:     [[Const128:j\d+]]  LongConstant 128
-  // CHECK-DAG:     [[Mul:j\d+]]       Mul [ [[Arg]] [[Const128]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  // CHECK-DAG:     <<Const128:j\d+>>  LongConstant 128
+  // CHECK-DAG:     <<Mul:j\d+>>       Mul [<<Arg>>,<<Const128>>]
+  // CHECK-DAG:                        Return [<<Mul>>]
 
   // CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:     [[Const7:i\d+]]    IntConstant 7
-  // CHECK-DAG:     [[Shl:j\d+]]       Shl [ [[Arg]] [[Const7]] ]
-  // CHECK-DAG:                        Return [ [[Shl]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  // CHECK-DAG:     <<Const7:i\d+>>    IntConstant 7
+  // CHECK-DAG:     <<Shl:j\d+>>       Shl [<<Arg>>,<<Const7>>]
+  // CHECK-DAG:                        Return [<<Shl>>]
 
   // CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
   // CHECK-NOT:                        Mul
@@ -174,14 +174,14 @@
   }
 
   // CHECK-START: int Main.Or0(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.Or0(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: int Main.Or0(int) instruction_simplifier (after)
   // CHECK-NOT:                       Or
@@ -191,13 +191,13 @@
   }
 
   // CHECK-START: long Main.OrSame(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:     [[Or:j\d+]]        Or [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                        Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  // CHECK-DAG:     <<Or:j\d+>>        Or [<<Arg>>,<<Arg>>]
+  // CHECK-DAG:                        Return [<<Or>>]
 
   // CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:                        Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  // CHECK-DAG:                        Return [<<Arg>>]
 
   // CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
   // CHECK-NOT:                        Or
@@ -207,14 +207,14 @@
   }
 
   // CHECK-START: int Main.Shl0(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Shl:i\d+]]      Shl [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Shl]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Shl>>]
 
   // CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
   // CHECK-NOT:                       Shl
@@ -224,15 +224,15 @@
   }
 
   // CHECK-START: int Main.Shl1(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Shl:i\d+]]      Shl [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       Return [ [[Shl]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Arg>>,<<Const1>>]
+  // CHECK-DAG:                       Return [<<Shl>>]
 
   // CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Arg>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Add>>]
 
   // CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
   // CHECK-NOT:                       Shl
@@ -242,14 +242,14 @@
   }
 
   // CHECK-START: long Main.Shr0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Shr:j\d+]]      Shr [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Shr]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Shr:j\d+>>      Shr [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Shr>>]
 
   // CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
   // CHECK-NOT:                       Shr
@@ -259,14 +259,14 @@
   }
 
   // CHECK-START: long Main.Sub0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  // CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
   // CHECK-NOT:                       Sub
@@ -276,15 +276,15 @@
   }
 
   // CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   // CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
   // CHECK-NOT:                       Sub
@@ -294,14 +294,14 @@
   }
 
   // CHECK-START: long Main.UShr0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[UShr:j\d+]]     UShr [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[UShr]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<UShr:j\d+>>     UShr [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<UShr>>]
 
   // CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
   // CHECK-NOT:                       UShr
@@ -311,14 +311,14 @@
   }
 
   // CHECK-START: int Main.Xor0(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Xor:i\d+]]      Xor [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Xor]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Xor:i\d+>>      Xor [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Xor>>]
 
   // CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
   // CHECK-NOT:                       Xor
@@ -328,15 +328,15 @@
   }
 
   // CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF:i\d+]]   IntConstant -1
-  // CHECK-DAG:     [[Xor:i\d+]]      Xor [ [[Arg]] [[ConstF]] ]
-  // CHECK-DAG:                       Return [ [[Xor]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstF:i\d+>>   IntConstant -1
+  // CHECK-DAG:     <<Xor:i\d+>>      Xor [<<Arg>>,<<ConstF>>]
+  // CHECK-DAG:                       Return [<<Xor>>]
 
   // CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Not:i\d+]]      Not [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Not]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Not:i\d+>>      Not [<<Arg>>]
+  // CHECK-DAG:                       Return [<<Not>>]
 
   // CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
   // CHECK-NOT:                       Xor
@@ -353,20 +353,20 @@
    */
 
   // CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:                       Return [<<Add>>]
 
   // CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
   // CHECK-NOT:                       Neg
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Add]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Arg1>>,<<Arg2>>]
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Add>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   public static int AddNegs1(int arg1, int arg2) {
     return -arg1 + -arg2;
@@ -384,34 +384,34 @@
    */
 
   // CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Add2:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  // CHECK-DAG:     <<Add1:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:     <<Add2:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Add1>>,<<Add2>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Add2:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  // CHECK-DAG:     <<Add1:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:     <<Add2:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
   // CHECK-NOT:                       Neg
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Add1>>,<<Add2>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.AddNegs2(int, int) GVN (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Add]] [[Add]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Add>>,<<Add>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   public static int AddNegs2(int arg1, int arg2) {
     int temp1 = -arg1;
@@ -429,26 +429,26 @@
 
   // CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (before)
   // -------------- Arguments and initial negation operations.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:j\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:j\d+]]     Neg [ [[Arg2]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg1:j\d+>>     Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Neg2:j\d+>>     Neg [<<Arg2>>]
   // CHECK:                           Goto
   // -------------- Loop
   // CHECK:                           SuspendCheck
-  // CHECK:         [[Add:j\d+]]      Add [ [[Neg1]] [[Neg2]] ]
+  // CHECK:         <<Add:j\d+>>      Add [<<Neg1>>,<<Neg2>>]
   // CHECK:                           Goto
 
   // CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (after)
   // -------------- Arguments and initial negation operations.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:j\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:j\d+]]     Neg [ [[Arg2]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg1:j\d+>>     Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Neg2:j\d+>>     Neg [<<Arg2>>]
   // CHECK:                           Goto
   // -------------- Loop
   // CHECK:                           SuspendCheck
-  // CHECK:         [[Add:j\d+]]      Add [ [[Neg1]] [[Neg2]] ]
+  // CHECK:         <<Add:j\d+>>      Add [<<Neg1>>,<<Neg2>>]
   // CHECK-NOT:                       Neg
   // CHECK:                           Goto
 
@@ -469,17 +469,17 @@
    */
 
   // CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Add:j\d+]]      Add [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Add:j\d+>>      Add [<<Neg>>,<<Arg2>>]
+  // CHECK-DAG:                       Return [<<Add>>]
 
   // CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Arg2]] [[Arg1]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Arg2>>,<<Arg1>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
   // CHECK-NOT:                       Neg
@@ -499,22 +499,22 @@
    */
 
   // CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Add2:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Res:j\d+]]      Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Res]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg2>>]
+  // CHECK-DAG:     <<Add1:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  // CHECK-DAG:     <<Add2:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  // CHECK-DAG:     <<Res:j\d+>>      Or [<<Add1>>,<<Add2>>]
+  // CHECK-DAG:                       Return [<<Res>>]
 
   // CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Add2:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Res:j\d+]]      Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Res]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg2>>]
+  // CHECK-DAG:     <<Add1:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  // CHECK-DAG:     <<Add2:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  // CHECK-DAG:     <<Res:j\d+>>      Or [<<Add1>>,<<Add2>>]
+  // CHECK-DAG:                       Return [<<Res>>]
 
   // CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
   // CHECK-NOT:                       Sub
@@ -530,14 +530,14 @@
    */
 
   // CHECK-START: long Main.NegNeg1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg1:j\d+]]     Neg [ [[Arg]] ]
-  // CHECK-DAG:     [[Neg2:j\d+]]     Neg [ [[Neg1]] ]
-  // CHECK-DAG:                       Return [ [[Neg2]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Neg1:j\d+>>     Neg [<<Arg>>]
+  // CHECK-DAG:     <<Neg2:j\d+>>     Neg [<<Neg1>>]
+  // CHECK-DAG:                       Return [<<Neg2>>]
 
   // CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
   // CHECK-NOT:                       Neg
@@ -554,26 +554,26 @@
    */
 
   // CHECK-START: int Main.NegNeg2(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Neg1]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Neg1>>]
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:                       Return [<<Add>>]
 
   // CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
   // CHECK-NOT:                       Neg
   // CHECK-NOT:                       Add
 
   // CHECK-START: int Main.NegNeg2(int) constant_folding_after_inlining (after)
-  // CHECK:         [[Const0:i\d+]]   IntConstant 0
+  // CHECK:         <<Const0:i\d+>>   IntConstant 0
   // CHECK-NOT:                       Neg
   // CHECK-NOT:                       Add
-  // CHECK:                           Return [ [[Const0]] ]
+  // CHECK:                           Return [<<Const0>>]
 
   public static int NegNeg2(int arg) {
     int temp = -arg;
@@ -588,15 +588,15 @@
    */
 
   // CHECK-START: long Main.NegNeg3(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Const0]] [[Neg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  // CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg>>]
+  // CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Const0>>,<<Neg>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
   // CHECK-NOT:                       Neg
@@ -613,17 +613,17 @@
    */
 
   // CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Sub]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg1>>,<<Arg2>>]
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Sub>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   // CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg2]] [[Arg1]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg2>>,<<Arg1>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
   // CHECK-NOT:                       Neg
@@ -643,22 +643,22 @@
    */
 
   // CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg1>>,<<Arg2>>]
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Sub>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Sub>>]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg1>>,<<Arg2>>]
+  // CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Sub>>]
+  // CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Sub>>]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Neg1>>,<<Neg2>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   public static int NegSub2(int arg1, int arg2) {
     int temp = arg1 - arg2;
@@ -671,15 +671,15 @@
    */
 
   // CHECK-START: long Main.NotNot1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF1:j\d+]]  LongConstant -1
-  // CHECK-DAG:     [[Xor1:j\d+]]     Xor [ [[Arg]] [[ConstF1]] ]
-  // CHECK-DAG:     [[Xor2:j\d+]]     Xor [ [[Xor1]] [[ConstF1]] ]
-  // CHECK-DAG:                       Return [ [[Xor2]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstF1:j\d+>>  LongConstant -1
+  // CHECK-DAG:     <<Xor1:j\d+>>     Xor [<<Arg>>,<<ConstF1>>]
+  // CHECK-DAG:     <<Xor2:j\d+>>     Xor [<<Xor1>>,<<ConstF1>>]
+  // CHECK-DAG:                       Return [<<Xor2>>]
 
   // CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  // CHECK-DAG:                       Return [<<Arg>>]
 
   // CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
   // CHECK-NOT:                       Xor
@@ -689,18 +689,18 @@
   }
 
   // CHECK-START: int Main.NotNot2(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF1:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[Xor1:i\d+]]     Xor [ [[Arg]] [[ConstF1]] ]
-  // CHECK-DAG:     [[Xor2:i\d+]]     Xor [ [[Xor1]] [[ConstF1]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Xor1]] [[Xor2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<ConstF1:i\d+>>  IntConstant -1
+  // CHECK-DAG:     <<Xor1:i\d+>>     Xor [<<Arg>>,<<ConstF1>>]
+  // CHECK-DAG:     <<Xor2:i\d+>>     Xor [<<Xor1>>,<<ConstF1>>]
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Xor1>>,<<Xor2>>]
+  // CHECK-DAG:                       Return [<<Add>>]
 
   // CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Not:i\d+]]      Not [ [[Arg]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Not]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  // CHECK-DAG:     <<Not:i\d+>>      Not [<<Arg>>]
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Not>>,<<Arg>>]
+  // CHECK-DAG:                       Return [<<Add>>]
 
   // CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
   // CHECK-NOT:                       Xor
@@ -716,18 +716,18 @@
    */
 
   // CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Neg>>,<<Arg2>>]
+  // CHECK-DAG:                       Return [<<Sub>>]
 
   // CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Add]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Add:i\d+>>      Add [<<Arg1>>,<<Arg2>>]
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Add>>]
+  // CHECK-DAG:                       Return [<<Neg>>]
 
   // CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
   // CHECK-NOT:                       Sub
@@ -747,22 +747,22 @@
    */
 
   // CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Sub1:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Sub2:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Sub1]] [[Sub2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Sub1:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  // CHECK-DAG:     <<Sub2:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Sub1>>,<<Sub2>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Sub1:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Sub2:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Sub1]] [[Sub2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  // CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg1>>]
+  // CHECK-DAG:     <<Sub1:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  // CHECK-DAG:     <<Sub2:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  // CHECK-DAG:     <<Or:i\d+>>       Or [<<Sub1>>,<<Sub2>>]
+  // CHECK-DAG:                       Return [<<Or>>]
 
   // CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
   // CHECK-NOT:                       Add
@@ -781,24 +781,24 @@
 
   // CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (before)
   // -------------- Arguments and initial negation operation.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg1]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg1>>]
   // CHECK:                           Goto
   // -------------- Loop
   // CHECK:                           SuspendCheck
-  // CHECK:         [[Sub:j\d+]]      Sub [ [[Neg]] [[Arg2]] ]
+  // CHECK:         <<Sub:j\d+>>      Sub [<<Neg>>,<<Arg2>>]
   // CHECK:                           Goto
 
   // CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (after)
   // -------------- Arguments and initial negation operation.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg1]] ]
+  // CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  // CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg1>>]
   // CHECK-DAG:                       Goto
   // -------------- Loop
   // CHECK:                           SuspendCheck
-  // CHECK:         [[Sub:j\d+]]      Sub [ [[Neg]] [[Arg2]] ]
+  // CHECK:         <<Sub:j\d+>>      Sub [<<Neg>>,<<Arg2>>]
   // CHECK-NOT:                       Neg
   // CHECK:                           Goto
 
@@ -812,116 +812,116 @@
   }
 
   // CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Arg>>,<<Const1>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:                       If [<<Arg>>]
 
   public static int EqualTrueRhs(boolean arg) {
     return (arg != true) ? 3 : 5;
   }
 
   // CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Const1]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Const1>>,<<Arg>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:                       If [<<Arg>>]
 
   public static int EqualTrueLhs(boolean arg) {
     return (true != arg) ? 3 : 5;
   }
 
   // CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  // CHECK-DAG:                       If [<<NotArg>>]
 
   public static int EqualFalseRhs(boolean arg) {
     return (arg != false) ? 3 : 5;
   }
 
   // CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  // CHECK-DAG:                       If [<<NotArg>>]
 
   public static int EqualFalseLhs(boolean arg) {
     return (false != arg) ? 3 : 5;
   }
 
   // CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Arg>>,<<Const1>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  // CHECK-DAG:                       If [<<NotArg>>]
 
   public static int NotEqualTrueRhs(boolean arg) {
     return (arg == true) ? 3 : 5;
   }
 
   // CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Const1]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Const1>>,<<Arg>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  // CHECK-DAG:                       If [<<NotArg>>]
 
   public static int NotEqualTrueLhs(boolean arg) {
     return (true == arg) ? 3 : 5;
   }
 
   // CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Arg>>,<<Const0>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:                       If [<<Arg>>]
 
   public static int NotEqualFalseRhs(boolean arg) {
     return (arg == false) ? 3 : 5;
   }
 
   // CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Const0>>,<<Arg>>]
+  // CHECK-DAG:                       If [<<Cond>>]
 
   // CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  // CHECK-DAG:                       If [<<Arg>>]
 
   public static int NotEqualFalseLhs(boolean arg) {
     return (false == arg) ? 3 : 5;
@@ -934,15 +934,15 @@
    */
 
   // CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (before)
-  // CHECK-DAG:     [[Arg:z\d+]]       ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]    BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:     [[NotNotArg:z\d+]] BooleanNot [ [[NotArg]] ]
-  // CHECK-DAG:                        Return [ [[NotNotArg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>       ParameterValue
+  // CHECK-DAG:     <<NotArg:z\d+>>    BooleanNot [<<Arg>>]
+  // CHECK-DAG:     <<NotNotArg:z\d+>> BooleanNot [<<NotArg>>]
+  // CHECK-DAG:                        Return [<<NotNotArg>>]
 
   // CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (after)
-  // CHECK-DAG:     [[Arg:z\d+]]       ParameterValue
-  // CHECK-DAG:                        BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                        Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:z\d+>>       ParameterValue
+  // CHECK-DAG:                        BooleanNot [<<Arg>>]
+  // CHECK-DAG:                        Return [<<Arg>>]
 
   // CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (after)
   // CHECK:                            BooleanNot
@@ -957,16 +957,16 @@
   }
 
   // CHECK-START: float Main.Div2(float) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[Const2:f\d+]]   FloatConstant 2
-  // CHECK-DAG:      [[Div:f\d+]]      Div [ [[Arg]] [[Const2]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  // CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  // CHECK-DAG:      <<Const2:f\d+>>   FloatConstant 2
+  // CHECK-DAG:      <<Div:f\d+>>      Div [<<Arg>>,<<Const2>>]
+  // CHECK-DAG:                        Return [<<Div>>]
 
   // CHECK-START: float Main.Div2(float) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstP5:f\d+]]  FloatConstant 0.5
-  // CHECK-DAG:      [[Mul:f\d+]]      Mul [ [[Arg]] [[ConstP5]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  // CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  // CHECK-DAG:      <<ConstP5:f\d+>>  FloatConstant 0.5
+  // CHECK-DAG:      <<Mul:f\d+>>      Mul [<<Arg>>,<<ConstP5>>]
+  // CHECK-DAG:                        Return [<<Mul>>]
 
   // CHECK-START: float Main.Div2(float) instruction_simplifier (after)
   // CHECK-NOT:                        Div
@@ -976,16 +976,16 @@
   }
 
   // CHECK-START: double Main.Div2(double) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[Const2:d\d+]]   DoubleConstant 2
-  // CHECK-DAG:      [[Div:d\d+]]      Div [ [[Arg]] [[Const2]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  // CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  // CHECK-DAG:      <<Const2:d\d+>>   DoubleConstant 2
+  // CHECK-DAG:      <<Div:d\d+>>      Div [<<Arg>>,<<Const2>>]
+  // CHECK-DAG:                        Return [<<Div>>]
 
   // CHECK-START: double Main.Div2(double) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstP5:d\d+]]  DoubleConstant 0.5
-  // CHECK-DAG:      [[Mul:d\d+]]      Mul [ [[Arg]] [[ConstP5]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  // CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  // CHECK-DAG:      <<ConstP5:d\d+>>  DoubleConstant 0.5
+  // CHECK-DAG:      <<Mul:d\d+>>      Mul [<<Arg>>,<<ConstP5>>]
+  // CHECK-DAG:                        Return [<<Mul>>]
 
   // CHECK-START: double Main.Div2(double) instruction_simplifier (after)
   // CHECK-NOT:                        Div
@@ -994,16 +994,16 @@
   }
 
   // CHECK-START: float Main.DivMP25(float) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstMP25:f\d+]]   FloatConstant -0.25
-  // CHECK-DAG:      [[Div:f\d+]]      Div [ [[Arg]] [[ConstMP25]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  // CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  // CHECK-DAG:      <<ConstMP25:f\d+>>   FloatConstant -0.25
+  // CHECK-DAG:      <<Div:f\d+>>      Div [<<Arg>>,<<ConstMP25>>]
+  // CHECK-DAG:                        Return [<<Div>>]
 
   // CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstM4:f\d+]]  FloatConstant -4
-  // CHECK-DAG:      [[Mul:f\d+]]      Mul [ [[Arg]] [[ConstM4]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  // CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  // CHECK-DAG:      <<ConstM4:f\d+>>  FloatConstant -4
+  // CHECK-DAG:      <<Mul:f\d+>>      Mul [<<Arg>>,<<ConstM4>>]
+  // CHECK-DAG:                        Return [<<Mul>>]
 
   // CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
   // CHECK-NOT:                        Div
@@ -1013,16 +1013,16 @@
   }
 
   // CHECK-START: double Main.DivMP25(double) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstMP25:d\d+]]   DoubleConstant -0.25
-  // CHECK-DAG:      [[Div:d\d+]]      Div [ [[Arg]] [[ConstMP25]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  // CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  // CHECK-DAG:      <<ConstMP25:d\d+>>   DoubleConstant -0.25
+  // CHECK-DAG:      <<Div:d\d+>>      Div [<<Arg>>,<<ConstMP25>>]
+  // CHECK-DAG:                        Return [<<Div>>]
 
   // CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstM4:d\d+]]  DoubleConstant -4
-  // CHECK-DAG:      [[Mul:d\d+]]      Mul [ [[Arg]] [[ConstM4]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  // CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  // CHECK-DAG:      <<ConstM4:d\d+>>  DoubleConstant -4
+  // CHECK-DAG:      <<Mul:d\d+>>      Mul [<<Arg>>,<<ConstM4>>]
+  // CHECK-DAG:                        Return [<<Mul>>]
 
   // CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
   // CHECK-NOT:                        Div
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 d5563b8..218c7ce 100644
--- a/test/462-checker-inlining-across-dex-files/src/Main.java
+++ b/test/462-checker-inlining-across-dex-files/src/Main.java
@@ -22,7 +22,7 @@
 public class Main {
 
   // CHECK-START: void Main.inlineEmptyMethod() inliner (before)
-  // CHECK-DAG:     [[Invoke:v\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:     <<Invoke:v\d+>>  InvokeStaticOrDirect
   // CHECK-DAG:                      ReturnVoid
 
   // CHECK-START: void Main.inlineEmptyMethod() inliner (after)
@@ -33,120 +33,124 @@
   }
 
   // CHECK-START: int Main.inlineReturnIntMethod() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
-  // CHECK-DAG:     [[Const38:i\d+]] IntConstant 38
-  // CHECK-DAG:                      Return [ [[Const38]] ]
+  // CHECK-DAG:     <<Const38:i\d+>> IntConstant 38
+  // CHECK-DAG:                      Return [<<Const38>>]
 
   public static int inlineReturnIntMethod() {
     return OtherDex.returnIntMethod();
   }
 
   // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   public static int dontInlineOtherDexStatic() {
     return OtherDex.returnOtherDexStatic();
   }
 
   // CHECK-START: int Main.inlineMainStatic() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.inlineMainStatic() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: int Main.inlineMainStatic() inliner (after)
-  // CHECK-DAG:     [[Static:i\d+]]  StaticFieldGet
-  // CHECK-DAG:                      Return [ [[Static]] ]
+  // CHECK-DAG:     <<Static:i\d+>>  StaticFieldGet
+  // CHECK-DAG:                      Return [<<Static>>]
 
   public static int inlineMainStatic() {
     return OtherDex.returnMainStatic();
   }
 
   // CHECK-START: int Main.dontInlineRecursiveCall() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.dontInlineRecursiveCall() inliner (after)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   public static int dontInlineRecursiveCall() {
     return OtherDex.recursiveCall();
   }
 
   // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   public static String dontInlineReturnString() {
     return OtherDex.returnString();
   }
 
   // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   public static Class dontInlineOtherDexClass() {
     return OtherDex.returnOtherDexClass();
   }
 
   // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
-  // CHECK-DAG:     [[Class:l\d+]]  LoadClass
-  // CHECK-DAG:                     Return [ [[Class]] ]
+  // CHECK-DAG:                     Return [<<Class:l\d+>>]
+  // CHECK-DAG:     <<Class>>       LoadClass
+  // 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();
   }
 
   // CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (after)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   public static Class dontInlineOtherDexClassStaticCall() {
     return OtherDex.returnOtherDexClassStaticCall();
   }
 
   // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
-  // CHECK-DAG:     [[Class:l\d+]]  LoadClass
-  // CHECK-DAG:                     Return [ [[Class]] ]
+  // CHECK-DAG:                     Return [<<Class:l\d+>>]
+  // CHECK-DAG:     <<Class>>       LoadClass
+  // 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/test/463-checker-boolean-simplifier/src/Main.java b/test/463-checker-boolean-simplifier/src/Main.java
index 4346103..e237448 100644
--- a/test/463-checker-boolean-simplifier/src/Main.java
+++ b/test/463-checker-boolean-simplifier/src/Main.java
@@ -38,12 +38,12 @@
    */
 
   // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:                       If [ [[Param]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:                       If [<<Param>>]
+  // CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const1>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Phi>>]
 
   // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
   // CHECK:                           Goto
@@ -52,10 +52,10 @@
   // CHECK-NOT:                       Goto
 
   // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[NotParam:z\d+]] BooleanNot [ [[Param]] ]
-  // CHECK-DAG:                       Return [ [[NotParam]] ]
+  // CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<NotParam:z\d+>> BooleanNot [<<Param>>]
+  // CHECK-DAG:                       Return [<<NotParam>>]
 
   // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
   // CHECK-NOT:                       If
@@ -75,22 +75,22 @@
    */
 
   // CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (before)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     GreaterThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const0]] [[Const1]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  // CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     GreaterThan [<<ParamX>>,<<ParamY>>]
+  // CHECK-DAG:                       If [<<Cond>>]
+  // CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const0>>,<<Const1>>]
+  // CHECK-DAG:                       Return [<<Phi>>]
 
   // CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (after)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     GreaterThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       Return [ [[Cond]] ]
+  // CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     GreaterThan [<<ParamX>>,<<ParamY>>]
+  // CHECK-DAG:                       Return [<<Cond>>]
 
   public static boolean GreaterThan(int x, int y) {
     return (x <= y) ? false : true;
@@ -102,22 +102,22 @@
    */
 
   // CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (before)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     GreaterThanOrEqual [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  // CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     GreaterThanOrEqual [<<ParamX>>,<<ParamY>>]
+  // CHECK-DAG:                       If [<<Cond>>]
+  // CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const1>>,<<Const0>>]
+  // CHECK-DAG:                       Return [<<Phi>>]
 
   // CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     LessThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       Return [ [[Cond]] ]
+  // CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<Cond:z\d+>>     LessThan [<<ParamX>>,<<ParamY>>]
+  // CHECK-DAG:                       Return [<<Cond>>]
 
   // CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
   // CHECK-NOT:                       GreaterThanOrEqual
@@ -132,51 +132,51 @@
    */
 
   // CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (before)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamZ:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[CondXY:z\d+]]   GreaterThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       If [ [[CondXY]] ]
-  // CHECK-DAG:     [[CondYZ:z\d+]]   GreaterThan [ [[ParamY]] [[ParamZ]] ]
-  // CHECK-DAG:                       If [ [[CondYZ]] ]
-  // CHECK-DAG:     [[CondXYZ:z\d+]]  NotEqual [ [[PhiXY:i\d+]] [[PhiYZ:i\d+]] ]
-  // CHECK-DAG:                       If [ [[CondXYZ]] ]
-  // CHECK-DAG:                       Return [ [[PhiXYZ:i\d+]] ]
-  // CHECK-DAG:     [[PhiXY]]         Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:     [[PhiYZ]]         Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:     [[PhiXYZ]]        Phi [ [[Const1]] [[Const0]] ]
+  // CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamZ:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  // CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  // CHECK-DAG:     <<CondXY:z\d+>>   GreaterThan [<<ParamX>>,<<ParamY>>]
+  // CHECK-DAG:                       If [<<CondXY>>]
+  // CHECK-DAG:     <<CondYZ:z\d+>>   GreaterThan [<<ParamY>>,<<ParamZ>>]
+  // CHECK-DAG:                       If [<<CondYZ>>]
+  // CHECK-DAG:     <<CondXYZ:z\d+>>  NotEqual [<<PhiXY:i\d+>>,<<PhiYZ:i\d+>>]
+  // CHECK-DAG:                       If [<<CondXYZ>>]
+  // CHECK-DAG:                       Return [<<PhiXYZ:i\d+>>]
+  // CHECK-DAG:     <<PhiXY>>         Phi [<<Const1>>,<<Const0>>]
+  // CHECK-DAG:     <<PhiYZ>>         Phi [<<Const1>>,<<Const0>>]
+  // CHECK-DAG:     <<PhiXYZ>>        Phi [<<Const1>>,<<Const0>>]
 
   // CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (after)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamZ:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[CmpXY:z\d+]]    LessThanOrEqual [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:     [[CmpYZ:z\d+]]    LessThanOrEqual [ [[ParamY]] [[ParamZ]] ]
-  // CHECK-DAG:     [[CmpXYZ:z\d+]]   Equal [ [[CmpXY]] [[CmpYZ]] ]
-  // CHECK-DAG:                       Return [ [[CmpXYZ]] ]
+  // CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<ParamZ:i\d+>>   ParameterValue
+  // CHECK-DAG:     <<CmpXY:z\d+>>    LessThanOrEqual [<<ParamX>>,<<ParamY>>]
+  // CHECK-DAG:     <<CmpYZ:z\d+>>    LessThanOrEqual [<<ParamY>>,<<ParamZ>>]
+  // CHECK-DAG:     <<CmpXYZ:z\d+>>   Equal [<<CmpXY>>,<<CmpYZ>>]
+  // CHECK-DAG:                       Return [<<CmpXYZ>>]
 
   public static boolean ValuesOrdered(int x, int y, int z) {
     return (x <= y) == (y <= z);
   }
 
   // CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (before)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
-  // CHECK-DAG:     [[Const43:i\d+]]  IntConstant 43
-  // CHECK-DAG:     [[NotParam:z\d+]] BooleanNot [ [[Param]] ]
-  // CHECK-DAG:                       If [ [[NotParam]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const42]] [[Const43]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  // CHECK-DAG:     <<Const42:i\d+>>  IntConstant 42
+  // CHECK-DAG:     <<Const43:i\d+>>  IntConstant 43
+  // CHECK-DAG:     <<NotParam:z\d+>> BooleanNot [<<Param>>]
+  // CHECK-DAG:                       If [<<NotParam>>]
+  // CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const42>>,<<Const43>>]
+  // CHECK-DAG:                       Return [<<Phi>>]
 
   // CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
-  // CHECK-DAG:     [[Const43:i\d+]]  IntConstant 43
-  // CHECK-DAG:                       If [ [[Param]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const42]] [[Const43]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  // CHECK-DAG:     <<Const42:i\d+>>  IntConstant 42
+  // CHECK-DAG:     <<Const43:i\d+>>  IntConstant 43
+  // CHECK-DAG:                       If [<<Param>>]
+  // CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const42>>,<<Const43>>]
+  // CHECK-DAG:                       Return [<<Phi>>]
 
   // Note: The fact that branches are swapped is verified by running the test.
 
diff --git a/test/464-checker-inline-sharpen-calls/src/Main.java b/test/464-checker-inline-sharpen-calls/src/Main.java
index 1b25b42..e451f70 100644
--- a/test/464-checker-inline-sharpen-calls/src/Main.java
+++ b/test/464-checker-inline-sharpen-calls/src/Main.java
@@ -20,7 +20,7 @@
   }
 
   // CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (before)
-  // CHECK-DAG:     [[Invoke:v\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:     <<Invoke:v\d+>>  InvokeStaticOrDirect
   // CHECK-DAG:                      ReturnVoid
 
   // CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (after)
@@ -31,15 +31,15 @@
   }
 
   // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  // CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [<<Invoke>>]
 
   // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
   // CHECK-NOT:                      InvokeStaticOrDirect
 
   // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
-  // CHECK-DAG:     [[Field:i\d+]]   InstanceFieldGet
-  // CHECK-DAG:                      Return [ [[Field]] ]
+  // CHECK-DAG:     <<Field:i\d+>>   InstanceFieldGet
+  // CHECK-DAG:                      Return [<<Field>>]
 
   public static int inlineSharpenStringInvoke() {
     return "Foo".length();
diff --git a/test/465-checker-clinit-gvn/src/Main.java b/test/465-checker-clinit-gvn/src/Main.java
index dcaef6f..ac2863c 100644
--- a/test/465-checker-clinit-gvn/src/Main.java
+++ b/test/465-checker-clinit-gvn/src/Main.java
@@ -27,14 +27,14 @@
 public final class Main {
 
   // CHECK-START: int Main.accessTwoStatics() GVN (before)
-  // CHECK-DAG:     [[Class1:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class1]] ]
-  // CHECK-DAG:     [[Class2:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class2]] ]
+  // CHECK-DAG:     <<Class1:l\d+>>  LoadClass
+  // CHECK-DAG:                      ClinitCheck [<<Class1>>]
+  // CHECK-DAG:     <<Class2:l\d+>>  LoadClass
+  // CHECK-DAG:                      ClinitCheck [<<Class2>>]
 
   // CHECK-START: int Main.accessTwoStatics() GVN (after)
-  // CHECK-DAG:     [[Class:l\d+]]   LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class]] ]
+  // CHECK-DAG:     <<Class:l\d+>>   LoadClass
+  // CHECK-DAG:                      ClinitCheck [<<Class>>]
   // CHECK-NOT:                      ClinitCheck
 
   public static int accessTwoStatics() {
@@ -42,14 +42,14 @@
   }
 
   // CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (before)
-  // CHECK-DAG:     [[Class1:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class1]] ]
-  // CHECK-DAG:     [[Class2:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class2]] ]
+  // CHECK-DAG:     <<Class1:l\d+>>  LoadClass
+  // CHECK-DAG:                      ClinitCheck [<<Class1>>]
+  // CHECK-DAG:     <<Class2:l\d+>>  LoadClass
+  // CHECK-DAG:                      ClinitCheck [<<Class2>>]
 
   // CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (after)
-  // CHECK-DAG:     [[Class:l\d+]]   LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class]] ]
+  // CHECK-DAG:     <<Class:l\d+>>   LoadClass
+  // CHECK-DAG:                      ClinitCheck [<<Class>>]
   // CHECK-NOT:                      ClinitCheck
 
   public static int accessTwoStaticsCallInBetween() {
diff --git a/test/468-checker-bool-simplifier-regression/smali/TestCase.smali b/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
index f36304d..33e6dc3 100644
--- a/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
+++ b/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
@@ -18,6 +18,19 @@
 
 .field public static value:Z
 
+# CHECK-START: boolean TestCase.testCase() boolean_simplifier (before)
+# CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+# CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+# CHECK-DAG:     <<Value:z\d+>>    StaticFieldGet
+# CHECK-DAG:                       If [<<Value>>]
+# CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const1>>,<<Const0>>]
+# CHECK-DAG:                       Return [<<Phi>>]
+
+# CHECK-START: boolean TestCase.testCase() boolean_simplifier (after)
+# CHECK-DAG:     <<Value:z\d+>>    StaticFieldGet
+# CHECK-DAG:     <<Not:z\d+>>      BooleanNot [<<Value>>]
+# CHECK-DAG:                       Return [<<Not>>]
+
 .method public static testCase()Z
     .registers 2
     sget-boolean v0, LTestCase;->value:Z
diff --git a/test/468-checker-bool-simplifier-regression/src/Main.java b/test/468-checker-bool-simplifier-regression/src/Main.java
index d45f3bf..8fe05c7 100644
--- a/test/468-checker-bool-simplifier-regression/src/Main.java
+++ b/test/468-checker-bool-simplifier-regression/src/Main.java
@@ -18,19 +18,6 @@
 
 public class Main {
 
-  // CHECK-START: boolean TestCase.testCase() boolean_simplifier (before)
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Value:z\d+]]    StaticFieldGet
-  // CHECK-DAG:                       If [ [[Value]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
-
-  // CHECK-START: boolean TestCase.testCase() boolean_simplifier (after)
-  // CHECK-DAG:     [[Value:z\d+]]    StaticFieldGet
-  // CHECK-DAG:     [[Not:z\d+]]      BooleanNot [ [[Value]] ]
-  // CHECK-DAG:                       Return [ [[Not]] ]
-
   public static boolean runTest(boolean input) throws Exception {
     Class<?> c = Class.forName("TestCase");
     Method m = c.getMethod("testCase");
diff --git a/test/474-checker-boolean-input/src/Main.java b/test/474-checker-boolean-input/src/Main.java
index 9151986..490f7f9 100644
--- a/test/474-checker-boolean-input/src/Main.java
+++ b/test/474-checker-boolean-input/src/Main.java
@@ -28,8 +28,8 @@
    */
 
   // CHECK-START: boolean Main.TestPhiAsBoolean(int) boolean_simplifier (after)
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi
-  // CHECK-DAG:                      BooleanNot [ [[Phi]] ]
+  // CHECK-DAG:     <<Phi:i\d+>>     Phi
+  // CHECK-DAG:                      BooleanNot [<<Phi>>]
 
   public static boolean f1;
   public static boolean f2;
@@ -48,8 +48,8 @@
    */
 
   // CHECK-START: boolean Main.TestAndAsBoolean(boolean, boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[And:i\d+]]     And
-  // CHECK-DAG:                      BooleanNot [ [[And]] ]
+  // CHECK-DAG:     <<And:i\d+>>     And
+  // CHECK-DAG:                      BooleanNot [<<And>>]
 
   public static boolean InlineAnd(boolean x, boolean y) {
     return x & y;
@@ -65,8 +65,8 @@
    */
 
   // CHECK-START: boolean Main.TestOrAsBoolean(boolean, boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Or:i\d+]]      Or
-  // CHECK-DAG:                      BooleanNot [ [[Or]] ]
+  // CHECK-DAG:     <<Or:i\d+>>      Or
+  // CHECK-DAG:                      BooleanNot [<<Or>>]
 
   public static boolean InlineOr(boolean x, boolean y) {
     return x | y;
@@ -82,8 +82,8 @@
    */
 
   // CHECK-START: boolean Main.TestXorAsBoolean(boolean, boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Xor:i\d+]]     Xor
-  // CHECK-DAG:                      BooleanNot [ [[Xor]] ]
+  // CHECK-DAG:     <<Xor:i\d+>>     Xor
+  // CHECK-DAG:                      BooleanNot [<<Xor>>]
 
   public static boolean InlineXor(boolean x, boolean y) {
     return x ^ y;
diff --git a/test/476-checker-ctor-memory-barrier/src/Main.java b/test/476-checker-ctor-memory-barrier/src/Main.java
index 10aa2ab..f24dc4a 100644
--- a/test/476-checker-ctor-memory-barrier/src/Main.java
+++ b/test/476-checker-ctor-memory-barrier/src/Main.java
@@ -14,10 +14,11 @@
 * limitations under the License.
 */
 
+// TODO: Add more tests after we can inline functions with calls.
 
 class ClassWithoutFinals {
   // CHECK-START: void ClassWithoutFinals.<init>() register (after)
-  // CHECK-NOT: MemoryBarrier {{StoreStore}}
+  // CHECK-NOT: MemoryBarrier kind:StoreStore
   public ClassWithoutFinals() {}
 }
 
@@ -26,9 +27,8 @@
   public ClassWithFinals obj;
 
   // CHECK-START: void ClassWithFinals.<init>(boolean) register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
   public ClassWithFinals(boolean cond) {
     x = 0;
     if (cond) {
@@ -38,18 +38,16 @@
   }
 
   // CHECK-START: void ClassWithFinals.<init>() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
   public ClassWithFinals() {
     x = 0;
   }
 
   // CHECK-START: void ClassWithFinals.<init>(int) register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
   public ClassWithFinals(int x) {
     // This should have two barriers:
     //   - one for the constructor
@@ -61,87 +59,135 @@
 
 class InheritFromClassWithFinals extends ClassWithFinals {
   // CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
 
   // CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
+  // CHECK-NOT:  InvokeStaticOrDirect
   public InheritFromClassWithFinals() {
     // Should inline the super constructor.
   }
 
   // CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
-  // CHECK:     InvokeStaticOrDirect
+  // CHECK:      InvokeStaticOrDirect
 
   // CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
-  // CHECK-NOT: MemoryBarrier {{StoreStore}}
+  // CHECK-NOT:  MemoryBarrier kind:StoreStore
   public InheritFromClassWithFinals(boolean cond) {
     super(cond);
     // should not inline the super constructor
   }
+
+  // CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK:      ReturnVoid
+
+  // CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
+  // CHECK-NOT:  InvokeStaticOrDirect
+  public InheritFromClassWithFinals(int unused) {
+    // Should inline the super constructor and insert a memory barrier.
+
+    // Should inline the new instance call and insert another memory barrier.
+    new InheritFromClassWithFinals();
+  }
 }
 
 class HaveFinalsAndInheritFromClassWithFinals extends ClassWithFinals {
   final int y;
 
   // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
 
   // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
   // CHECK-NOT: InvokeStaticOrDirect
   public HaveFinalsAndInheritFromClassWithFinals() {
-    // Should inline the super constructor.
+    // Should inline the super constructor and remove the memory barrier.
     y = 0;
   }
 
   // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(boolean) register (after)
-  // CHECK:     InvokeStaticOrDirect
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  // CHECK:      InvokeStaticOrDirect
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
   public HaveFinalsAndInheritFromClassWithFinals(boolean cond) {
     super(cond);
     // should not inline the super constructor
     y = 0;
   }
+
+  // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
+
+  // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
+  // CHECK-NOT:  InvokeStaticOrDirect
+  public HaveFinalsAndInheritFromClassWithFinals(int unused) {
+    // Should inline the super constructor and keep just one memory barrier.
+    y = 0;
+
+    // Should inline new instance and keep one barrier.
+    new HaveFinalsAndInheritFromClassWithFinals();
+    // Should inline new instance and keep one barrier.
+    new InheritFromClassWithFinals();
+  }
 }
 
 public class Main {
 
   // CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
-  // CHECK:     InvokeStaticOrDirect
+  // CHECK:      InvokeStaticOrDirect
 
   // CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
-  // CHECK-NOT: MemoryBarrier {{StoreStore}}
+  // CHECK-NOT:  MemoryBarrier kind:StoreStore
   public static ClassWithFinals noInlineNoConstructorBarrier() {
     return new ClassWithFinals(false);
   }
 
-  // CHECK-START: ClassWithFinals Main.inlineConstructorBarrier() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     Return
+  // CHECK-START: void Main.inlineNew() register (after)
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
 
-  // CHECK-START: ClassWithFinals Main.inlineConstructorBarrier() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
-  public static ClassWithFinals inlineConstructorBarrier() {
-    return new ClassWithFinals();
+  // CHECK-START: void Main.inlineNew() register (after)
+  // CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew() {
+    new ClassWithFinals();
   }
 
-  // CHECK-START: InheritFromClassWithFinals Main.doubleInlineConstructorBarrier() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     Return
+  // CHECK-START: void Main.inlineNew1() register (after)
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
 
-  // CHECK-START: InheritFromClassWithFinals Main.doubleInlineConstructorBarrier() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
-  public static InheritFromClassWithFinals doubleInlineConstructorBarrier() {
-    return new InheritFromClassWithFinals();
+  // CHECK-START: void Main.inlineNew1() register (after)
+  // CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew1() {
+    new InheritFromClassWithFinals();
   }
 
-  public static void main(String[] args) {  }
+  // CHECK-START: void Main.inlineNew2() register (after)
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
+
+  // CHECK-START: void Main.inlineNew2() register (after)
+  // CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew2() {
+    new HaveFinalsAndInheritFromClassWithFinals();
+  }
+
+  // CHECK-START: void Main.inlineNew3() register (after)
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK:      MemoryBarrier kind:StoreStore
+  // CHECK-NEXT: ReturnVoid
+
+  // CHECK-START: void Main.inlineNew3() register (after)
+  // CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew3() {
+    new HaveFinalsAndInheritFromClassWithFinals();
+    new HaveFinalsAndInheritFromClassWithFinals();
+  }
+
+  public static void main(String[] args) {}
 }
diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java
index 6da8945..e8739b8 100644
--- a/test/478-checker-clinit-check-pruning/src/Main.java
+++ b/test/478-checker-clinit-check-pruning/src/Main.java
@@ -24,13 +24,13 @@
    */
 
   // CHECK-START: void Main.invokeStaticInlined() builder (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
-  // CHECK-DAG:                           InvokeStaticOrDirect [ [[ClinitCheck]] ]
+  // CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  // CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
+  // CHECK-DAG:                           InvokeStaticOrDirect [<<ClinitCheck>>]
 
   // CHECK-START: void Main.invokeStaticInlined() inliner (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
+  // CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  // CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
 
   // CHECK-START: void Main.invokeStaticInlined() inliner (after)
   // CHECK-NOT:                           InvokeStaticOrDirect
@@ -42,7 +42,7 @@
   // CFG as it is before the next pass (liveness analysis) instead.
 
   // CHECK-START: void Main.invokeStaticInlined() liveness (before)
-  // CHECK-DAG:                           LoadClass
+  // CHECK-DAG:                           LoadClass gen_clinit_check:true
 
   // CHECK-START: void Main.invokeStaticInlined() liveness (before)
   // CHECK-NOT:                           ClinitCheck
@@ -67,14 +67,14 @@
    */
 
   // CHECK-START: void Main.invokeStaticNotInlined() builder (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
-  // CHECK-DAG:                           InvokeStaticOrDirect [ [[ClinitCheck]] ]
+  // CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  // CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
+  // CHECK-DAG:                           InvokeStaticOrDirect [<<ClinitCheck>>]
 
   // CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
-  // CHECK-DAG:                           InvokeStaticOrDirect [ [[ClinitCheck]] ]
+  // CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  // CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
+  // CHECK-DAG:                           InvokeStaticOrDirect [<<ClinitCheck>>]
 
   // The following checks ensure the clinit check and load class
   // instructions added by the builder are pruned by the
@@ -260,6 +260,44 @@
     }
   }
 
+
+  /*
+   * Verify that if we have a static call immediately after the load class
+   * we don't do generate a clinit check.
+   */
+
+  // CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
+  // CHECK-DAG:     <<IntConstant:i\d+>>  IntConstant 0
+  // CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  // CHECK-DAG:                           InvokeStaticOrDirect
+  // CHECK-DAG:                           StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
+
+  // CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
+  // CHECK-NOT:                           ClinitCheck
+
+  static void noClinitBecauseOfInvokeStatic() {
+    ClassWithClinit2.staticMethod();
+    ClassWithClinit2.doThrow = false;
+  }
+
+  /*
+   * Verify that if the static call is after a field access, the load class
+   * will generate a clinit check.
+   */
+
+  // CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
+  // CHECK-DAG:     <<IntConstant:i\d+>>  IntConstant 0
+  // CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:true
+  // CHECK-DAG:                           StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
+  // CHECK-DAG:                           InvokeStaticOrDirect
+
+  // CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
+  // CHECK-NOT:                           ClinitCheck
+  static void clinitBecauseOfFieldAccess() {
+    ClassWithClinit2.doThrow = false;
+    ClassWithClinit2.staticMethod();
+  }
+
   // TODO: Add a test for the case of a static method whose declaring
   // class type index is not available (i.e. when `storage_index`
   // equals `DexFile::kDexNoIndex` in
diff --git a/test/480-checker-dead-blocks/src/Main.java b/test/480-checker-dead-blocks/src/Main.java
index 83dbb26..b76755e 100644
--- a/test/480-checker-dead-blocks/src/Main.java
+++ b/test/480-checker-dead-blocks/src/Main.java
@@ -31,19 +31,19 @@
   }
 
   // CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (before)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
+  // CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  // CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
   // CHECK-DAG:                      If
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Add:i\d+>>     Add [<<ArgX>>,<<ArgY>>]
+  // CHECK-DAG:     <<Sub:i\d+>>     Sub [<<ArgX>>,<<ArgY>>]
+  // CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Add>>,<<Sub>>]
+  // CHECK-DAG:                      Return [<<Phi>>]
 
   // CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  // CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  // CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
+  // CHECK-DAG:     <<Add:i\d+>>     Add [<<ArgX>>,<<ArgY>>]
+  // CHECK-DAG:                      Return [<<Add>>]
 
   // CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
   // CHECK-NOT:                      If
@@ -61,19 +61,19 @@
   }
 
   // CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (before)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
+  // CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  // CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
   // CHECK-DAG:                      If
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  // CHECK-DAG:     <<Add:i\d+>>     Add [<<ArgX>>,<<ArgY>>]
+  // CHECK-DAG:     <<Sub:i\d+>>     Sub [<<ArgX>>,<<ArgY>>]
+  // CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Add>>,<<Sub>>]
+  // CHECK-DAG:                      Return [<<Phi>>]
 
   // CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:                      Return [ [[Sub]] ]
+  // CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  // CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
+  // CHECK-DAG:     <<Sub:i\d+>>     Sub [<<ArgX>>,<<ArgY>>]
+  // CHECK-DAG:                      Return [<<Sub>>]
 
   // CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
   // CHECK-NOT:                      If
@@ -125,8 +125,8 @@
   // CHECK-DAG:                      Add
 
   // CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  // CHECK-DAG:                      Return [<<Arg>>]
 
   // CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
   // CHECK-NOT:                      If
@@ -145,8 +145,8 @@
   // CHECK-DAG:                      Add
 
   // CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  // CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  // CHECK-DAG:                      Return [<<Arg>>]
 
   // CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
   // CHECK-NOT:                      If
diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java
index 74184e8..0ed9267 100644
--- a/test/482-checker-loop-back-edge-use/src/Main.java
+++ b/test/482-checker-loop-back-edge-use/src/Main.java
@@ -18,16 +18,16 @@
 public class Main {
 
   // CHECK-START: void Main.loop1(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 22) }, uses: { 17 22 }
-  // CHECK:         Goto (liveness: 20)
+  // CHECK:         ParameterValue  liveness:2  ranges:{[2,22)} uses:[17,22]
+  // CHECK:         Goto            liveness:20
   public static void loop1(boolean incoming) {
     while (incoming) {}
   }
 
   // CHECK-START: void Main.loop2(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 42) }, uses: { 33 38 42 }
-  // CHECK:         Goto (liveness: 36)
-  // CHECK:         Goto (liveness: 40)
+  // CHECK:         ParameterValue  liveness:2  ranges:{[2,42)} uses:[33,38,42]
+  // CHECK:         Goto            liveness:36
+  // CHECK:         Goto            liveness:40
   public static void loop2(boolean incoming) {
     while (true) {
       System.out.println("foo");
@@ -36,11 +36,11 @@
   }
 
   // CHECK-START: void Main.loop3(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 60) }, uses: { 56 60 }
-  // CHECK:         Goto (liveness: 58)
+  // CHECK:         ParameterValue  liveness:2  ranges:{[2,60)} uses:[56,60]
+  // CHECK:         Goto            liveness:58
 
   // CHECK-START: void Main.loop3(boolean) liveness (after)
-  // CHECK-NOT:     Goto (liveness: 54)
+  // CHECK-NOT:     Goto liveness:54
   public static void loop3(boolean incoming) {
     // 'incoming' only needs a use at the outer loop's back edge.
     while (System.currentTimeMillis() != 42) {
@@ -50,10 +50,10 @@
   }
 
   // CHECK-START: void Main.loop4(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 22) }, uses: { 22 }
+  // CHECK:         ParameterValue  liveness:2  ranges:{[2,22)} uses:[22]
 
   // CHECK-START: void Main.loop4(boolean) liveness (after)
-  // CHECK-NOT:     Goto (liveness: 20)
+  // CHECK-NOT:     Goto            liveness:20
   public static void loop4(boolean incoming) {
     // 'incoming' has no loop use, so should not have back edge uses.
     System.out.println(incoming);
@@ -63,9 +63,9 @@
   }
 
   // CHECK-START: void Main.loop5(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 50) }, uses: { 33 42 46 50 }
-  // CHECK:         Goto (liveness: 44)
-  // CHECK:         Goto (liveness: 48)
+  // CHECK:         ParameterValue  liveness:2  ranges:{[2,50)} uses:[33,42,46,50]
+  // CHECK:         Goto            liveness:44
+  // CHECK:         Goto            liveness:48
   public static void loop5(boolean incoming) {
     // 'incoming' must have a use at both back edges.
     while (Runtime.getRuntime() != null) {
@@ -76,11 +76,11 @@
   }
 
   // CHECK-START: void Main.loop6(boolean) liveness (after)
-  // CHECK          ParameterValue (liveness: 2 ranges: { [2, 46) }, uses: { 24 46 }
-  // CHECK:         Goto (liveness: 44)
+  // CHECK          ParameterValue  liveness:2  ranges:{[2,46)} uses:[24,46]
+  // CHECK:         Goto            liveness:44
 
   // CHECK-START: void Main.loop6(boolean) liveness (after)
-  // CHECK-NOT:     Goto (liveness: 22)
+  // CHECK-NOT:     Goto            liveness:22
   public static void loop6(boolean incoming) {
     // 'incoming' must have a use only at the first loop's back edge.
     while (true) {
@@ -90,9 +90,9 @@
   }
 
   // CHECK-START: void Main.loop7(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 50) }, uses: { 32 41 46 50 }
-  // CHECK:         Goto (liveness: 44)
-  // CHECK:         Goto (liveness: 48)
+  // CHECK:         ParameterValue  liveness:2  ranges:{[2,50)} uses:[32,41,46,50]
+  // CHECK:         Goto            liveness:44
+  // CHECK:         Goto            liveness:48
   public static void loop7(boolean incoming) {
     // 'incoming' must have a use at both back edges.
     while (Runtime.getRuntime() != null) {
@@ -102,9 +102,9 @@
   }
 
   // CHECK-START: void Main.loop8() liveness (after)
-  // CHECK:         StaticFieldGet (liveness: 12 ranges: { [12, 44) }, uses: { 35 40 44 }
-  // CHECK:         Goto (liveness: 38)
-  // CHECK:         Goto (liveness: 42)
+  // CHECK:         StaticFieldGet  liveness:12 ranges:{[12,44)} uses:[35,40,44]
+  // CHECK:         Goto            liveness:38
+  // CHECK:         Goto            liveness:42
   public static void loop8() {
     // 'incoming' must have a use at both back edges.
     boolean incoming = field;
@@ -114,8 +114,8 @@
   }
 
   // CHECK-START: void Main.loop9() liveness (after)
-  // CHECK:         StaticFieldGet (liveness: 22 ranges: { [22, 36) }, uses: { 31 36 }
-  // CHECK:         Goto (liveness: 38)
+  // CHECK:         StaticFieldGet  liveness:22 ranges:{[22,36)} uses:[31,36]
+  // CHECK:         Goto            liveness:38
   public static void loop9() {
     while (Runtime.getRuntime() != null) {
       // 'incoming' must only have a use in the inner loop.
diff --git a/test/485-checker-dce-loop-update/smali/TestCase.smali b/test/485-checker-dce-loop-update/smali/TestCase.smali
index 3873ac5..487a5df 100644
--- a/test/485-checker-dce-loop-update/smali/TestCase.smali
+++ b/test/485-checker-dce-loop-update/smali/TestCase.smali
@@ -24,26 +24,26 @@
 
 
 # CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[Cst1]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX]] [[Cst5]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+# CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+# CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<Cst1>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Add5>>       Add [<<PhiX>>,<<Cst5>>]                    loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+# CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 # CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[AddX:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[AddX]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+# CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<AddX:i\d+>>]               loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<AddX>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+# CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 .method public static testSingleExit(IZ)I
   .registers 3
@@ -74,30 +74,30 @@
 
 
 # CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[Cst1]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX]] [[Cst5]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+# CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+# CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<ArgZ>>]                              loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<Cst1>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Add5>>       Add [<<PhiX>>,<<Cst5>>]                    loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+# CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 # CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add7:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:null
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+# CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add7:i\d+>>]               loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<ArgZ>>]                              loop:none
+# CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 .method public static testMultipleExits(IZZ)I
   .registers 4
@@ -130,36 +130,36 @@
 
 
 # CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[Cst9:i\d+]]  IntConstant 9
-# CHECK-DAG:     [[PhiX1:i\d+]] Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Mul9:i\d+]]  Mul [ [[PhiX1]] [[Cst9]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:     [[PhiX2:i\d+]] Phi [ [[Mul9]] [[PhiX1]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[Cst1]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX2]] [[Cst5]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX1]] [[Cst7]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX2]] ]                         loop_header:null
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+# CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+# CHECK-DAG:     <<Cst9:i\d+>>  IntConstant 9
+# CHECK-DAG:     <<PhiX1:i\d+>> Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<ArgZ>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Mul9:i\d+>>  Mul [<<PhiX1>>,<<Cst9>>]                   loop:<<HeaderY>>
+# CHECK-DAG:     <<PhiX2:i\d+>> Phi [<<Mul9>>,<<PhiX1>>]                   loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<Cst1>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Add5>>       Add [<<PhiX2>>,<<Cst5>>]                   loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX1>>,<<Cst7>>]                   loop:<<HeaderY>>
+# CHECK-DAG:                    Return [<<PhiX2>>]                         loop:none
 
 # CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[Cst9:i\d+]]  IntConstant 9
-# CHECK-DAG:     [[PhiX1:i\d+]] Phi [ [[ArgX]] [[Add7:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX1]] [[Cst7]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:null
-# CHECK-DAG:     [[Mul9:i\d+]]  Mul [ [[PhiX1]] [[Cst9]] ]                   loop_header:null
-# CHECK-DAG:     [[PhiX2:i\d+]] Phi [ [[Mul9]] [[PhiX1]] ]                   loop_header:null
-# CHECK-DAG:                    Return [ [[PhiX2]] ]                         loop_header:null
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+# CHECK-DAG:     <<Cst9:i\d+>>  IntConstant 9
+# CHECK-DAG:     <<PhiX1:i\d+>> Phi [<<ArgX>>,<<Add7:i\d+>>]               loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX1>>,<<Cst7>>]                   loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<ArgZ>>]                              loop:none
+# CHECK-DAG:     <<Mul9:i\d+>>  Mul [<<PhiX1>>,<<Cst9>>]                   loop:none
+# CHECK-DAG:     <<PhiX2:i\d+>> Phi [<<Mul9>>,<<PhiX1>>]                   loop:none
+# CHECK-DAG:                    Return [<<PhiX2>>]                         loop:none
 
 .method public static testExitPredecessors(IZZ)I
   .registers 4
@@ -197,48 +197,47 @@
 
 
 # CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst0:i\d+]]  IntConstant 0
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst0:i\d+>>  IntConstant 0
+# CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+# CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
 #
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:     [[PhiZ1:i\d+]] Phi [ [[ArgZ]] [[XorZ:i\d+]] [[PhiZ1]] ]     loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
+# CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG:     <<PhiZ1:i\d+>> Phi [<<ArgZ>>,<<XorZ:i\d+>>,<<PhiZ1>>]     loop:<<HeaderY>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
 #
 #                               ### Inner loop ###
-# CHECK-DAG:     [[PhiZ2:i\d+]] Phi [ [[PhiZ1]] [[XorZ]] ]                   loop_header:[[HeaderZ:B\d+]]
-# CHECK-DAG:     [[XorZ]]       Xor [ [[PhiZ2]] [[Cst1]] ]                   loop_header:[[HeaderZ]]
-# CHECK-DAG:     [[CondZ:z\d+]] Equal [ [[XorZ]] [[Cst0]] ]                  loop_header:[[HeaderZ]]
-# CHECK-DAG:                    If [ [[CondZ]] ]                             loop_header:[[HeaderZ]]
+# CHECK-DAG:     <<PhiZ2:i\d+>> Phi [<<PhiZ1>>,<<XorZ>>]                   loop:<<HeaderZ:B\d+>>
+# CHECK-DAG:     <<XorZ>>       Xor [<<PhiZ2>>,<<Cst1>>]                   loop:<<HeaderZ>>
+# CHECK-DAG:     <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>]                  loop:<<HeaderZ>>
+# CHECK-DAG:                    If [<<CondZ>>]                             loop:<<HeaderZ>>
 #
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX]] [[Cst5]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+# CHECK-DAG:     <<Add5>>       Add [<<PhiX>>,<<Cst5>>]                    loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+# CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 # CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst0:i\d+]]  IntConstant 0
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
+# CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+# CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+# CHECK-DAG:     <<Cst0:i\d+>>  IntConstant 0
+# CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+# CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
 #
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add7:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:     [[PhiZ1:i\d+]] Phi [ [[ArgZ]] [[PhiZ1]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
+# CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add7:i\d+>>]               loop:<<HeaderY:B\d+>>
+# CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+# CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
 #
 #                               ### Inner loop ###
-# CHECK-DAG:     [[PhiZ2:i\d+]] Phi [ [[PhiZ1]] [[XorZ:i\d+]] ]              loop_header:[[HeaderZ:B\d+]]
-# CHECK-DAG:     [[XorZ]]       Xor [ [[PhiZ2]] [[Cst1]] ]                   loop_header:[[HeaderZ]]
-# CHECK-DAG:     [[CondZ:z\d+]] Equal [ [[XorZ]] [[Cst0]] ]                  loop_header:[[HeaderZ]]
-# CHECK-DAG:                    If [ [[CondZ]] ]                             loop_header:[[HeaderZ]]
+# CHECK-DAG:     <<PhiZ:i\d+>>  Phi [<<ArgZ>>,<<XorZ:i\d+>>]               loop:<<HeaderZ:B\d+>>
+# CHECK-DAG:     <<XorZ>>       Xor [<<PhiZ>>,<<Cst1>>]                    loop:<<HeaderZ>>
+# CHECK-DAG:     <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>]                  loop:<<HeaderZ>>
+# CHECK-DAG:                    If [<<CondZ>>]                             loop:<<HeaderZ>>
 #
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+# CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 .method public static testInnerLoop(IZZ)I
   .registers 4
diff --git a/test/486-checker-must-do-null-check/expected.txt b/test/486-checker-must-do-null-check/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/486-checker-must-do-null-check/expected.txt
diff --git a/test/486-checker-must-do-null-check/info.txt b/test/486-checker-must-do-null-check/info.txt
new file mode 100644
index 0000000..494ff1c
--- /dev/null
+++ b/test/486-checker-must-do-null-check/info.txt
@@ -0,0 +1 @@
+Verifies MustDoNullCheck() on InstanceOf and CheckCast
diff --git a/test/486-checker-must-do-null-check/src/Main.java b/test/486-checker-must-do-null-check/src/Main.java
new file mode 100644
index 0000000..f285566
--- /dev/null
+++ b/test/486-checker-must-do-null-check/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  // CHECK-START: void Main.InstanceOfPreChecked(java.lang.Object) instruction_simplifier (after)
+  // CHECK:       InstanceOf must_do_null_check:false
+  public void InstanceOfPreChecked(Object o) throws Exception {
+    o.toString();
+    if (o instanceof Main) {
+      throw new Exception();
+    }
+  }
+
+  // CHECK-START: void Main.InstanceOf(java.lang.Object) instruction_simplifier (after)
+  // CHECK:       InstanceOf must_do_null_check:true
+  public void InstanceOf(Object o) throws Exception {
+    if (o instanceof Main) {
+      throw new Exception();
+    }
+  }
+
+  // CHECK-START: void Main.CheckCastPreChecked(java.lang.Object) instruction_simplifier (after)
+  // CHECK:       CheckCast must_do_null_check:false
+  public void CheckCastPreChecked(Object o) {
+    o.toString();
+    ((Main)o).Bar();
+  }
+
+  // CHECK-START: void Main.CheckCast(java.lang.Object) instruction_simplifier (after)
+  // CHECK:       CheckCast must_do_null_check:true
+  public void CheckCast(Object o) {
+    ((Main)o).Bar();
+  }
+
+  void Bar() {throw new RuntimeException();}
+
+  public static void main(String[] sa) {
+    Main t = new Main();
+  }
+}
diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build
new file mode 100644
index 0000000..1dc8452
--- /dev/null
+++ b/test/701-easy-div-rem/build
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# Write out the source file.
+mkdir src
+python ./genMain.py
+
+# Increase the file size limitation for classes.lst as the machine generated
+# source file contains a lot of methods and is quite large.
+ulimit -S 4096
+
+./default-build
diff --git a/test/701-easy-div-rem/genMain.py b/test/701-easy-div-rem/genMain.py
index 80eac34..75eee17 100644
--- a/test/701-easy-div-rem/genMain.py
+++ b/test/701-easy-div-rem/genMain.py
@@ -12,15 +12,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+upper_bound_int_pow2 = 31
+upper_bound_long_pow2 = 63
+upper_bound_constant = 100
 all_tests = [
     ({'@INT@': 'int', '@SUFFIX@':''},
-     [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(31)]),
-      ('CheckDiv', 'idiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
-      ('CheckRem', 'irem_by_pow2_', [2**i for i in range(31)])]),
+     [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckDiv', 'idiv_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckDiv', 'idiv_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckDiv', 'idiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'irem_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckRem', 'irem_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckRem', 'irem_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'irem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]),
     ({'@INT@': 'long', '@SUFFIX@': 'l'},
-     [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(63)]),
-      ('CheckDiv', 'ldiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
-      ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(63)])])
+     [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckDiv', 'ldiv_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckDiv', 'ldiv_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckDiv', 'ldiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckRem', 'lrem_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckRem', 'lrem_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'lrem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])])
 ]
 
 def subst_vars(variables, text):
diff --git a/test/701-easy-div-rem/src/Main.java b/test/701-easy-div-rem/src/Main.java
deleted file mode 100644
index f995f61..0000000
--- a/test/701-easy-div-rem/src/Main.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Main {
-    public static int num_errors = 0;
-
-    public static void reportError(String message) {
-        if (num_errors == 10) {
-            System.out.println("Omitting other error messages...");
-        } else if (num_errors < 10) {
-            System.out.println(message);
-        }
-        num_errors += 1;
-    }
-
-    public static void intCheckDiv(String desc, int result, int dividend, int divisor) {
-        int correct_result = dividend / divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-    public static void intCheckRem(String desc, int result, int dividend, int divisor) {
-        int correct_result = dividend % divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-    public static void longCheckDiv(String desc, long result, long dividend, long divisor) {
-        long correct_result = dividend / divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-    public static void longCheckRem(String desc, long result, long dividend, long divisor) {
-        long correct_result = dividend % divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-
-    public static int idiv_by_pow2_0(int x) {return x / 1;}
-    public static int idiv_by_pow2_1(int x) {return x / 2;}
-    public static int idiv_by_pow2_2(int x) {return x / 4;}
-    public static int idiv_by_pow2_3(int x) {return x / 8;}
-    public static int idiv_by_pow2_4(int x) {return x / 16;}
-    public static int idiv_by_pow2_5(int x) {return x / 32;}
-    public static int idiv_by_pow2_6(int x) {return x / 64;}
-    public static int idiv_by_pow2_7(int x) {return x / 128;}
-    public static int idiv_by_pow2_8(int x) {return x / 256;}
-    public static int idiv_by_pow2_9(int x) {return x / 512;}
-    public static int idiv_by_pow2_10(int x) {return x / 1024;}
-    public static int idiv_by_pow2_11(int x) {return x / 2048;}
-    public static int idiv_by_pow2_12(int x) {return x / 4096;}
-    public static int idiv_by_pow2_13(int x) {return x / 8192;}
-    public static int idiv_by_pow2_14(int x) {return x / 16384;}
-    public static int idiv_by_pow2_15(int x) {return x / 32768;}
-    public static int idiv_by_pow2_16(int x) {return x / 65536;}
-    public static int idiv_by_pow2_17(int x) {return x / 131072;}
-    public static int idiv_by_pow2_18(int x) {return x / 262144;}
-    public static int idiv_by_pow2_19(int x) {return x / 524288;}
-    public static int idiv_by_pow2_20(int x) {return x / 1048576;}
-    public static int idiv_by_pow2_21(int x) {return x / 2097152;}
-    public static int idiv_by_pow2_22(int x) {return x / 4194304;}
-    public static int idiv_by_pow2_23(int x) {return x / 8388608;}
-    public static int idiv_by_pow2_24(int x) {return x / 16777216;}
-    public static int idiv_by_pow2_25(int x) {return x / 33554432;}
-    public static int idiv_by_pow2_26(int x) {return x / 67108864;}
-    public static int idiv_by_pow2_27(int x) {return x / 134217728;}
-    public static int idiv_by_pow2_28(int x) {return x / 268435456;}
-    public static int idiv_by_pow2_29(int x) {return x / 536870912;}
-    public static int idiv_by_pow2_30(int x) {return x / 1073741824;}
-    public static int idiv_by_small_0(int x) {return x / 3;}
-    public static int idiv_by_small_1(int x) {return x / 5;}
-    public static int idiv_by_small_2(int x) {return x / 6;}
-    public static int idiv_by_small_3(int x) {return x / 7;}
-    public static int idiv_by_small_4(int x) {return x / 9;}
-    public static int idiv_by_small_5(int x) {return x / 10;}
-    public static int idiv_by_small_6(int x) {return x / 11;}
-    public static int idiv_by_small_7(int x) {return x / 12;}
-    public static int idiv_by_small_8(int x) {return x / 13;}
-    public static int idiv_by_small_9(int x) {return x / 14;}
-    public static int idiv_by_small_10(int x) {return x / 15;}
-    public static int irem_by_pow2_0(int x) {return x % 1;}
-    public static int irem_by_pow2_1(int x) {return x % 2;}
-    public static int irem_by_pow2_2(int x) {return x % 4;}
-    public static int irem_by_pow2_3(int x) {return x % 8;}
-    public static int irem_by_pow2_4(int x) {return x % 16;}
-    public static int irem_by_pow2_5(int x) {return x % 32;}
-    public static int irem_by_pow2_6(int x) {return x % 64;}
-    public static int irem_by_pow2_7(int x) {return x % 128;}
-    public static int irem_by_pow2_8(int x) {return x % 256;}
-    public static int irem_by_pow2_9(int x) {return x % 512;}
-    public static int irem_by_pow2_10(int x) {return x % 1024;}
-    public static int irem_by_pow2_11(int x) {return x % 2048;}
-    public static int irem_by_pow2_12(int x) {return x % 4096;}
-    public static int irem_by_pow2_13(int x) {return x % 8192;}
-    public static int irem_by_pow2_14(int x) {return x % 16384;}
-    public static int irem_by_pow2_15(int x) {return x % 32768;}
-    public static int irem_by_pow2_16(int x) {return x % 65536;}
-    public static int irem_by_pow2_17(int x) {return x % 131072;}
-    public static int irem_by_pow2_18(int x) {return x % 262144;}
-    public static int irem_by_pow2_19(int x) {return x % 524288;}
-    public static int irem_by_pow2_20(int x) {return x % 1048576;}
-    public static int irem_by_pow2_21(int x) {return x % 2097152;}
-    public static int irem_by_pow2_22(int x) {return x % 4194304;}
-    public static int irem_by_pow2_23(int x) {return x % 8388608;}
-    public static int irem_by_pow2_24(int x) {return x % 16777216;}
-    public static int irem_by_pow2_25(int x) {return x % 33554432;}
-    public static int irem_by_pow2_26(int x) {return x % 67108864;}
-    public static int irem_by_pow2_27(int x) {return x % 134217728;}
-    public static int irem_by_pow2_28(int x) {return x % 268435456;}
-    public static int irem_by_pow2_29(int x) {return x % 536870912;}
-    public static int irem_by_pow2_30(int x) {return x % 1073741824;}
-    public static long ldiv_by_pow2_0(long x) {return x / 1l;}
-    public static long ldiv_by_pow2_1(long x) {return x / 2l;}
-    public static long ldiv_by_pow2_2(long x) {return x / 4l;}
-    public static long ldiv_by_pow2_3(long x) {return x / 8l;}
-    public static long ldiv_by_pow2_4(long x) {return x / 16l;}
-    public static long ldiv_by_pow2_5(long x) {return x / 32l;}
-    public static long ldiv_by_pow2_6(long x) {return x / 64l;}
-    public static long ldiv_by_pow2_7(long x) {return x / 128l;}
-    public static long ldiv_by_pow2_8(long x) {return x / 256l;}
-    public static long ldiv_by_pow2_9(long x) {return x / 512l;}
-    public static long ldiv_by_pow2_10(long x) {return x / 1024l;}
-    public static long ldiv_by_pow2_11(long x) {return x / 2048l;}
-    public static long ldiv_by_pow2_12(long x) {return x / 4096l;}
-    public static long ldiv_by_pow2_13(long x) {return x / 8192l;}
-    public static long ldiv_by_pow2_14(long x) {return x / 16384l;}
-    public static long ldiv_by_pow2_15(long x) {return x / 32768l;}
-    public static long ldiv_by_pow2_16(long x) {return x / 65536l;}
-    public static long ldiv_by_pow2_17(long x) {return x / 131072l;}
-    public static long ldiv_by_pow2_18(long x) {return x / 262144l;}
-    public static long ldiv_by_pow2_19(long x) {return x / 524288l;}
-    public static long ldiv_by_pow2_20(long x) {return x / 1048576l;}
-    public static long ldiv_by_pow2_21(long x) {return x / 2097152l;}
-    public static long ldiv_by_pow2_22(long x) {return x / 4194304l;}
-    public static long ldiv_by_pow2_23(long x) {return x / 8388608l;}
-    public static long ldiv_by_pow2_24(long x) {return x / 16777216l;}
-    public static long ldiv_by_pow2_25(long x) {return x / 33554432l;}
-    public static long ldiv_by_pow2_26(long x) {return x / 67108864l;}
-    public static long ldiv_by_pow2_27(long x) {return x / 134217728l;}
-    public static long ldiv_by_pow2_28(long x) {return x / 268435456l;}
-    public static long ldiv_by_pow2_29(long x) {return x / 536870912l;}
-    public static long ldiv_by_pow2_30(long x) {return x / 1073741824l;}
-    public static long ldiv_by_pow2_31(long x) {return x / 2147483648l;}
-    public static long ldiv_by_pow2_32(long x) {return x / 4294967296l;}
-    public static long ldiv_by_pow2_33(long x) {return x / 8589934592l;}
-    public static long ldiv_by_pow2_34(long x) {return x / 17179869184l;}
-    public static long ldiv_by_pow2_35(long x) {return x / 34359738368l;}
-    public static long ldiv_by_pow2_36(long x) {return x / 68719476736l;}
-    public static long ldiv_by_pow2_37(long x) {return x / 137438953472l;}
-    public static long ldiv_by_pow2_38(long x) {return x / 274877906944l;}
-    public static long ldiv_by_pow2_39(long x) {return x / 549755813888l;}
-    public static long ldiv_by_pow2_40(long x) {return x / 1099511627776l;}
-    public static long ldiv_by_pow2_41(long x) {return x / 2199023255552l;}
-    public static long ldiv_by_pow2_42(long x) {return x / 4398046511104l;}
-    public static long ldiv_by_pow2_43(long x) {return x / 8796093022208l;}
-    public static long ldiv_by_pow2_44(long x) {return x / 17592186044416l;}
-    public static long ldiv_by_pow2_45(long x) {return x / 35184372088832l;}
-    public static long ldiv_by_pow2_46(long x) {return x / 70368744177664l;}
-    public static long ldiv_by_pow2_47(long x) {return x / 140737488355328l;}
-    public static long ldiv_by_pow2_48(long x) {return x / 281474976710656l;}
-    public static long ldiv_by_pow2_49(long x) {return x / 562949953421312l;}
-    public static long ldiv_by_pow2_50(long x) {return x / 1125899906842624l;}
-    public static long ldiv_by_pow2_51(long x) {return x / 2251799813685248l;}
-    public static long ldiv_by_pow2_52(long x) {return x / 4503599627370496l;}
-    public static long ldiv_by_pow2_53(long x) {return x / 9007199254740992l;}
-    public static long ldiv_by_pow2_54(long x) {return x / 18014398509481984l;}
-    public static long ldiv_by_pow2_55(long x) {return x / 36028797018963968l;}
-    public static long ldiv_by_pow2_56(long x) {return x / 72057594037927936l;}
-    public static long ldiv_by_pow2_57(long x) {return x / 144115188075855872l;}
-    public static long ldiv_by_pow2_58(long x) {return x / 288230376151711744l;}
-    public static long ldiv_by_pow2_59(long x) {return x / 576460752303423488l;}
-    public static long ldiv_by_pow2_60(long x) {return x / 1152921504606846976l;}
-    public static long ldiv_by_pow2_61(long x) {return x / 2305843009213693952l;}
-    public static long ldiv_by_pow2_62(long x) {return x / 4611686018427387904l;}
-    public static long ldiv_by_small_0(long x) {return x / 3l;}
-    public static long ldiv_by_small_1(long x) {return x / 5l;}
-    public static long ldiv_by_small_2(long x) {return x / 6l;}
-    public static long ldiv_by_small_3(long x) {return x / 7l;}
-    public static long ldiv_by_small_4(long x) {return x / 9l;}
-    public static long ldiv_by_small_5(long x) {return x / 10l;}
-    public static long ldiv_by_small_6(long x) {return x / 11l;}
-    public static long ldiv_by_small_7(long x) {return x / 12l;}
-    public static long ldiv_by_small_8(long x) {return x / 13l;}
-    public static long ldiv_by_small_9(long x) {return x / 14l;}
-    public static long ldiv_by_small_10(long x) {return x / 15l;}
-    public static long lrem_by_pow2_0(long x) {return x % 1l;}
-    public static long lrem_by_pow2_1(long x) {return x % 2l;}
-    public static long lrem_by_pow2_2(long x) {return x % 4l;}
-    public static long lrem_by_pow2_3(long x) {return x % 8l;}
-    public static long lrem_by_pow2_4(long x) {return x % 16l;}
-    public static long lrem_by_pow2_5(long x) {return x % 32l;}
-    public static long lrem_by_pow2_6(long x) {return x % 64l;}
-    public static long lrem_by_pow2_7(long x) {return x % 128l;}
-    public static long lrem_by_pow2_8(long x) {return x % 256l;}
-    public static long lrem_by_pow2_9(long x) {return x % 512l;}
-    public static long lrem_by_pow2_10(long x) {return x % 1024l;}
-    public static long lrem_by_pow2_11(long x) {return x % 2048l;}
-    public static long lrem_by_pow2_12(long x) {return x % 4096l;}
-    public static long lrem_by_pow2_13(long x) {return x % 8192l;}
-    public static long lrem_by_pow2_14(long x) {return x % 16384l;}
-    public static long lrem_by_pow2_15(long x) {return x % 32768l;}
-    public static long lrem_by_pow2_16(long x) {return x % 65536l;}
-    public static long lrem_by_pow2_17(long x) {return x % 131072l;}
-    public static long lrem_by_pow2_18(long x) {return x % 262144l;}
-    public static long lrem_by_pow2_19(long x) {return x % 524288l;}
-    public static long lrem_by_pow2_20(long x) {return x % 1048576l;}
-    public static long lrem_by_pow2_21(long x) {return x % 2097152l;}
-    public static long lrem_by_pow2_22(long x) {return x % 4194304l;}
-    public static long lrem_by_pow2_23(long x) {return x % 8388608l;}
-    public static long lrem_by_pow2_24(long x) {return x % 16777216l;}
-    public static long lrem_by_pow2_25(long x) {return x % 33554432l;}
-    public static long lrem_by_pow2_26(long x) {return x % 67108864l;}
-    public static long lrem_by_pow2_27(long x) {return x % 134217728l;}
-    public static long lrem_by_pow2_28(long x) {return x % 268435456l;}
-    public static long lrem_by_pow2_29(long x) {return x % 536870912l;}
-    public static long lrem_by_pow2_30(long x) {return x % 1073741824l;}
-    public static long lrem_by_pow2_31(long x) {return x % 2147483648l;}
-    public static long lrem_by_pow2_32(long x) {return x % 4294967296l;}
-    public static long lrem_by_pow2_33(long x) {return x % 8589934592l;}
-    public static long lrem_by_pow2_34(long x) {return x % 17179869184l;}
-    public static long lrem_by_pow2_35(long x) {return x % 34359738368l;}
-    public static long lrem_by_pow2_36(long x) {return x % 68719476736l;}
-    public static long lrem_by_pow2_37(long x) {return x % 137438953472l;}
-    public static long lrem_by_pow2_38(long x) {return x % 274877906944l;}
-    public static long lrem_by_pow2_39(long x) {return x % 549755813888l;}
-    public static long lrem_by_pow2_40(long x) {return x % 1099511627776l;}
-    public static long lrem_by_pow2_41(long x) {return x % 2199023255552l;}
-    public static long lrem_by_pow2_42(long x) {return x % 4398046511104l;}
-    public static long lrem_by_pow2_43(long x) {return x % 8796093022208l;}
-    public static long lrem_by_pow2_44(long x) {return x % 17592186044416l;}
-    public static long lrem_by_pow2_45(long x) {return x % 35184372088832l;}
-    public static long lrem_by_pow2_46(long x) {return x % 70368744177664l;}
-    public static long lrem_by_pow2_47(long x) {return x % 140737488355328l;}
-    public static long lrem_by_pow2_48(long x) {return x % 281474976710656l;}
-    public static long lrem_by_pow2_49(long x) {return x % 562949953421312l;}
-    public static long lrem_by_pow2_50(long x) {return x % 1125899906842624l;}
-    public static long lrem_by_pow2_51(long x) {return x % 2251799813685248l;}
-    public static long lrem_by_pow2_52(long x) {return x % 4503599627370496l;}
-    public static long lrem_by_pow2_53(long x) {return x % 9007199254740992l;}
-    public static long lrem_by_pow2_54(long x) {return x % 18014398509481984l;}
-    public static long lrem_by_pow2_55(long x) {return x % 36028797018963968l;}
-    public static long lrem_by_pow2_56(long x) {return x % 72057594037927936l;}
-    public static long lrem_by_pow2_57(long x) {return x % 144115188075855872l;}
-    public static long lrem_by_pow2_58(long x) {return x % 288230376151711744l;}
-    public static long lrem_by_pow2_59(long x) {return x % 576460752303423488l;}
-    public static long lrem_by_pow2_60(long x) {return x % 1152921504606846976l;}
-    public static long lrem_by_pow2_61(long x) {return x % 2305843009213693952l;}
-    public static long lrem_by_pow2_62(long x) {return x % 4611686018427387904l;}
-
-    public static void intCheckAll(int x) {
-        intCheckDiv("idiv_by_pow2_0", idiv_by_pow2_0(x), x, 1);
-        intCheckDiv("idiv_by_pow2_1", idiv_by_pow2_1(x), x, 2);
-        intCheckDiv("idiv_by_pow2_2", idiv_by_pow2_2(x), x, 4);
-        intCheckDiv("idiv_by_pow2_3", idiv_by_pow2_3(x), x, 8);
-        intCheckDiv("idiv_by_pow2_4", idiv_by_pow2_4(x), x, 16);
-        intCheckDiv("idiv_by_pow2_5", idiv_by_pow2_5(x), x, 32);
-        intCheckDiv("idiv_by_pow2_6", idiv_by_pow2_6(x), x, 64);
-        intCheckDiv("idiv_by_pow2_7", idiv_by_pow2_7(x), x, 128);
-        intCheckDiv("idiv_by_pow2_8", idiv_by_pow2_8(x), x, 256);
-        intCheckDiv("idiv_by_pow2_9", idiv_by_pow2_9(x), x, 512);
-        intCheckDiv("idiv_by_pow2_10", idiv_by_pow2_10(x), x, 1024);
-        intCheckDiv("idiv_by_pow2_11", idiv_by_pow2_11(x), x, 2048);
-        intCheckDiv("idiv_by_pow2_12", idiv_by_pow2_12(x), x, 4096);
-        intCheckDiv("idiv_by_pow2_13", idiv_by_pow2_13(x), x, 8192);
-        intCheckDiv("idiv_by_pow2_14", idiv_by_pow2_14(x), x, 16384);
-        intCheckDiv("idiv_by_pow2_15", idiv_by_pow2_15(x), x, 32768);
-        intCheckDiv("idiv_by_pow2_16", idiv_by_pow2_16(x), x, 65536);
-        intCheckDiv("idiv_by_pow2_17", idiv_by_pow2_17(x), x, 131072);
-        intCheckDiv("idiv_by_pow2_18", idiv_by_pow2_18(x), x, 262144);
-        intCheckDiv("idiv_by_pow2_19", idiv_by_pow2_19(x), x, 524288);
-        intCheckDiv("idiv_by_pow2_20", idiv_by_pow2_20(x), x, 1048576);
-        intCheckDiv("idiv_by_pow2_21", idiv_by_pow2_21(x), x, 2097152);
-        intCheckDiv("idiv_by_pow2_22", idiv_by_pow2_22(x), x, 4194304);
-        intCheckDiv("idiv_by_pow2_23", idiv_by_pow2_23(x), x, 8388608);
-        intCheckDiv("idiv_by_pow2_24", idiv_by_pow2_24(x), x, 16777216);
-        intCheckDiv("idiv_by_pow2_25", idiv_by_pow2_25(x), x, 33554432);
-        intCheckDiv("idiv_by_pow2_26", idiv_by_pow2_26(x), x, 67108864);
-        intCheckDiv("idiv_by_pow2_27", idiv_by_pow2_27(x), x, 134217728);
-        intCheckDiv("idiv_by_pow2_28", idiv_by_pow2_28(x), x, 268435456);
-        intCheckDiv("idiv_by_pow2_29", idiv_by_pow2_29(x), x, 536870912);
-        intCheckDiv("idiv_by_pow2_30", idiv_by_pow2_30(x), x, 1073741824);
-        intCheckDiv("idiv_by_small_0", idiv_by_small_0(x), x, 3);
-        intCheckDiv("idiv_by_small_1", idiv_by_small_1(x), x, 5);
-        intCheckDiv("idiv_by_small_2", idiv_by_small_2(x), x, 6);
-        intCheckDiv("idiv_by_small_3", idiv_by_small_3(x), x, 7);
-        intCheckDiv("idiv_by_small_4", idiv_by_small_4(x), x, 9);
-        intCheckDiv("idiv_by_small_5", idiv_by_small_5(x), x, 10);
-        intCheckDiv("idiv_by_small_6", idiv_by_small_6(x), x, 11);
-        intCheckDiv("idiv_by_small_7", idiv_by_small_7(x), x, 12);
-        intCheckDiv("idiv_by_small_8", idiv_by_small_8(x), x, 13);
-        intCheckDiv("idiv_by_small_9", idiv_by_small_9(x), x, 14);
-        intCheckDiv("idiv_by_small_10", idiv_by_small_10(x), x, 15);
-        intCheckRem("irem_by_pow2_0", irem_by_pow2_0(x), x, 1);
-        intCheckRem("irem_by_pow2_1", irem_by_pow2_1(x), x, 2);
-        intCheckRem("irem_by_pow2_2", irem_by_pow2_2(x), x, 4);
-        intCheckRem("irem_by_pow2_3", irem_by_pow2_3(x), x, 8);
-        intCheckRem("irem_by_pow2_4", irem_by_pow2_4(x), x, 16);
-        intCheckRem("irem_by_pow2_5", irem_by_pow2_5(x), x, 32);
-        intCheckRem("irem_by_pow2_6", irem_by_pow2_6(x), x, 64);
-        intCheckRem("irem_by_pow2_7", irem_by_pow2_7(x), x, 128);
-        intCheckRem("irem_by_pow2_8", irem_by_pow2_8(x), x, 256);
-        intCheckRem("irem_by_pow2_9", irem_by_pow2_9(x), x, 512);
-        intCheckRem("irem_by_pow2_10", irem_by_pow2_10(x), x, 1024);
-        intCheckRem("irem_by_pow2_11", irem_by_pow2_11(x), x, 2048);
-        intCheckRem("irem_by_pow2_12", irem_by_pow2_12(x), x, 4096);
-        intCheckRem("irem_by_pow2_13", irem_by_pow2_13(x), x, 8192);
-        intCheckRem("irem_by_pow2_14", irem_by_pow2_14(x), x, 16384);
-        intCheckRem("irem_by_pow2_15", irem_by_pow2_15(x), x, 32768);
-        intCheckRem("irem_by_pow2_16", irem_by_pow2_16(x), x, 65536);
-        intCheckRem("irem_by_pow2_17", irem_by_pow2_17(x), x, 131072);
-        intCheckRem("irem_by_pow2_18", irem_by_pow2_18(x), x, 262144);
-        intCheckRem("irem_by_pow2_19", irem_by_pow2_19(x), x, 524288);
-        intCheckRem("irem_by_pow2_20", irem_by_pow2_20(x), x, 1048576);
-        intCheckRem("irem_by_pow2_21", irem_by_pow2_21(x), x, 2097152);
-        intCheckRem("irem_by_pow2_22", irem_by_pow2_22(x), x, 4194304);
-        intCheckRem("irem_by_pow2_23", irem_by_pow2_23(x), x, 8388608);
-        intCheckRem("irem_by_pow2_24", irem_by_pow2_24(x), x, 16777216);
-        intCheckRem("irem_by_pow2_25", irem_by_pow2_25(x), x, 33554432);
-        intCheckRem("irem_by_pow2_26", irem_by_pow2_26(x), x, 67108864);
-        intCheckRem("irem_by_pow2_27", irem_by_pow2_27(x), x, 134217728);
-        intCheckRem("irem_by_pow2_28", irem_by_pow2_28(x), x, 268435456);
-        intCheckRem("irem_by_pow2_29", irem_by_pow2_29(x), x, 536870912);
-        intCheckRem("irem_by_pow2_30", irem_by_pow2_30(x), x, 1073741824);
-    }
-
-    public static void longCheckAll(long x) {
-        longCheckDiv("ldiv_by_pow2_0", ldiv_by_pow2_0(x), x, 1l);
-        longCheckDiv("ldiv_by_pow2_1", ldiv_by_pow2_1(x), x, 2l);
-        longCheckDiv("ldiv_by_pow2_2", ldiv_by_pow2_2(x), x, 4l);
-        longCheckDiv("ldiv_by_pow2_3", ldiv_by_pow2_3(x), x, 8l);
-        longCheckDiv("ldiv_by_pow2_4", ldiv_by_pow2_4(x), x, 16l);
-        longCheckDiv("ldiv_by_pow2_5", ldiv_by_pow2_5(x), x, 32l);
-        longCheckDiv("ldiv_by_pow2_6", ldiv_by_pow2_6(x), x, 64l);
-        longCheckDiv("ldiv_by_pow2_7", ldiv_by_pow2_7(x), x, 128l);
-        longCheckDiv("ldiv_by_pow2_8", ldiv_by_pow2_8(x), x, 256l);
-        longCheckDiv("ldiv_by_pow2_9", ldiv_by_pow2_9(x), x, 512l);
-        longCheckDiv("ldiv_by_pow2_10", ldiv_by_pow2_10(x), x, 1024l);
-        longCheckDiv("ldiv_by_pow2_11", ldiv_by_pow2_11(x), x, 2048l);
-        longCheckDiv("ldiv_by_pow2_12", ldiv_by_pow2_12(x), x, 4096l);
-        longCheckDiv("ldiv_by_pow2_13", ldiv_by_pow2_13(x), x, 8192l);
-        longCheckDiv("ldiv_by_pow2_14", ldiv_by_pow2_14(x), x, 16384l);
-        longCheckDiv("ldiv_by_pow2_15", ldiv_by_pow2_15(x), x, 32768l);
-        longCheckDiv("ldiv_by_pow2_16", ldiv_by_pow2_16(x), x, 65536l);
-        longCheckDiv("ldiv_by_pow2_17", ldiv_by_pow2_17(x), x, 131072l);
-        longCheckDiv("ldiv_by_pow2_18", ldiv_by_pow2_18(x), x, 262144l);
-        longCheckDiv("ldiv_by_pow2_19", ldiv_by_pow2_19(x), x, 524288l);
-        longCheckDiv("ldiv_by_pow2_20", ldiv_by_pow2_20(x), x, 1048576l);
-        longCheckDiv("ldiv_by_pow2_21", ldiv_by_pow2_21(x), x, 2097152l);
-        longCheckDiv("ldiv_by_pow2_22", ldiv_by_pow2_22(x), x, 4194304l);
-        longCheckDiv("ldiv_by_pow2_23", ldiv_by_pow2_23(x), x, 8388608l);
-        longCheckDiv("ldiv_by_pow2_24", ldiv_by_pow2_24(x), x, 16777216l);
-        longCheckDiv("ldiv_by_pow2_25", ldiv_by_pow2_25(x), x, 33554432l);
-        longCheckDiv("ldiv_by_pow2_26", ldiv_by_pow2_26(x), x, 67108864l);
-        longCheckDiv("ldiv_by_pow2_27", ldiv_by_pow2_27(x), x, 134217728l);
-        longCheckDiv("ldiv_by_pow2_28", ldiv_by_pow2_28(x), x, 268435456l);
-        longCheckDiv("ldiv_by_pow2_29", ldiv_by_pow2_29(x), x, 536870912l);
-        longCheckDiv("ldiv_by_pow2_30", ldiv_by_pow2_30(x), x, 1073741824l);
-        longCheckDiv("ldiv_by_pow2_31", ldiv_by_pow2_31(x), x, 2147483648l);
-        longCheckDiv("ldiv_by_pow2_32", ldiv_by_pow2_32(x), x, 4294967296l);
-        longCheckDiv("ldiv_by_pow2_33", ldiv_by_pow2_33(x), x, 8589934592l);
-        longCheckDiv("ldiv_by_pow2_34", ldiv_by_pow2_34(x), x, 17179869184l);
-        longCheckDiv("ldiv_by_pow2_35", ldiv_by_pow2_35(x), x, 34359738368l);
-        longCheckDiv("ldiv_by_pow2_36", ldiv_by_pow2_36(x), x, 68719476736l);
-        longCheckDiv("ldiv_by_pow2_37", ldiv_by_pow2_37(x), x, 137438953472l);
-        longCheckDiv("ldiv_by_pow2_38", ldiv_by_pow2_38(x), x, 274877906944l);
-        longCheckDiv("ldiv_by_pow2_39", ldiv_by_pow2_39(x), x, 549755813888l);
-        longCheckDiv("ldiv_by_pow2_40", ldiv_by_pow2_40(x), x, 1099511627776l);
-        longCheckDiv("ldiv_by_pow2_41", ldiv_by_pow2_41(x), x, 2199023255552l);
-        longCheckDiv("ldiv_by_pow2_42", ldiv_by_pow2_42(x), x, 4398046511104l);
-        longCheckDiv("ldiv_by_pow2_43", ldiv_by_pow2_43(x), x, 8796093022208l);
-        longCheckDiv("ldiv_by_pow2_44", ldiv_by_pow2_44(x), x, 17592186044416l);
-        longCheckDiv("ldiv_by_pow2_45", ldiv_by_pow2_45(x), x, 35184372088832l);
-        longCheckDiv("ldiv_by_pow2_46", ldiv_by_pow2_46(x), x, 70368744177664l);
-        longCheckDiv("ldiv_by_pow2_47", ldiv_by_pow2_47(x), x, 140737488355328l);
-        longCheckDiv("ldiv_by_pow2_48", ldiv_by_pow2_48(x), x, 281474976710656l);
-        longCheckDiv("ldiv_by_pow2_49", ldiv_by_pow2_49(x), x, 562949953421312l);
-        longCheckDiv("ldiv_by_pow2_50", ldiv_by_pow2_50(x), x, 1125899906842624l);
-        longCheckDiv("ldiv_by_pow2_51", ldiv_by_pow2_51(x), x, 2251799813685248l);
-        longCheckDiv("ldiv_by_pow2_52", ldiv_by_pow2_52(x), x, 4503599627370496l);
-        longCheckDiv("ldiv_by_pow2_53", ldiv_by_pow2_53(x), x, 9007199254740992l);
-        longCheckDiv("ldiv_by_pow2_54", ldiv_by_pow2_54(x), x, 18014398509481984l);
-        longCheckDiv("ldiv_by_pow2_55", ldiv_by_pow2_55(x), x, 36028797018963968l);
-        longCheckDiv("ldiv_by_pow2_56", ldiv_by_pow2_56(x), x, 72057594037927936l);
-        longCheckDiv("ldiv_by_pow2_57", ldiv_by_pow2_57(x), x, 144115188075855872l);
-        longCheckDiv("ldiv_by_pow2_58", ldiv_by_pow2_58(x), x, 288230376151711744l);
-        longCheckDiv("ldiv_by_pow2_59", ldiv_by_pow2_59(x), x, 576460752303423488l);
-        longCheckDiv("ldiv_by_pow2_60", ldiv_by_pow2_60(x), x, 1152921504606846976l);
-        longCheckDiv("ldiv_by_pow2_61", ldiv_by_pow2_61(x), x, 2305843009213693952l);
-        longCheckDiv("ldiv_by_pow2_62", ldiv_by_pow2_62(x), x, 4611686018427387904l);
-        longCheckDiv("ldiv_by_small_0", ldiv_by_small_0(x), x, 3l);
-        longCheckDiv("ldiv_by_small_1", ldiv_by_small_1(x), x, 5l);
-        longCheckDiv("ldiv_by_small_2", ldiv_by_small_2(x), x, 6l);
-        longCheckDiv("ldiv_by_small_3", ldiv_by_small_3(x), x, 7l);
-        longCheckDiv("ldiv_by_small_4", ldiv_by_small_4(x), x, 9l);
-        longCheckDiv("ldiv_by_small_5", ldiv_by_small_5(x), x, 10l);
-        longCheckDiv("ldiv_by_small_6", ldiv_by_small_6(x), x, 11l);
-        longCheckDiv("ldiv_by_small_7", ldiv_by_small_7(x), x, 12l);
-        longCheckDiv("ldiv_by_small_8", ldiv_by_small_8(x), x, 13l);
-        longCheckDiv("ldiv_by_small_9", ldiv_by_small_9(x), x, 14l);
-        longCheckDiv("ldiv_by_small_10", ldiv_by_small_10(x), x, 15l);
-        longCheckRem("lrem_by_pow2_0", lrem_by_pow2_0(x), x, 1l);
-        longCheckRem("lrem_by_pow2_1", lrem_by_pow2_1(x), x, 2l);
-        longCheckRem("lrem_by_pow2_2", lrem_by_pow2_2(x), x, 4l);
-        longCheckRem("lrem_by_pow2_3", lrem_by_pow2_3(x), x, 8l);
-        longCheckRem("lrem_by_pow2_4", lrem_by_pow2_4(x), x, 16l);
-        longCheckRem("lrem_by_pow2_5", lrem_by_pow2_5(x), x, 32l);
-        longCheckRem("lrem_by_pow2_6", lrem_by_pow2_6(x), x, 64l);
-        longCheckRem("lrem_by_pow2_7", lrem_by_pow2_7(x), x, 128l);
-        longCheckRem("lrem_by_pow2_8", lrem_by_pow2_8(x), x, 256l);
-        longCheckRem("lrem_by_pow2_9", lrem_by_pow2_9(x), x, 512l);
-        longCheckRem("lrem_by_pow2_10", lrem_by_pow2_10(x), x, 1024l);
-        longCheckRem("lrem_by_pow2_11", lrem_by_pow2_11(x), x, 2048l);
-        longCheckRem("lrem_by_pow2_12", lrem_by_pow2_12(x), x, 4096l);
-        longCheckRem("lrem_by_pow2_13", lrem_by_pow2_13(x), x, 8192l);
-        longCheckRem("lrem_by_pow2_14", lrem_by_pow2_14(x), x, 16384l);
-        longCheckRem("lrem_by_pow2_15", lrem_by_pow2_15(x), x, 32768l);
-        longCheckRem("lrem_by_pow2_16", lrem_by_pow2_16(x), x, 65536l);
-        longCheckRem("lrem_by_pow2_17", lrem_by_pow2_17(x), x, 131072l);
-        longCheckRem("lrem_by_pow2_18", lrem_by_pow2_18(x), x, 262144l);
-        longCheckRem("lrem_by_pow2_19", lrem_by_pow2_19(x), x, 524288l);
-        longCheckRem("lrem_by_pow2_20", lrem_by_pow2_20(x), x, 1048576l);
-        longCheckRem("lrem_by_pow2_21", lrem_by_pow2_21(x), x, 2097152l);
-        longCheckRem("lrem_by_pow2_22", lrem_by_pow2_22(x), x, 4194304l);
-        longCheckRem("lrem_by_pow2_23", lrem_by_pow2_23(x), x, 8388608l);
-        longCheckRem("lrem_by_pow2_24", lrem_by_pow2_24(x), x, 16777216l);
-        longCheckRem("lrem_by_pow2_25", lrem_by_pow2_25(x), x, 33554432l);
-        longCheckRem("lrem_by_pow2_26", lrem_by_pow2_26(x), x, 67108864l);
-        longCheckRem("lrem_by_pow2_27", lrem_by_pow2_27(x), x, 134217728l);
-        longCheckRem("lrem_by_pow2_28", lrem_by_pow2_28(x), x, 268435456l);
-        longCheckRem("lrem_by_pow2_29", lrem_by_pow2_29(x), x, 536870912l);
-        longCheckRem("lrem_by_pow2_30", lrem_by_pow2_30(x), x, 1073741824l);
-        longCheckRem("lrem_by_pow2_31", lrem_by_pow2_31(x), x, 2147483648l);
-        longCheckRem("lrem_by_pow2_32", lrem_by_pow2_32(x), x, 4294967296l);
-        longCheckRem("lrem_by_pow2_33", lrem_by_pow2_33(x), x, 8589934592l);
-        longCheckRem("lrem_by_pow2_34", lrem_by_pow2_34(x), x, 17179869184l);
-        longCheckRem("lrem_by_pow2_35", lrem_by_pow2_35(x), x, 34359738368l);
-        longCheckRem("lrem_by_pow2_36", lrem_by_pow2_36(x), x, 68719476736l);
-        longCheckRem("lrem_by_pow2_37", lrem_by_pow2_37(x), x, 137438953472l);
-        longCheckRem("lrem_by_pow2_38", lrem_by_pow2_38(x), x, 274877906944l);
-        longCheckRem("lrem_by_pow2_39", lrem_by_pow2_39(x), x, 549755813888l);
-        longCheckRem("lrem_by_pow2_40", lrem_by_pow2_40(x), x, 1099511627776l);
-        longCheckRem("lrem_by_pow2_41", lrem_by_pow2_41(x), x, 2199023255552l);
-        longCheckRem("lrem_by_pow2_42", lrem_by_pow2_42(x), x, 4398046511104l);
-        longCheckRem("lrem_by_pow2_43", lrem_by_pow2_43(x), x, 8796093022208l);
-        longCheckRem("lrem_by_pow2_44", lrem_by_pow2_44(x), x, 17592186044416l);
-        longCheckRem("lrem_by_pow2_45", lrem_by_pow2_45(x), x, 35184372088832l);
-        longCheckRem("lrem_by_pow2_46", lrem_by_pow2_46(x), x, 70368744177664l);
-        longCheckRem("lrem_by_pow2_47", lrem_by_pow2_47(x), x, 140737488355328l);
-        longCheckRem("lrem_by_pow2_48", lrem_by_pow2_48(x), x, 281474976710656l);
-        longCheckRem("lrem_by_pow2_49", lrem_by_pow2_49(x), x, 562949953421312l);
-        longCheckRem("lrem_by_pow2_50", lrem_by_pow2_50(x), x, 1125899906842624l);
-        longCheckRem("lrem_by_pow2_51", lrem_by_pow2_51(x), x, 2251799813685248l);
-        longCheckRem("lrem_by_pow2_52", lrem_by_pow2_52(x), x, 4503599627370496l);
-        longCheckRem("lrem_by_pow2_53", lrem_by_pow2_53(x), x, 9007199254740992l);
-        longCheckRem("lrem_by_pow2_54", lrem_by_pow2_54(x), x, 18014398509481984l);
-        longCheckRem("lrem_by_pow2_55", lrem_by_pow2_55(x), x, 36028797018963968l);
-        longCheckRem("lrem_by_pow2_56", lrem_by_pow2_56(x), x, 72057594037927936l);
-        longCheckRem("lrem_by_pow2_57", lrem_by_pow2_57(x), x, 144115188075855872l);
-        longCheckRem("lrem_by_pow2_58", lrem_by_pow2_58(x), x, 288230376151711744l);
-        longCheckRem("lrem_by_pow2_59", lrem_by_pow2_59(x), x, 576460752303423488l);
-        longCheckRem("lrem_by_pow2_60", lrem_by_pow2_60(x), x, 1152921504606846976l);
-        longCheckRem("lrem_by_pow2_61", lrem_by_pow2_61(x), x, 2305843009213693952l);
-        longCheckRem("lrem_by_pow2_62", lrem_by_pow2_62(x), x, 4611686018427387904l);
-    }
-
-    public static void main(String[] args) {
-      int i;
-      long l;
-
-      System.out.println("Begin");
-
-      System.out.println("Int: checking some equally spaced dividends...");
-      for (i = -1000; i < 1000; i += 300) {
-          intCheckAll(i);
-          intCheckAll(-i);
-      }
-
-      System.out.println("Int: checking small dividends...");
-      for (i = 1; i < 100; i += 1) {
-          intCheckAll(i);
-          intCheckAll(-i);
-      }
-
-      System.out.println("Int: checking big dividends...");
-      for (i = 0; i < 100; i += 1) {
-          intCheckAll(Integer.MAX_VALUE - i);
-          intCheckAll(Integer.MIN_VALUE + i);
-      }
-
-      System.out.println("Long: checking some equally spaced dividends...");
-      for (l = 0l; l < 1000000000000l; l += 300000000000l) {
-          longCheckAll(l);
-          longCheckAll(-l);
-      }
-
-      System.out.println("Long: checking small dividends...");
-      for (l = 1l; l < 100l; l += 1l) {
-          longCheckAll(l);
-          longCheckAll(-l);
-      }
-
-      System.out.println("Long: checking big dividends...");
-      for (l = 0l; l < 100l; l += 1l) {
-          longCheckAll(Long.MAX_VALUE - l);
-          longCheckAll(Long.MIN_VALUE + l);
-      }
-
-      System.out.println("End");
-    }
-}
diff --git a/test/702-LargeBranchOffset/build b/test/702-LargeBranchOffset/build
index eacf730..20030fa 100644
--- a/test/702-LargeBranchOffset/build
+++ b/test/702-LargeBranchOffset/build
@@ -17,11 +17,7 @@
 # Stop if something fails.
 set -e
 
-# Write out a bunch of source files.
+# Write out the source file.
 cpp -P src/Main.java.in src/Main.java
 
-mkdir classes
-${JAVAC} -d classes src/*.java
-
-${DX} --debug --dex --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+./default-build
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 6ad8787..57d06c4 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -28,6 +28,7 @@
   116-nodex2oat/nodex2oat.cc \
   117-nopatchoat/nopatchoat.cc \
   118-noimage-dex2oat/noimage-dex2oat.cc \
+  137-cfi/cfi.cc \
   139-register-natives/regnative.cc \
   454-get-vreg/get_vreg_jni.cc \
   455-set-vreg/set_vreg_jni.cc \
@@ -57,7 +58,7 @@
     LOCAL_MODULE_TAGS := tests
   endif
   LOCAL_SRC_FILES := $(LIBARTTEST_COMMON_SRC_FILES)
-  LOCAL_SHARED_LIBRARIES += libartd
+  LOCAL_SHARED_LIBRARIES += libartd libbacktrace
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.libarttest.mk
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index f6c9231..8b074ae 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -264,10 +264,12 @@
   117-nopatchoat \
   118-noimage-dex2oat \
   119-noimage-patchoat \
+  137-cfi \
   138-duplicate-classes-check2
 
 # This test fails without an image.
 TEST_ART_BROKEN_NO_IMAGE_RUN_TESTS := \
+  137-cfi \
   138-duplicate-classes-check
 
 ifneq (,$(filter no-dex2oat,$(PREBUILD_TYPES)))
@@ -294,9 +296,13 @@
 
 TEST_ART_BROKEN_FALLBACK_RUN_TESTS :=
 
+# 137:
+# This test unrolls and expects managed frames, but tracing means we run the interpreter.
+# 802:
 # This test dynamically enables tracing to force a deoptimization. This makes the test meaningless
 # when already tracing, and writes an error message that we do not want to check for.
 TEST_ART_BROKEN_TRACING_RUN_TESTS := \
+  137-cfi \
   802-deoptimization
 
 ifneq (,$(filter trace,$(TRACE_TYPES)))
@@ -323,6 +329,7 @@
   118-noimage-dex2oat \
   119-noimage-patchoat \
   131-structural-change \
+  137-cfi \
   139-register-natives \
   454-get-vreg \
   455-set-vreg \
@@ -338,6 +345,33 @@
 
 TEST_ART_BROKEN_NDEBUG_TESTS :=
 
+# Known broken tests for the interpreter.
+# CFI unwinding expects managed frames.
+TEST_ART_BROKEN_INTERPRETER_RUN_TESTS := \
+  137-cfi
+
+ifneq (,$(filter interpreter,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      interpreter,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_INTERPRETER_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_INTERPRETER_RUN_TESTS :=
+
+# Known broken tests for the JIT.
+# CFI unwinding expects managed frames, and the test does not iterate enough to even compile. JIT
+# also uses Generic JNI instead of the JNI compiler.
+TEST_ART_BROKEN_JIT_RUN_TESTS := \
+  137-cfi
+
+ifneq (,$(filter jit,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      jit,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_JIT_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_JIT_RUN_TESTS :=
+
 # Known broken tests for the default compiler (Quick).
 TEST_ART_BROKEN_DEFAULT_RUN_TESTS := \
   457-regs
@@ -429,8 +463,9 @@
 TEST_ART_BROKEN_OPTIMIZING_DEBUGGABLE_RUN_TESTS :=
 
 # Tests that should fail in the read barrier configuration.
+# 137: Read barrier forces interpreter. Cannot run this with the interpreter.
 TEST_ART_BROKEN_READ_BARRIER_RUN_TESTS := \
-  098-ddmc  # b/20720510
+  137-cfi
 
 ifeq ($(ART_USE_READ_BARRIER),true)
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -440,6 +475,24 @@
 
 TEST_ART_BROKEN_READ_BARRIER_RUN_TESTS :=
 
+# Tests that should fail in the heap poisoning configuration.
+# 137: Heap poisoning forces interpreter. Cannot run this with the interpreter.
+TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS := \
+  137-cfi
+
+ifeq ($(ART_HEAP_POISONING),true)
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS :=
+
+# Test 137-cfi works in 32-bit only until we enable 64-bit ELF files.
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+    $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+    $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),137-cfi,64)
+
 # Clear variables ahead of appending to them when defining tests.
 $(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=))
 $(foreach target, $(TARGET_TYPES), \
diff --git a/test/run-test b/test/run-test
index dc60eda..ed33099 100755
--- a/test/run-test
+++ b/test/run-test
@@ -39,7 +39,7 @@
 else
   tmp_dir="${TMPDIR}/$USER/${test_dir}"
 fi
-checker="${progdir}/../tools/checker.py"
+checker="${progdir}/../tools/checker/checker.py"
 
 export JAVA="java"
 export JAVAC="javac -g"
@@ -75,7 +75,7 @@
 check_cmd="check"
 output="output.txt"
 build_output="build-output.txt"
-cfg_output="cfg-output.txt"
+cfg_output="graph.cfg"
 lib="libartd.so"
 run_args="--quiet"
 build_args=""
@@ -504,14 +504,20 @@
 
 if [ '!' -r "$build" ]; then
     cp "${progdir}/etc/default-build" build
+else
+    cp "${progdir}/etc/default-build" .
 fi
 
 if [ '!' -r "$run" ]; then
     cp "${progdir}/etc/default-run" run
+else
+    cp "${progdir}/etc/default-run" .
 fi
 
 if [ '!' -r "$check_cmd" ]; then
     cp "${progdir}/etc/default-check" check
+else
+    cp "${progdir}/etc/default-check" .
 fi
 
 chmod 755 "$build"
diff --git a/tools/checker.py b/tools/checker.py
deleted file mode 100755
index 0bce236..0000000
--- a/tools/checker.py
+++ /dev/null
@@ -1,777 +0,0 @@
-#!/usr/bin/env python2
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# Checker is a testing tool which compiles a given test file and compares the
-# state of the control-flow graph before and after each optimization pass
-# against a set of assertions specified alongside the tests.
-#
-# Tests are written in Java, turned into DEX and compiled with the Optimizing
-# compiler. "Check lines" are assertions formatted as comments of the Java file.
-# They begin with prefix 'CHECK' followed by a pattern that the engine attempts
-# to match in the compiler-generated output.
-#
-# Assertions are tested in groups which correspond to the individual compiler
-# passes. Each group of check lines therefore must start with a 'CHECK-START'
-# header which specifies the output group it should be tested against. The group
-# name must exactly match one of the groups recognized in the output (they can
-# be listed with the '--list-groups' command-line flag).
-#
-# Matching of check lines is carried out in the order of appearance in the
-# source file. There are three types of check lines:
-#  - CHECK:     Must match an output line which appears in the output group
-#               later than lines matched against any preceeding checks. Output
-#               lines must therefore match the check lines in the same order.
-#               These are referred to as "in-order" checks in the code.
-#  - CHECK-DAG: Must match an output line which appears in the output group
-#               later than lines matched against any preceeding in-order checks.
-#               In other words, the order of output lines does not matter
-#               between consecutive DAG checks.
-#  - CHECK-NOT: Must not match any output line which appears in the output group
-#               later than lines matched against any preceeding checks and
-#               earlier than lines matched against any subsequent checks.
-#               Surrounding non-negative checks (or boundaries of the group)
-#               therefore create a scope within which the assertion is verified.
-#
-# Check-line patterns are treated as plain text rather than regular expressions
-# but are whitespace agnostic.
-#
-# Actual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If
-# curly brackets need to be used inside the body of the regex, they need to be
-# enclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse
-# the invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'.
-#
-# Regex patterns can be named and referenced later. A new variable is defined
-# with '[[name:regex]]' and can be referenced with '[[name]]'. Variables are
-# only valid within the scope of the defining group. Within a group they cannot
-# be redefined or used undefined.
-#
-# Example:
-#   The following assertions can be placed in a Java source file:
-#
-#   // CHECK-START: int MyClass.MyMethod() constant_folding (after)
-#   // CHECK:         [[ID:i[0-9]+]] IntConstant {{11|22}}
-#   // 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
-#   constant folding returns an integer constant with value either 11 or 22.
-#
-
-from __future__ import print_function
-import argparse
-import os
-import re
-import shutil
-import sys
-import tempfile
-
-class Logger(object):
-
-  class Level(object):
-    NoOutput, Error, Info = range(3)
-
-  class Color(object):
-    Default, Blue, Gray, Purple, Red = range(5)
-
-    @staticmethod
-    def terminalCode(color, out=sys.stdout):
-      if not out.isatty():
-        return ''
-      elif color == Logger.Color.Blue:
-        return '\033[94m'
-      elif color == Logger.Color.Gray:
-        return '\033[37m'
-      elif color == Logger.Color.Purple:
-        return '\033[95m'
-      elif color == Logger.Color.Red:
-        return '\033[91m'
-      else:
-        return '\033[0m'
-
-  Verbosity = Level.Info
-
-  @staticmethod
-  def log(text, level=Level.Info, color=Color.Default, newLine=True, out=sys.stdout):
-    if level <= Logger.Verbosity:
-      text = Logger.Color.terminalCode(color, out) + text + \
-             Logger.Color.terminalCode(Logger.Color.Default, out)
-      if newLine:
-        print(text, file=out)
-      else:
-        print(text, end="", file=out)
-      out.flush()
-
-  @staticmethod
-  def fail(msg, file=None, line=-1):
-    location = ""
-    if file:
-      location += file + ":"
-    if line > 0:
-      location += str(line) + ":"
-    if location:
-      location += " "
-
-    Logger.log(location, Logger.Level.Error, color=Logger.Color.Gray, newLine=False, out=sys.stderr)
-    Logger.log("error: ", Logger.Level.Error, color=Logger.Color.Red, newLine=False, out=sys.stderr)
-    Logger.log(msg, Logger.Level.Error, out=sys.stderr)
-    sys.exit(msg)
-
-  @staticmethod
-  def startTest(name):
-    Logger.log("TEST ", color=Logger.Color.Purple, newLine=False)
-    Logger.log(name + "... ", newLine=False)
-
-  @staticmethod
-  def testPassed():
-    Logger.log("PASS", color=Logger.Color.Blue)
-
-  @staticmethod
-  def testFailed(msg, file=None, line=-1):
-    Logger.log("FAIL", color=Logger.Color.Red)
-    Logger.fail(msg, file, line)
-
-class CommonEqualityMixin:
-  """Mixin for class equality as equality of the fields."""
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__)
-           and self.__dict__ == other.__dict__)
-
-  def __ne__(self, other):
-    return not self.__eq__(other)
-
-  def __repr__(self):
-    return "<%s: %s>" % (type(self).__name__, str(self.__dict__))
-
-
-class CheckElement(CommonEqualityMixin):
-  """Single element of the check line."""
-
-  class Variant(object):
-    """Supported language constructs."""
-    Text, Pattern, VarRef, VarDef, Separator = range(5)
-
-  rStartOptional = r"("
-  rEndOptional = r")?"
-
-  rName = r"([a-zA-Z][a-zA-Z0-9]*)"
-  rRegex = r"(.+?)"
-  rPatternStartSym = r"(\{\{)"
-  rPatternEndSym = r"(\}\})"
-  rVariableStartSym = r"(\[\[)"
-  rVariableEndSym = r"(\]\])"
-  rVariableSeparator = r"(:)"
-
-  regexPattern = rPatternStartSym + rRegex + rPatternEndSym
-  regexVariable = rVariableStartSym + \
-                    rName + \
-                    (rStartOptional + rVariableSeparator + rRegex + rEndOptional) + \
-                  rVariableEndSym
-
-  def __init__(self, variant, name, pattern):
-    self.variant = variant
-    self.name = name
-    self.pattern = pattern
-
-  @staticmethod
-  def newSeparator():
-    return CheckElement(CheckElement.Variant.Separator, None, None)
-
-  @staticmethod
-  def parseText(text):
-    return CheckElement(CheckElement.Variant.Text, None, re.escape(text))
-
-  @staticmethod
-  def parsePattern(patternElem):
-    return CheckElement(CheckElement.Variant.Pattern, None, patternElem[2:-2])
-
-  @staticmethod
-  def parseVariable(varElem):
-    colonPos = varElem.find(":")
-    if colonPos == -1:
-      # Variable reference
-      name = varElem[2:-2]
-      return CheckElement(CheckElement.Variant.VarRef, name, None)
-    else:
-      # Variable definition
-      name = varElem[2:colonPos]
-      body = varElem[colonPos+1:-2]
-      return CheckElement(CheckElement.Variant.VarDef, name, body)
-
-class CheckLine(CommonEqualityMixin):
-  """Representation of a single assertion in the check file formed of one or
-     more regex elements. Matching against an output line is successful only
-     if all regex elements can be matched in the given order."""
-
-  class Variant(object):
-    """Supported types of assertions."""
-    InOrder, DAG, Not = range(3)
-
-  def __init__(self, content, variant=Variant.InOrder, fileName=None, lineNo=-1):
-    self.fileName = fileName
-    self.lineNo = lineNo
-    self.content = content.strip()
-
-    self.variant = variant
-    self.lineParts = self.__parse(self.content)
-    if not self.lineParts:
-      Logger.fail("Empty check line", self.fileName, self.lineNo)
-
-    if self.variant == CheckLine.Variant.Not:
-      for elem in self.lineParts:
-        if elem.variant == CheckElement.Variant.VarDef:
-          Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
-
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__) and
-            self.variant == other.variant and
-            self.lineParts == other.lineParts)
-
-  # Returns True if the given Match object was at the beginning of the line.
-  def __isMatchAtStart(self, match):
-    return (match is not None) and (match.start() == 0)
-
-  # Takes in a list of Match objects and returns the minimal start point among
-  # them. If there aren't any successful matches it returns the length of
-  # the searched string.
-  def __firstMatch(self, matches, string):
-    starts = map(lambda m: len(string) if m is None else m.start(), matches)
-    return min(starts)
-
-  # This method parses the content of a check line stripped of the initial
-  # comment symbol and the CHECK keyword.
-  def __parse(self, line):
-    lineParts = []
-    # Loop as long as there is something to parse.
-    while line:
-      # Search for the nearest occurrence of the special markers.
-      matchWhitespace = re.search(r"\s+", line)
-      matchPattern = re.search(CheckElement.regexPattern, line)
-      matchVariable = re.search(CheckElement.regexVariable, line)
-
-      # If one of the above was identified at the current position, extract them
-      # from the line, parse them and add to the list of line parts.
-      if self.__isMatchAtStart(matchWhitespace):
-        # A whitespace in the check line creates a new separator of line parts.
-        # This allows for ignored output between the previous and next parts.
-        line = line[matchWhitespace.end():]
-        lineParts.append(CheckElement.newSeparator())
-      elif self.__isMatchAtStart(matchPattern):
-        pattern = line[0:matchPattern.end()]
-        line = line[matchPattern.end():]
-        lineParts.append(CheckElement.parsePattern(pattern))
-      elif self.__isMatchAtStart(matchVariable):
-        var = line[0:matchVariable.end()]
-        line = line[matchVariable.end():]
-        lineParts.append(CheckElement.parseVariable(var))
-      else:
-        # If we're not currently looking at a special marker, this is a plain
-        # text match all the way until the first special marker (or the end
-        # of the line).
-        firstMatch = self.__firstMatch([ matchWhitespace, matchPattern, matchVariable ], line)
-        text = line[0:firstMatch]
-        line = line[firstMatch:]
-        lineParts.append(CheckElement.parseText(text))
-    return lineParts
-
-  # Returns the regex pattern to be matched in the output line. Variable
-  # references are substituted with their current values provided in the
-  # 'varState' argument.
-  # An exception is raised if a referenced variable is undefined.
-  def __generatePattern(self, linePart, varState):
-    if linePart.variant == CheckElement.Variant.VarRef:
-      try:
-        return re.escape(varState[linePart.name])
-      except KeyError:
-        Logger.testFailed("Use of undefined variable \"" + linePart.name + "\"",
-                          self.fileName, self.lineNo)
-    else:
-      return linePart.pattern
-
-  def __isSeparated(self, outputLine, matchStart):
-    return (matchStart == 0) or (outputLine[matchStart - 1:matchStart].isspace())
-
-  # Attempts to match the check line against a line from the output file with
-  # the given initial variable values. It returns the new variable state if
-  # successful and None otherwise.
-  def match(self, outputLine, initialVarState):
-    # Do the full matching on a shadow copy of the variable state. If the
-    # matching fails half-way, we will not need to revert the state.
-    varState = dict(initialVarState)
-
-    matchStart = 0
-    isAfterSeparator = True
-
-    # Now try to parse all of the parts of the check line in the right order.
-    # Variable values are updated on-the-fly, meaning that a variable can
-    # be referenced immediately after its definition.
-    for part in self.lineParts:
-      if part.variant == CheckElement.Variant.Separator:
-        isAfterSeparator = True
-        continue
-
-      # Find the earliest match for this line part.
-      pattern = self.__generatePattern(part, varState)
-      while True:
-        match = re.search(pattern, outputLine[matchStart:])
-        if (match is None) or (not isAfterSeparator and not self.__isMatchAtStart(match)):
-          return None
-        matchEnd = matchStart + match.end()
-        matchStart += match.start()
-
-        # Check if this is a valid match if we expect a whitespace separator
-        # before the matched text. Otherwise loop and look for another match.
-        if not isAfterSeparator or self.__isSeparated(outputLine, matchStart):
-          break
-        else:
-          matchStart += 1
-
-      if part.variant == CheckElement.Variant.VarDef:
-        if part.name in varState:
-          Logger.testFailed("Multiple definitions of variable \"" + part.name + "\"",
-                            self.fileName, self.lineNo)
-        varState[part.name] = outputLine[matchStart:matchEnd]
-
-      matchStart = matchEnd
-      isAfterSeparator = False
-
-    # All parts were successfully matched. Return the new variable state.
-    return varState
-
-
-class CheckGroup(CommonEqualityMixin):
-  """Represents a named collection of check lines which are to be matched
-     against an output group of the same name."""
-
-  def __init__(self, name, lines, fileName=None, lineNo=-1):
-    self.fileName = fileName
-    self.lineNo = lineNo
-
-    if not name:
-      Logger.fail("Check group does not have a name", self.fileName, self.lineNo)
-    if not lines:
-      Logger.fail("Check group does not have a body", self.fileName, self.lineNo)
-
-    self.name = name
-    self.lines = lines
-
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__) and
-            self.name == other.name and
-            self.lines == other.lines)
-
-  def __headAndTail(self, list):
-    return list[0], list[1:]
-
-  # Splits a list of check lines at index 'i' such that lines[i] is the first
-  # element whose variant is not equal to the given parameter.
-  def __splitByVariant(self, lines, variant):
-    i = 0
-    while i < len(lines) and lines[i].variant == variant:
-      i += 1
-    return lines[:i], lines[i:]
-
-  # Extracts the first sequence of check lines which are independent of each
-  # other's match location, i.e. either consecutive DAG lines or a single
-  # InOrder line. Any Not lines preceeding this sequence are also extracted.
-  def __nextIndependentChecks(self, checkLines):
-    notChecks, checkLines = self.__splitByVariant(checkLines, CheckLine.Variant.Not)
-    if not checkLines:
-      return notChecks, [], []
-
-    head, tail = self.__headAndTail(checkLines)
-    if head.variant == CheckLine.Variant.InOrder:
-      return notChecks, [head], tail
-    else:
-      assert head.variant == CheckLine.Variant.DAG
-      independentChecks, checkLines = self.__splitByVariant(checkLines, CheckLine.Variant.DAG)
-      return notChecks, independentChecks, checkLines
-
-  # If successful, returns the line number of the first output line matching the
-  # check line and the updated variable state. Otherwise returns -1 and None,
-  # respectively. The 'lineFilter' parameter can be used to supply a list of
-  # line numbers (counting from 1) which should be skipped.
-  def __findFirstMatch(self, checkLine, outputLines, startLineNo, lineFilter, varState):
-    matchLineNo = startLineNo
-    for outputLine in outputLines:
-      if matchLineNo not in lineFilter:
-        newVarState = checkLine.match(outputLine, varState)
-        if newVarState is not None:
-          return matchLineNo, newVarState
-      matchLineNo += 1
-    return -1, None
-
-  # Matches the given positive check lines against the output in order of
-  # appearance. Variable state is propagated but the scope of the search remains
-  # the same for all checks. Each output line can only be matched once.
-  # If all check lines are matched, the resulting variable state is returned
-  # together with the remaining output. The function also returns output lines
-  # which appear before either of the matched lines so they can be tested
-  # against Not checks.
-  def __matchIndependentChecks(self, checkLines, outputLines, startLineNo, varState):
-    # If no checks are provided, skip over the entire output.
-    if not checkLines:
-      return outputLines, [], startLineNo + len(outputLines), varState
-
-    # Keep track of which lines have been matched.
-    matchedLines = []
-
-    # Find first unused output line which matches each check line.
-    for checkLine in checkLines:
-      matchLineNo, varState = \
-        self.__findFirstMatch(checkLine, outputLines, startLineNo, matchedLines, varState)
-      if varState is None:
-        Logger.testFailed("Could not match check line \"" + checkLine.content + "\" " +
-                          "starting from output line " + str(startLineNo),
-                          self.fileName, checkLine.lineNo)
-      matchedLines.append(matchLineNo)
-
-    # Return new variable state and the output lines which lie outside the
-    # match locations of this independent group.
-    minMatchLineNo = min(matchedLines)
-    maxMatchLineNo = max(matchedLines)
-    preceedingLines = outputLines[:minMatchLineNo - startLineNo]
-    remainingLines = outputLines[maxMatchLineNo - startLineNo + 1:]
-    return preceedingLines, remainingLines, maxMatchLineNo + 1, varState
-
-  # Makes sure that the given check lines do not match any of the given output
-  # lines. Variable state does not change.
-  def __matchNotLines(self, checkLines, outputLines, startLineNo, varState):
-    for checkLine in checkLines:
-      assert checkLine.variant == CheckLine.Variant.Not
-      matchLineNo, matchVarState = \
-        self.__findFirstMatch(checkLine, outputLines, startLineNo, [], varState)
-      if matchVarState is not None:
-        Logger.testFailed("CHECK-NOT line \"" + checkLine.content + "\" matches output line " + \
-                          str(matchLineNo), self.fileName, checkLine.lineNo)
-
-  # Matches the check lines in this group against an output group. It is
-  # responsible for running the checks in the right order and scope, and
-  # for propagating the variable state between the check lines.
-  def match(self, outputGroup):
-    varState = {}
-    checkLines = self.lines
-    outputLines = outputGroup.body
-    startLineNo = outputGroup.lineNo
-
-    while checkLines:
-      # Extract the next sequence of location-independent checks to be matched.
-      notChecks, independentChecks, checkLines = self.__nextIndependentChecks(checkLines)
-
-      # Match the independent checks.
-      notOutput, outputLines, newStartLineNo, newVarState = \
-        self.__matchIndependentChecks(independentChecks, outputLines, startLineNo, varState)
-
-      # Run the Not checks against the output lines which lie between the last
-      # two independent groups or the bounds of the output.
-      self.__matchNotLines(notChecks, notOutput, startLineNo, varState)
-
-      # Update variable state.
-      startLineNo = newStartLineNo
-      varState = newVarState
-
-class OutputGroup(CommonEqualityMixin):
-  """Represents a named part of the test output against which a check group of
-     the same name is to be matched."""
-
-  def __init__(self, name, body, fileName=None, lineNo=-1):
-    if not name:
-      Logger.fail("Output group does not have a name", fileName, lineNo)
-    if not body:
-      Logger.fail("Output group does not have a body", fileName, lineNo)
-
-    self.name = name
-    self.body = body
-    self.lineNo = lineNo
-
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__) and
-            self.name == other.name and
-            self.body == other.body)
-
-
-class FileSplitMixin(object):
-  """Mixin for representing text files which need to be split into smaller
-     chunks before being parsed."""
-
-  def _parseStream(self, stream):
-    lineNo = 0
-    allGroups = []
-    currentGroup = None
-
-    for line in stream:
-      lineNo += 1
-      line = line.strip()
-      if not line:
-        continue
-
-      # Let the child class process the line and return information about it.
-      # The _processLine method can modify the content of the line (or delete it
-      # entirely) and specify whether it starts a new group.
-      processedLine, newGroupName = self._processLine(line, lineNo)
-      if newGroupName is not None:
-        currentGroup = (newGroupName, [], lineNo)
-        allGroups.append(currentGroup)
-      if processedLine is not None:
-        if currentGroup is not None:
-          currentGroup[1].append(processedLine)
-        else:
-          self._exceptionLineOutsideGroup(line, lineNo)
-
-    # Finally, take the generated line groups and let the child class process
-    # each one before storing the final outcome.
-    return list(map(lambda group: self._processGroup(group[0], group[1], group[2]), allGroups))
-
-
-class CheckFile(FileSplitMixin):
-  """Collection of check groups extracted from the input test file."""
-
-  def __init__(self, prefix, checkStream, fileName=None):
-    self.fileName = fileName
-    self.prefix = prefix
-    self.groups = self._parseStream(checkStream)
-
-  # Attempts to parse a check line. The regex searches for a comment symbol
-  # followed by the CHECK keyword, given attribute and a colon at the very
-  # beginning of the line. Whitespaces are ignored.
-  def _extractLine(self, prefix, line):
-    rIgnoreWhitespace = r"\s*"
-    rCommentSymbols = [r"//", r"#"]
-    regexPrefix = rIgnoreWhitespace + \
-                  r"(" + r"|".join(rCommentSymbols) + r")" + \
-                  rIgnoreWhitespace + \
-                  prefix + r":"
-
-    # The 'match' function succeeds only if the pattern is matched at the
-    # beginning of the line.
-    match = re.match(regexPrefix, line)
-    if match is not None:
-      return line[match.end():].strip()
-    else:
-      return None
-
-  # This function is invoked on each line of the check file and returns a pair
-  # which instructs the parser how the line should be handled. If the line is to
-  # be included in the current check group, it is returned in the first value.
-  # If the line starts a new check group, the name of the group is returned in
-  # the second value.
-  def _processLine(self, line, lineNo):
-    # Lines beginning with 'CHECK-START' start a new check group.
-    startLine = self._extractLine(self.prefix + "-START", line)
-    if startLine is not None:
-      return None, startLine
-
-    # Lines starting only with 'CHECK' are matched in order.
-    plainLine = self._extractLine(self.prefix, line)
-    if plainLine is not None:
-      return (plainLine, CheckLine.Variant.InOrder, lineNo), None
-
-    # 'CHECK-DAG' lines are no-order assertions.
-    dagLine = self._extractLine(self.prefix + "-DAG", line)
-    if dagLine is not None:
-      return (dagLine, CheckLine.Variant.DAG, lineNo), None
-
-    # 'CHECK-NOT' lines are no-order negative assertions.
-    notLine = self._extractLine(self.prefix + "-NOT", line)
-    if notLine is not None:
-      return (notLine, CheckLine.Variant.Not, lineNo), None
-
-    # Other lines are ignored.
-    return None, None
-
-  def _exceptionLineOutsideGroup(self, line, lineNo):
-    Logger.fail("Check line not inside a group", self.fileName, lineNo)
-
-  # Constructs a check group from the parser-collected check lines.
-  def _processGroup(self, name, lines, lineNo):
-    checkLines = list(map(lambda line: CheckLine(line[0], line[1], self.fileName, line[2]), lines))
-    return CheckGroup(name, checkLines, self.fileName, lineNo)
-
-  def match(self, outputFile):
-    for checkGroup in self.groups:
-      # TODO: Currently does not handle multiple occurrences of the same group
-      # name, e.g. when a pass is run multiple times. It will always try to
-      # match a check group against the first output group of the same name.
-      outputGroup = outputFile.findGroup(checkGroup.name)
-      if outputGroup is None:
-        Logger.fail("Group \"" + checkGroup.name + "\" not found in the output",
-                    self.fileName, checkGroup.lineNo)
-      Logger.startTest(checkGroup.name)
-      checkGroup.match(outputGroup)
-      Logger.testPassed()
-
-
-class OutputFile(FileSplitMixin):
-  """Representation of the output generated by the test and split into groups
-     within which the checks are performed.
-
-     C1visualizer format is parsed with a state machine which differentiates
-     between the 'compilation' and 'cfg' blocks. The former marks the beginning
-     of a method. It is parsed for the method's name but otherwise ignored. Each
-     subsequent CFG block represents one stage of the compilation pipeline and
-     is parsed into an output group named "<method name> <pass name>".
-     """
-
-  class ParsingState:
-    OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4)
-
-  def __init__(self, outputStream, fileName=None):
-    self.fileName = fileName
-
-    # Initialize the state machine
-    self.lastMethodName = None
-    self.state = OutputFile.ParsingState.OutsideBlock
-    self.groups = self._parseStream(outputStream)
-
-  # This function is invoked on each line of the output file and returns a pair
-  # which instructs the parser how the line should be handled. If the line is to
-  # be included in the current group, it is returned in the first value. If the
-  # line starts a new output group, the name of the group is returned in the
-  # second value.
-  def _processLine(self, line, lineNo):
-    if self.state == OutputFile.ParsingState.StartingCfgBlock:
-      # Previous line started a new 'cfg' block which means that this one must
-      # contain the name of the pass (this is enforced by C1visualizer).
-      if re.match("name\s+\"[^\"]+\"", line):
-        # Extract the pass name, prepend it with the name of the method and
-        # return as the beginning of a new group.
-        self.state = OutputFile.ParsingState.InsideCfgBlock
-        return (None, self.lastMethodName + " " + line.split("\"")[1])
-      else:
-        Logger.fail("Expected output group name", self.fileName, lineNo)
-
-    elif self.state == OutputFile.ParsingState.InsideCfgBlock:
-      if line == "end_cfg":
-        self.state = OutputFile.ParsingState.OutsideBlock
-        return (None, None)
-      else:
-        return (line, None)
-
-    elif self.state == OutputFile.ParsingState.InsideCompilationBlock:
-      # Search for the method's name. Format: method "<name>"
-      if re.match("method\s+\"[^\"]*\"", line):
-        methodName = line.split("\"")[1].strip()
-        if not methodName:
-          Logger.fail("Empty method name in output", self.fileName, lineNo)
-        self.lastMethodName = methodName
-      elif line == "end_compilation":
-        self.state = OutputFile.ParsingState.OutsideBlock
-      return (None, None)
-
-    else:
-      assert self.state == OutputFile.ParsingState.OutsideBlock
-      if line == "begin_cfg":
-        # The line starts a new group but we'll wait until the next line from
-        # which we can extract the name of the pass.
-        if self.lastMethodName is None:
-          Logger.fail("Expected method header", self.fileName, lineNo)
-        self.state = OutputFile.ParsingState.StartingCfgBlock
-        return (None, None)
-      elif line == "begin_compilation":
-        self.state = OutputFile.ParsingState.InsideCompilationBlock
-        return (None, None)
-      else:
-        Logger.fail("Output line not inside a group", self.fileName, lineNo)
-
-  # Constructs an output group from the parser-collected output lines.
-  def _processGroup(self, name, lines, lineNo):
-    return OutputGroup(name, lines, self.fileName, lineNo + 1)
-
-  def findGroup(self, name):
-    for group in self.groups:
-      if group.name == name:
-        return group
-    return None
-
-
-def ParseArguments():
-  parser = argparse.ArgumentParser()
-  parser.add_argument("tested_file",
-                      help="text file the checks should be verified against")
-  parser.add_argument("source_path", nargs="?",
-                      help="path to file/folder with checking annotations")
-  parser.add_argument("--check-prefix", dest="check_prefix", default="CHECK", metavar="PREFIX",
-                      help="prefix of checks in the test files (default: CHECK)")
-  parser.add_argument("--list-groups", dest="list_groups", action="store_true",
-                      help="print a list of all groups found in the tested file")
-  parser.add_argument("--dump-group", dest="dump_group", metavar="GROUP",
-                      help="print the contents of an output group")
-  parser.add_argument("-q", "--quiet", action="store_true",
-                      help="print only errors")
-  return parser.parse_args()
-
-
-def ListGroups(outputFilename):
-  outputFile = OutputFile(open(outputFilename, "r"))
-  for group in outputFile.groups:
-    Logger.log(group.name)
-
-
-def DumpGroup(outputFilename, groupName):
-  outputFile = OutputFile(open(outputFilename, "r"))
-  group = outputFile.findGroup(groupName)
-  if group:
-    lineNo = group.lineNo
-    maxLineNo = lineNo + len(group.body)
-    lenLineNo = len(str(maxLineNo)) + 2
-    for line in group.body:
-      Logger.log((str(lineNo) + ":").ljust(lenLineNo) + line)
-      lineNo += 1
-  else:
-    Logger.fail("Group \"" + groupName + "\" not found in the output")
-
-
-# Returns a list of files to scan for check annotations in the given path. Path
-# to a file is returned as a single-element list, directories are recursively
-# traversed and all '.java' files returned.
-def FindCheckFiles(path):
-  if not path:
-    Logger.fail("No source path provided")
-  elif os.path.isfile(path):
-    return [ path ]
-  elif os.path.isdir(path):
-    foundFiles = []
-    for root, dirs, files in os.walk(path):
-      for file in files:
-        if os.path.splitext(file)[1] == ".java":
-          foundFiles.append(os.path.join(root, file))
-    return foundFiles
-  else:
-    Logger.fail("Source path \"" + path + "\" not found")
-
-
-def RunChecks(checkPrefix, checkPath, outputFilename):
-  outputBaseName = os.path.basename(outputFilename)
-  outputFile = OutputFile(open(outputFilename, "r"), outputBaseName)
-
-  for checkFilename in FindCheckFiles(checkPath):
-    checkBaseName = os.path.basename(checkFilename)
-    checkFile = CheckFile(checkPrefix, open(checkFilename, "r"), checkBaseName)
-    checkFile.match(outputFile)
-
-
-if __name__ == "__main__":
-  args = ParseArguments()
-
-  if args.quiet:
-    Logger.Verbosity = Logger.Level.Error
-
-  if args.list_groups:
-    ListGroups(args.tested_file)
-  elif args.dump_group:
-    DumpGroup(args.tested_file, args.dump_group)
-  else:
-    RunChecks(args.check_prefix, args.source_path, args.tested_file)
diff --git a/tools/checker/README b/tools/checker/README
new file mode 100644
index 0000000..858a773
--- /dev/null
+++ b/tools/checker/README
@@ -0,0 +1,54 @@
+Checker is a testing tool which compiles a given test file and compares the
+state of the control-flow graph before and after each optimization pass
+against a set of assertions specified alongside the tests.
+
+Tests are written in Java, turned into DEX and compiled with the Optimizing
+compiler. "Check lines" are assertions formatted as comments of the Java file.
+They begin with prefix 'CHECK' followed by a pattern that the engine attempts
+to match in the compiler-generated output.
+
+Assertions are tested in groups which correspond to the individual compiler
+passes. Each group of check lines therefore must start with a 'CHECK-START'
+header which specifies the output group it should be tested against. The group
+name must exactly match one of the groups recognized in the output (they can
+be listed with the '--list-passes' command-line flag).
+
+Matching of check lines is carried out in the order of appearance in the
+source file. There are three types of check lines:
+ - CHECK:     Must match an output line which appears in the output group
+              later than lines matched against any preceeding checks. Output
+              lines must therefore match the check lines in the same order.
+              These are referred to as "in-order" checks in the code.
+ - CHECK-DAG: Must match an output line which appears in the output group
+              later than lines matched against any preceeding in-order checks.
+              In other words, the order of output lines does not matter
+              between consecutive DAG checks.
+ - CHECK-NOT: Must not match any output line which appears in the output group
+              later than lines matched against any preceeding checks and
+              earlier than lines matched against any subsequent checks.
+              Surrounding non-negative checks (or boundaries of the group)
+              therefore create a scope within which the assertion is verified.
+
+Check-line patterns are treated as plain text rather than regular expressions
+but are whitespace agnostic.
+
+Actual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If
+curly brackets need to be used inside the body of the regex, they need to be
+enclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse
+the invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'.
+
+Regex patterns can be named and referenced later. A new variable is defined
+with '<<name:regex>>' and can be referenced with '<<name>>'. Variables are
+only valid within the scope of the defining group. Within a group they cannot
+be redefined or used undefined.
+
+Example:
+  The following assertions can be placed in a Java source file:
+
+  // CHECK-START: int MyClass.MyMethod() constant_folding (after)
+  // CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
+  // 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
+  constant folding returns an integer constant with value either 11 or 22.
diff --git a/tools/checker/checker.py b/tools/checker/checker.py
new file mode 100755
index 0000000..ed630e3
--- /dev/null
+++ b/tools/checker/checker.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import os
+
+from common.logger                    import Logger
+from file_format.c1visualizer.parser  import ParseC1visualizerStream
+from file_format.checker.parser       import ParseCheckerStream
+from match.file                       import MatchFiles
+
+def ParseArguments():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("tested_file",
+                      help="text file the checks should be verified against")
+  parser.add_argument("source_path", nargs="?",
+                      help="path to file/folder with checking annotations")
+  parser.add_argument("--check-prefix", dest="check_prefix", default="CHECK", metavar="PREFIX",
+                      help="prefix of checks in the test files (default: CHECK)")
+  parser.add_argument("--list-passes", dest="list_passes", action="store_true",
+                      help="print a list of all passes found in the tested file")
+  parser.add_argument("--dump-pass", dest="dump_pass", metavar="PASS",
+                      help="print a compiler pass dump")
+  parser.add_argument("-q", "--quiet", action="store_true",
+                      help="print only errors")
+  return parser.parse_args()
+
+
+def ListPasses(outputFilename):
+  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
+  for compiler_pass in c1File.passes:
+    Logger.log(compiler_pass.name)
+
+
+def DumpPass(outputFilename, passName):
+  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
+  compiler_pass = c1File.findPass(passName)
+  if compiler_pass:
+    maxLineNo = compiler_pass.startLineNo + len(compiler_pass.body)
+    lenLineNo = len(str(maxLineNo)) + 2
+    curLineNo = compiler_pass.startLineNo
+    for line in compiler_pass.body:
+      Logger.log((str(curLineNo) + ":").ljust(lenLineNo) + line)
+      curLineNo += 1
+  else:
+    Logger.fail("Pass \"" + passName + "\" not found in the output")
+
+
+def FindCheckerFiles(path):
+  """ Returns a list of files to scan for check annotations in the given path.
+      Path to a file is returned as a single-element list, directories are
+      recursively traversed and all '.java' files returned.
+  """
+  if not path:
+    Logger.fail("No source path provided")
+  elif os.path.isfile(path):
+    return [ path ]
+  elif os.path.isdir(path):
+    foundFiles = []
+    for root, dirs, files in os.walk(path):
+      for file in files:
+        extension = os.path.splitext(file)[1]
+        if extension in [".java", ".smali"]:
+          foundFiles.append(os.path.join(root, file))
+    return foundFiles
+  else:
+    Logger.fail("Source path \"" + path + "\" not found")
+
+
+def RunTests(checkPrefix, checkPath, outputFilename):
+  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
+  for checkFilename in FindCheckerFiles(checkPath):
+    checkerFile = ParseCheckerStream(os.path.basename(checkFilename),
+                                     checkPrefix,
+                                     open(checkFilename, "r"))
+    MatchFiles(checkerFile, c1File)
+
+
+if __name__ == "__main__":
+  args = ParseArguments()
+
+  if args.quiet:
+    Logger.Verbosity = Logger.Level.Error
+
+  if args.list_passes:
+    ListPasses(args.tested_file)
+  elif args.dump_pass:
+    DumpPass(args.tested_file, args.dump_pass)
+  else:
+    RunTests(args.check_prefix, args.source_path, args.tested_file)
diff --git a/tools/checker/common/__init__.py b/tools/checker/common/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/common/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tools/checker/common/immutables.py b/tools/checker/common/immutables.py
new file mode 100644
index 0000000..e016867
--- /dev/null
+++ b/tools/checker/common/immutables.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class ImmutableDict(dict):
+  def __setitem__(self, key, value):
+    raise RuntimeError("Cannot modify ImmutableDict")
+
+  def __delitem__(self, key):
+    raise RuntimeError("Cannot modify ImmutableDict")
+
+  def copyWith(self, key, value):
+    newDict = ImmutableDict(self)
+    dict.__setitem__(newDict, key, value)
+    return newDict
diff --git a/tools/checker/common/logger.py b/tools/checker/common/logger.py
new file mode 100644
index 0000000..28bb458
--- /dev/null
+++ b/tools/checker/common/logger.py
@@ -0,0 +1,81 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+import sys
+
+class Logger(object):
+
+  class Level(object):
+    NoOutput, Error, Info = range(3)
+
+  class Color(object):
+    Default, Blue, Gray, Purple, Red = range(5)
+
+    @staticmethod
+    def terminalCode(color, out=sys.stdout):
+      if not out.isatty():
+        return ''
+      elif color == Logger.Color.Blue:
+        return '\033[94m'
+      elif color == Logger.Color.Gray:
+        return '\033[37m'
+      elif color == Logger.Color.Purple:
+        return '\033[95m'
+      elif color == Logger.Color.Red:
+        return '\033[91m'
+      else:
+        return '\033[0m'
+
+  Verbosity = Level.Info
+
+  @staticmethod
+  def log(text, level=Level.Info, color=Color.Default, newLine=True, out=sys.stdout):
+    if level <= Logger.Verbosity:
+      text = Logger.Color.terminalCode(color, out) + text + \
+             Logger.Color.terminalCode(Logger.Color.Default, out)
+      if newLine:
+        print(text, file=out)
+      else:
+        print(text, end="", file=out)
+      out.flush()
+
+  @staticmethod
+  def fail(msg, file=None, line=-1):
+    location = ""
+    if file:
+      location += file + ":"
+    if line > 0:
+      location += str(line) + ":"
+    if location:
+      location += " "
+
+    Logger.log(location, Logger.Level.Error, color=Logger.Color.Gray, newLine=False, out=sys.stderr)
+    Logger.log("error: ", Logger.Level.Error, color=Logger.Color.Red, newLine=False, out=sys.stderr)
+    Logger.log(msg, Logger.Level.Error, out=sys.stderr)
+    sys.exit(msg)
+
+  @staticmethod
+  def startTest(name):
+    Logger.log("TEST ", color=Logger.Color.Purple, newLine=False)
+    Logger.log(name + "... ", newLine=False)
+
+  @staticmethod
+  def testPassed():
+    Logger.log("PASS", color=Logger.Color.Blue)
+
+  @staticmethod
+  def testFailed(msg, file=None, line=-1):
+    Logger.log("FAIL", color=Logger.Color.Red)
+    Logger.fail(msg, file, line)
diff --git a/tools/checker/common/mixins.py b/tools/checker/common/mixins.py
new file mode 100644
index 0000000..819de24
--- /dev/null
+++ b/tools/checker/common/mixins.py
@@ -0,0 +1,26 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class EqualityMixin:
+  """ Object equality via equality of dictionaries. """
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.__dict__ == other.__dict__
+
+class PrintableMixin:
+  """ Prints object as name-dictionary pair. """
+
+  def __repr__(self):
+    return "<%s: %s>" % (type(self).__name__, str(self.__dict__))
diff --git a/tools/checker/common/testing.py b/tools/checker/common/testing.py
new file mode 100644
index 0000000..1299c07
--- /dev/null
+++ b/tools/checker/common/testing.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+def ToUnicode(string):
+  """ Converts a string into Unicode.
+
+  This is a delegate function for the built-in `unicode`. It checks if the input
+  is not `None`, because `unicode` turns it into an actual "None" string.
+  """
+  assert string is not None
+  return unicode(string)
diff --git a/tools/checker/file_format/__init__.py b/tools/checker/file_format/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/file_format/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tools/checker/file_format/c1visualizer/__init__.py b/tools/checker/file_format/c1visualizer/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tools/checker/file_format/c1visualizer/parser.py b/tools/checker/file_format/c1visualizer/parser.py
new file mode 100644
index 0000000..335a195
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/parser.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.logger                   import Logger
+from file_format.common              import SplitStream
+from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
+
+import re
+
+class C1ParserState:
+  OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4)
+
+  def __init__(self):
+    self.currentState = C1ParserState.OutsideBlock
+    self.lastMethodName = None
+
+def __parseC1Line(line, lineNo, state, fileName):
+  """ This function is invoked on each line of the output file and returns
+      a pair which instructs the parser how the line should be handled. If the
+      line is to be included in the current group, it is returned in the first
+      value. If the line starts a new output group, the name of the group is
+      returned in the second value.
+  """
+  if state.currentState == C1ParserState.StartingCfgBlock:
+    # Previous line started a new 'cfg' block which means that this one must
+    # contain the name of the pass (this is enforced by C1visualizer).
+    if re.match("name\s+\"[^\"]+\"", line):
+      # Extract the pass name, prepend it with the name of the method and
+      # return as the beginning of a new group.
+      state.currentState = C1ParserState.InsideCfgBlock
+      return (None, state.lastMethodName + " " + line.split("\"")[1])
+    else:
+      Logger.fail("Expected output group name", fileName, lineNo)
+
+  elif state.currentState == C1ParserState.InsideCfgBlock:
+    if line == "end_cfg":
+      state.currentState = C1ParserState.OutsideBlock
+      return (None, None)
+    else:
+      return (line, None)
+
+  elif state.currentState == C1ParserState.InsideCompilationBlock:
+    # Search for the method's name. Format: method "<name>"
+    if re.match("method\s+\"[^\"]*\"", line):
+      methodName = line.split("\"")[1].strip()
+      if not methodName:
+        Logger.fail("Empty method name in output", fileName, lineNo)
+      state.lastMethodName = methodName
+    elif line == "end_compilation":
+      state.currentState = C1ParserState.OutsideBlock
+    return (None, None)
+
+  else:
+    assert state.currentState == C1ParserState.OutsideBlock
+    if line == "begin_cfg":
+      # The line starts a new group but we'll wait until the next line from
+      # which we can extract the name of the pass.
+      if state.lastMethodName is None:
+        Logger.fail("Expected method header", fileName, lineNo)
+      state.currentState = C1ParserState.StartingCfgBlock
+      return (None, None)
+    elif line == "begin_compilation":
+      state.currentState = C1ParserState.InsideCompilationBlock
+      return (None, None)
+    else:
+      Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
+
+def ParseC1visualizerStream(fileName, stream):
+  c1File = C1visualizerFile(fileName)
+  state = C1ParserState()
+  fnProcessLine = lambda line, lineNo: __parseC1Line(line, lineNo, state, fileName)
+  fnLineOutsideChunk = lambda line, lineNo: \
+      Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
+  for passName, passLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+    C1visualizerPass(c1File, passName, passLines, startLineNo + 1)
+  return c1File
diff --git a/tools/checker/file_format/c1visualizer/struct.py b/tools/checker/file_format/c1visualizer/struct.py
new file mode 100644
index 0000000..991564e
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/struct.py
@@ -0,0 +1,60 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.logger import Logger
+from common.mixins import PrintableMixin
+
+class C1visualizerFile(PrintableMixin):
+
+  def __init__(self, fileName):
+    self.fileName = fileName
+    self.passes = []
+
+  def addPass(self, new_pass):
+    self.passes.append(new_pass)
+
+  def findPass(self, name):
+    for entry in self.passes:
+      if entry.name == name:
+        return entry
+    return None
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.passes == other.passes
+
+
+class C1visualizerPass(PrintableMixin):
+
+  def __init__(self, parent, name, body, startLineNo):
+    self.parent = parent
+    self.name = name
+    self.body = body
+    self.startLineNo = startLineNo
+
+    if not self.name:
+      Logger.fail("C1visualizer pass does not have a name", self.fileName, self.startLineNo)
+    if not self.body:
+      Logger.fail("C1visualizer pass does not have a body", self.fileName, self.startLineNo)
+
+    self.parent.addPass(self)
+
+  @property
+  def fileName(self):
+    return self.parent.fileName
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.name == other.name \
+       and self.body == other.body
diff --git a/tools/checker/file_format/c1visualizer/test.py b/tools/checker/file_format/c1visualizer/test.py
new file mode 100644
index 0000000..812a4cf
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.testing                  import ToUnicode
+from file_format.c1visualizer.parser import ParseC1visualizerStream
+from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
+
+import io
+import unittest
+
+class C1visualizerParser_Test(unittest.TestCase):
+
+  def createFile(self, passList):
+    """ Creates an instance of CheckerFile from provided info.
+
+    Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
+    """
+    c1File = C1visualizerFile("<c1_file>")
+    for passEntry in passList:
+      passName = passEntry[0]
+      passBody = passEntry[1]
+      c1Pass = C1visualizerPass(c1File, passName, passBody, 0)
+    return c1File
+
+  def assertParsesTo(self, c1Text, expectedData):
+    expectedFile = self.createFile(expectedData)
+    actualFile = ParseC1visualizerStream("<c1_file>", io.StringIO(ToUnicode(c1Text)))
+    return self.assertEqual(expectedFile, actualFile)
+
+  def test_EmptyFile(self):
+    self.assertParsesTo("", [])
+
+  def test_SingleGroup(self):
+    self.assertParsesTo(
+      """
+        begin_compilation
+          method "MyMethod"
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+      """,
+      [ ( "MyMethod pass1", [ "foo", "bar" ] ) ])
+
+  def test_MultipleGroups(self):
+    self.assertParsesTo(
+      """
+        begin_compilation
+          name "xyz1"
+          method "MyMethod1"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+        begin_cfg
+          name "pass2"
+          abc
+          def
+        end_cfg
+      """,
+      [ ( "MyMethod1 pass1", [ "foo", "bar" ] ),
+        ( "MyMethod1 pass2", [ "abc", "def" ] ) ])
+    self.assertParsesTo(
+      """
+        begin_compilation
+          name "xyz1"
+          method "MyMethod1"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+        begin_compilation
+          name "xyz2"
+          method "MyMethod2"
+          date 5678
+        end_compilation
+        begin_cfg
+          name "pass2"
+          abc
+          def
+        end_cfg
+      """,
+      [ ( "MyMethod1 pass1", [ "foo", "bar" ] ),
+        ( "MyMethod2 pass2", [ "abc", "def" ] ) ])
diff --git a/tools/checker/file_format/checker/__init__.py b/tools/checker/file_format/checker/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/file_format/checker/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
new file mode 100644
index 0000000..4eed391
--- /dev/null
+++ b/tools/checker/file_format/checker/parser.py
@@ -0,0 +1,147 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from file_format.common         import SplitStream
+from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
+
+import re
+
+def __extractLine(prefix, line):
+  """ Attempts to parse a check line. The regex searches for a comment symbol
+      followed by the CHECK keyword, given attribute and a colon at the very
+      beginning of the line. Whitespaces are ignored.
+  """
+  rIgnoreWhitespace = r"\s*"
+  rCommentSymbols = [r"//", r"#"]
+  regexPrefix = rIgnoreWhitespace + \
+                r"(" + r"|".join(rCommentSymbols) + r")" + \
+                rIgnoreWhitespace + \
+                prefix + r":"
+
+  # The 'match' function succeeds only if the pattern is matched at the
+  # beginning of the line.
+  match = re.match(regexPrefix, line)
+  if match is not None:
+    return line[match.end():].strip()
+  else:
+    return None
+
+def __processLine(line, lineNo, prefix):
+  """ This function is invoked on each line of the check file and returns a pair
+      which instructs the parser how the line should be handled. If the line is
+      to be included in the current check group, it is returned in the first
+      value. If the line starts a new check group, the name of the group is
+      returned in the second value.
+  """
+  # Lines beginning with 'CHECK-START' start a new test case.
+  startLine = __extractLine(prefix + "-START", line)
+  if startLine is not None:
+    return None, startLine
+
+  # Lines starting only with 'CHECK' are matched in order.
+  plainLine = __extractLine(prefix, line)
+  if plainLine is not None:
+    return (plainLine, TestAssertion.Variant.InOrder, lineNo), None
+
+  # 'CHECK-NEXT' lines are in-order but must match the very next line.
+  nextLine = __extractLine(prefix + "-NEXT", line)
+  if nextLine is not None:
+    return (nextLine, TestAssertion.Variant.NextLine, lineNo), None
+
+  # 'CHECK-DAG' lines are no-order assertions.
+  dagLine = __extractLine(prefix + "-DAG", line)
+  if dagLine is not None:
+    return (dagLine, TestAssertion.Variant.DAG, lineNo), None
+
+  # 'CHECK-NOT' lines are no-order negative assertions.
+  notLine = __extractLine(prefix + "-NOT", line)
+  if notLine is not None:
+    return (notLine, TestAssertion.Variant.Not, lineNo), None
+
+  # Other lines are ignored.
+  return None, None
+
+def __isMatchAtStart(match):
+  """ Tests if the given Match occurred at the beginning of the line. """
+  return (match is not None) and (match.start() == 0)
+
+def __firstMatch(matches, string):
+  """ Takes in a list of Match objects and returns the minimal start point among
+      them. If there aren't any successful matches it returns the length of
+      the searched string.
+  """
+  starts = map(lambda m: len(string) if m is None else m.start(), matches)
+  return min(starts)
+
+def ParseCheckerAssertion(parent, line, variant, lineNo):
+  """ This method parses the content of a check line stripped of the initial
+      comment symbol and the CHECK keyword.
+  """
+  assertion = TestAssertion(parent, variant, line, lineNo)
+  # Loop as long as there is something to parse.
+  while line:
+    # Search for the nearest occurrence of the special markers.
+    matchWhitespace = re.search(r"\s+", line)
+    matchPattern = re.search(RegexExpression.Regex.regexPattern, line)
+    matchVariableReference = re.search(RegexExpression.Regex.regexVariableReference, line)
+    matchVariableDefinition = re.search(RegexExpression.Regex.regexVariableDefinition, line)
+
+    # If one of the above was identified at the current position, extract them
+    # from the line, parse them and add to the list of line parts.
+    if __isMatchAtStart(matchWhitespace):
+      # A whitespace in the check line creates a new separator of line parts.
+      # This allows for ignored output between the previous and next parts.
+      line = line[matchWhitespace.end():]
+      assertion.addExpression(RegexExpression.createSeparator())
+    elif __isMatchAtStart(matchPattern):
+      pattern = line[0:matchPattern.end()]
+      pattern = pattern[2:-2]
+      line = line[matchPattern.end():]
+      assertion.addExpression(RegexExpression.createPattern(pattern))
+    elif __isMatchAtStart(matchVariableReference):
+      var = line[0:matchVariableReference.end()]
+      line = line[matchVariableReference.end():]
+      name = var[2:-2]
+      assertion.addExpression(RegexExpression.createVariableReference(name))
+    elif __isMatchAtStart(matchVariableDefinition):
+      var = line[0:matchVariableDefinition.end()]
+      line = line[matchVariableDefinition.end():]
+      colonPos = var.find(":")
+      name = var[2:colonPos]
+      body = var[colonPos+1:-2]
+      assertion.addExpression(RegexExpression.createVariableDefinition(name, body))
+    else:
+      # If we're not currently looking at a special marker, this is a plain
+      # text match all the way until the first special marker (or the end
+      # of the line).
+      firstMatch = __firstMatch([ matchWhitespace,
+                                  matchPattern,
+                                  matchVariableReference,
+                                  matchVariableDefinition ],
+                                line)
+      text = line[0:firstMatch]
+      line = line[firstMatch:]
+      assertion.addExpression(RegexExpression.createText(text))
+  return assertion
+
+def ParseCheckerStream(fileName, prefix, stream):
+  checkerFile = CheckerFile(fileName)
+  fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix)
+  fnLineOutsideChunk = lambda line, lineNo: \
+      Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
+  for caseName, caseLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+    testCase = TestCase(checkerFile, caseName, startLineNo)
+    for caseLine in caseLines:
+      ParseCheckerAssertion(testCase, caseLine[0], caseLine[1], caseLine[2])
+  return checkerFile
diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py
new file mode 100644
index 0000000..6a54142
--- /dev/null
+++ b/tools/checker/file_format/checker/struct.py
@@ -0,0 +1,163 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.logger import Logger
+from common.mixins import EqualityMixin, PrintableMixin
+
+import re
+
+class CheckerFile(PrintableMixin):
+
+  def __init__(self, fileName):
+    self.fileName = fileName
+    self.testCases = []
+
+  def addTestCase(self, new_test_case):
+    self.testCases.append(new_test_case)
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.testCases == other.testCases
+
+
+class TestCase(PrintableMixin):
+
+  def __init__(self, parent, name, startLineNo):
+    assert isinstance(parent, CheckerFile)
+
+    self.parent = parent
+    self.name = name
+    self.assertions = []
+    self.startLineNo = startLineNo
+
+    if not self.name:
+      Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
+
+    self.parent.addTestCase(self)
+
+  @property
+  def fileName(self):
+    return self.parent.fileName
+
+  def addAssertion(self, new_assertion):
+    if new_assertion.variant == TestAssertion.Variant.NextLine:
+      if not self.assertions or \
+         (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
+          self.assertions[-1].variant != TestAssertion.Variant.NextLine):
+        Logger.fail("A next-line assertion can only be placed after an "
+                    "in-order assertion or another next-line assertion.",
+                    new_assertion.fileName, new_assertion.lineNo)
+    self.assertions.append(new_assertion)
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.name == other.name \
+       and self.assertions == other.assertions
+
+
+class TestAssertion(PrintableMixin):
+
+  class Variant(object):
+    """Supported types of assertions."""
+    InOrder, NextLine, DAG, Not = range(4)
+
+  def __init__(self, parent, variant, originalText, lineNo):
+    assert isinstance(parent, TestCase)
+
+    self.parent = parent
+    self.variant = variant
+    self.expressions = []
+    self.lineNo = lineNo
+    self.originalText = originalText
+
+    self.parent.addAssertion(self)
+
+  @property
+  def fileName(self):
+    return self.parent.fileName
+
+  def addExpression(self, new_expression):
+    assert isinstance(new_expression, RegexExpression)
+    if self.variant == TestAssertion.Variant.Not:
+      if new_expression.variant == RegexExpression.Variant.VarDef:
+        Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
+    self.expressions.append(new_expression)
+
+  def toRegex(self):
+    """ Returns a regex pattern for this entire assertion. Only used in tests. """
+    regex = ""
+    for expression in self.expressions:
+      if expression.variant == RegexExpression.Variant.Separator:
+        regex = regex + ", "
+      else:
+        regex = regex + "(" + expression.pattern + ")"
+    return regex
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.variant == other.variant \
+       and self.expressions == other.expressions
+
+
+class RegexExpression(EqualityMixin, PrintableMixin):
+
+  class Variant(object):
+    """Supported language constructs."""
+    Text, Pattern, VarRef, VarDef, Separator = range(5)
+
+  class Regex(object):
+    rName = r"([a-zA-Z][a-zA-Z0-9]*)"
+    rRegex = r"(.+?)"
+    rPatternStartSym = r"(\{\{)"
+    rPatternEndSym = r"(\}\})"
+    rVariableStartSym = r"(<<)"
+    rVariableEndSym = r"(>>)"
+    rVariableSeparator = r"(:)"
+
+    regexPattern = rPatternStartSym + rRegex + rPatternEndSym
+    regexVariableReference = rVariableStartSym + rName + rVariableEndSym
+    regexVariableDefinition = rVariableStartSym + rName + rVariableSeparator + rRegex + rVariableEndSym
+
+  def __init__(self, variant, name, pattern):
+    self.variant = variant
+    self.name = name
+    self.pattern = pattern
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.variant == other.variant \
+       and self.name == other.name \
+       and self.pattern == other.pattern
+
+  @staticmethod
+  def createSeparator():
+    return RegexExpression(RegexExpression.Variant.Separator, None, None)
+
+  @staticmethod
+  def createText(text):
+    return RegexExpression(RegexExpression.Variant.Text, None, re.escape(text))
+
+  @staticmethod
+  def createPattern(pattern):
+    return RegexExpression(RegexExpression.Variant.Pattern, None, pattern)
+
+  @staticmethod
+  def createVariableReference(name):
+    assert re.match(RegexExpression.Regex.rName, name)
+    return RegexExpression(RegexExpression.Variant.VarRef, name, None)
+
+  @staticmethod
+  def createVariableDefinition(name, pattern):
+    assert re.match(RegexExpression.Regex.rName, name)
+    return RegexExpression(RegexExpression.Variant.VarDef, name, pattern)
diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py
new file mode 100644
index 0000000..453deed
--- /dev/null
+++ b/tools/checker/file_format/checker/test.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.testing             import ToUnicode
+from file_format.checker.parser import ParseCheckerStream
+from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
+
+import io
+import unittest
+
+CheckerException = SystemExit
+
+class CheckerParser_PrefixTest(unittest.TestCase):
+
+  def tryParse(self, string):
+    checkerText = u"// CHECK-START: pass\n" + ToUnicode(string)
+    checkFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
+    self.assertEqual(len(checkFile.testCases), 1)
+    testCase = checkFile.testCases[0]
+    return len(testCase.assertions) != 0
+
+  def test_InvalidFormat(self):
+    self.assertFalse(self.tryParse("CHECK"))
+    self.assertFalse(self.tryParse(":CHECK"))
+    self.assertFalse(self.tryParse("CHECK:"))
+    self.assertFalse(self.tryParse("//CHECK"))
+    self.assertFalse(self.tryParse("#CHECK"))
+
+    self.assertTrue(self.tryParse("//CHECK:foo"))
+    self.assertTrue(self.tryParse("#CHECK:bar"))
+
+  def test_InvalidLabel(self):
+    self.assertFalse(self.tryParse("//ACHECK:foo"))
+    self.assertFalse(self.tryParse("#ACHECK:foo"))
+
+  def test_NotFirstOnTheLine(self):
+    self.assertFalse(self.tryParse("A// CHECK: foo"))
+    self.assertFalse(self.tryParse("A # CHECK: foo"))
+    self.assertFalse(self.tryParse("// // CHECK: foo"))
+    self.assertFalse(self.tryParse("# # CHECK: foo"))
+
+  def test_WhitespaceAgnostic(self):
+    self.assertTrue(self.tryParse("  //CHECK: foo"))
+    self.assertTrue(self.tryParse("//  CHECK: foo"))
+    self.assertTrue(self.tryParse("    //CHECK: foo"))
+    self.assertTrue(self.tryParse("//    CHECK: foo"))
+
+
+class CheckerParser_RegexExpressionTest(unittest.TestCase):
+
+  def parseAssertion(self, string, variant=""):
+    checkerText = u"// CHECK-START: pass\n// CHECK" + ToUnicode(variant) + u": " + ToUnicode(string)
+    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
+    self.assertEqual(len(checkerFile.testCases), 1)
+    testCase = checkerFile.testCases[0]
+    self.assertEqual(len(testCase.assertions), 1)
+    return testCase.assertions[0]
+
+  def parseExpression(self, string):
+    line = self.parseAssertion(string)
+    self.assertEqual(1, len(line.expressions))
+    return line.expressions[0]
+
+  def assertEqualsRegex(self, string, expected):
+    self.assertEqual(expected, self.parseAssertion(string).toRegex())
+
+  def assertEqualsText(self, string, text):
+    self.assertEqual(self.parseExpression(string), RegexExpression.createText(text))
+
+  def assertEqualsPattern(self, string, pattern):
+    self.assertEqual(self.parseExpression(string), RegexExpression.createPattern(pattern))
+
+  def assertEqualsVarRef(self, string, name):
+    self.assertEqual(self.parseExpression(string), RegexExpression.createVariableReference(name))
+
+  def assertEqualsVarDef(self, string, name, pattern):
+    self.assertEqual(self.parseExpression(string),
+                     RegexExpression.createVariableDefinition(name, pattern))
+
+  def assertVariantNotEqual(self, string, variant):
+    self.assertNotEqual(variant, self.parseExpression(string).variant)
+
+  # Test that individual parts of the line are recognized
+
+  def test_TextOnly(self):
+    self.assertEqualsText("foo", "foo")
+    self.assertEqualsText("  foo  ", "foo")
+    self.assertEqualsRegex("f$o^o", "(f\$o\^o)")
+
+  def test_PatternOnly(self):
+    self.assertEqualsPattern("{{a?b.c}}", "a?b.c")
+
+  def test_VarRefOnly(self):
+    self.assertEqualsVarRef("<<ABC>>", "ABC")
+
+  def test_VarDefOnly(self):
+    self.assertEqualsVarDef("<<ABC:a?b.c>>", "ABC", "a?b.c")
+
+  def test_TextWithWhitespace(self):
+    self.assertEqualsRegex("foo bar", "(foo), (bar)")
+    self.assertEqualsRegex("foo   bar", "(foo), (bar)")
+
+  def test_TextWithRegex(self):
+    self.assertEqualsRegex("foo{{abc}}bar", "(foo)(abc)(bar)")
+
+  def test_TextWithVar(self):
+    self.assertEqualsRegex("foo<<ABC:abc>>bar", "(foo)(abc)(bar)")
+
+  def test_PlainWithRegexAndWhitespaces(self):
+    self.assertEqualsRegex("foo {{abc}}bar", "(foo), (abc)(bar)")
+    self.assertEqualsRegex("foo{{abc}} bar", "(foo)(abc), (bar)")
+    self.assertEqualsRegex("foo {{abc}} bar", "(foo), (abc), (bar)")
+
+  def test_PlainWithVarAndWhitespaces(self):
+    self.assertEqualsRegex("foo <<ABC:abc>>bar", "(foo), (abc)(bar)")
+    self.assertEqualsRegex("foo<<ABC:abc>> bar", "(foo)(abc), (bar)")
+    self.assertEqualsRegex("foo <<ABC:abc>> bar", "(foo), (abc), (bar)")
+
+  def test_AllKinds(self):
+    self.assertEqualsRegex("foo <<ABC:abc>>{{def}}bar", "(foo), (abc)(def)(bar)")
+    self.assertEqualsRegex("foo<<ABC:abc>> {{def}}bar", "(foo)(abc), (def)(bar)")
+    self.assertEqualsRegex("foo <<ABC:abc>> {{def}} bar", "(foo), (abc), (def), (bar)")
+
+  # # Test that variables and patterns are parsed correctly
+
+  def test_ValidPattern(self):
+    self.assertEqualsPattern("{{abc}}", "abc")
+    self.assertEqualsPattern("{{a[b]c}}", "a[b]c")
+    self.assertEqualsPattern("{{(a{bc})}}", "(a{bc})")
+
+  def test_ValidRef(self):
+    self.assertEqualsVarRef("<<ABC>>", "ABC")
+    self.assertEqualsVarRef("<<A1BC2>>", "A1BC2")
+
+  def test_ValidDef(self):
+    self.assertEqualsVarDef("<<ABC:abc>>", "ABC", "abc")
+    self.assertEqualsVarDef("<<ABC:ab:c>>", "ABC", "ab:c")
+    self.assertEqualsVarDef("<<ABC:a[b]c>>", "ABC", "a[b]c")
+    self.assertEqualsVarDef("<<ABC:(a[bc])>>", "ABC", "(a[bc])")
+
+  def test_Empty(self):
+    self.assertVariantNotEqual("{{}}", RegexExpression.Variant.Pattern)
+    self.assertVariantNotEqual("<<>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<:>>", RegexExpression.Variant.VarDef)
+
+  def test_InvalidVarName(self):
+    self.assertVariantNotEqual("<<0ABC>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<AB=C>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<ABC=>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<0ABC:abc>>", RegexExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<AB=C:abc>>", RegexExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<ABC=:abc>>", RegexExpression.Variant.VarDef)
+
+  def test_BodyMatchNotGreedy(self):
+    self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)")
+    self.assertEqualsRegex("<<ABC:abc>><<DEF:def>>", "(abc)(def)")
+
+  def test_NoVarDefsInNotChecks(self):
+    with self.assertRaises(CheckerException):
+      self.parseAssertion("<<ABC:abc>>", "-NOT")
+
+
+class CheckerParser_FileLayoutTest(unittest.TestCase):
+
+  # Creates an instance of CheckerFile from provided info.
+  # Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
+  def createFile(self, caseList):
+    testFile = CheckerFile("<test_file>")
+    for caseEntry in caseList:
+      caseName = caseEntry[0]
+      testCase = TestCase(testFile, caseName, 0)
+      assertionList = caseEntry[1]
+      for assertionEntry in assertionList:
+        content = assertionEntry[0]
+        variant = assertionEntry[1]
+        assertion = TestAssertion(testCase, variant, content, 0)
+        assertion.addExpression(RegexExpression.createText(content))
+    return testFile
+
+  def assertParsesTo(self, checkerText, expectedData):
+    expectedFile = self.createFile(expectedData)
+    actualFile = self.parse(checkerText)
+    return self.assertEqual(expectedFile, actualFile)
+
+  def parse(self, checkerText):
+    return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
+
+  def test_EmptyFile(self):
+    self.assertParsesTo("", [])
+
+  def test_SingleGroup(self):
+    self.assertParsesTo(
+      """
+        // CHECK-START: Example Group
+        // CHECK:  foo
+        // CHECK:    bar
+      """,
+      [ ( "Example Group", [ ("foo", TestAssertion.Variant.InOrder),
+                             ("bar", TestAssertion.Variant.InOrder) ] ) ])
+
+  def test_MultipleGroups(self):
+    self.assertParsesTo(
+      """
+        // CHECK-START: Example Group1
+        // CHECK: foo
+        // CHECK: bar
+        // CHECK-START: Example Group2
+        // CHECK: abc
+        // CHECK: def
+      """,
+      [ ( "Example Group1", [ ("foo", TestAssertion.Variant.InOrder),
+                              ("bar", TestAssertion.Variant.InOrder) ] ),
+        ( "Example Group2", [ ("abc", TestAssertion.Variant.InOrder),
+                              ("def", TestAssertion.Variant.InOrder) ] ) ])
+
+  def test_AssertionVariants(self):
+    self.assertParsesTo(
+      """
+        // CHECK-START: Example Group
+        // CHECK:      foo1
+        // CHECK:      foo2
+        // CHECK-NEXT: foo3
+        // CHECK-NEXT: foo4
+        // CHECK-NOT:  bar
+        // CHECK-DAG:  abc
+        // CHECK-DAG:  def
+      """,
+      [ ( "Example Group", [ ("foo1", TestAssertion.Variant.InOrder),
+                             ("foo2", TestAssertion.Variant.InOrder),
+                             ("foo3", TestAssertion.Variant.NextLine),
+                             ("foo4", TestAssertion.Variant.NextLine),
+                             ("bar", TestAssertion.Variant.Not),
+                             ("abc", TestAssertion.Variant.DAG),
+                             ("def", TestAssertion.Variant.DAG) ] ) ])
+
+  def test_MisplacedNext(self):
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          // CHECK-START: Example Group
+          // CHECK-DAG:  foo
+          // CHECK-NEXT: bar
+        """)
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          // CHECK-START: Example Group
+          // CHECK-NOT:  foo
+          // CHECK-NEXT: bar
+        """)
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          // CHECK-START: Example Group
+          // CHECK-NEXT: bar
+        """)
diff --git a/tools/checker/file_format/common.py b/tools/checker/file_format/common.py
new file mode 100644
index 0000000..f91fdeb
--- /dev/null
+++ b/tools/checker/file_format/common.py
@@ -0,0 +1,48 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+def SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+  """ Reads the given input stream and splits it into chunks based on
+      information extracted from individual lines.
+
+  Arguments:
+   - fnProcessLine: Called on each line with the text and line number. Must
+     return a pair, name of the chunk started on this line and data extracted
+     from this line (or None in both cases).
+   - fnLineOutsideChunk: Called on attempt to attach data prior to creating
+     a chunk.
+  """
+  lineNo = 0
+  allChunks = []
+  currentChunk = None
+
+  for line in stream:
+    lineNo += 1
+    line = line.strip()
+    if not line:
+      continue
+
+    # Let the child class process the line and return information about it.
+    # The _processLine method can modify the content of the line (or delete it
+    # entirely) and specify whether it starts a new group.
+    processedLine, newChunkName = fnProcessLine(line, lineNo)
+    if newChunkName is not None:
+      currentChunk = (newChunkName, [], lineNo)
+      allChunks.append(currentChunk)
+    if processedLine is not None:
+      if currentChunk is not None:
+        currentChunk[1].append(processedLine)
+      else:
+        fnLineOutsideChunk(line, lineNo)
+  return allChunks
diff --git a/tools/checker/match/__init__.py b/tools/checker/match/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/match/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
new file mode 100644
index 0000000..b22211a
--- /dev/null
+++ b/tools/checker/match/file.py
@@ -0,0 +1,174 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from collections                      import namedtuple
+from common.immutables                import ImmutableDict
+from common.logger                    import Logger
+from file_format.c1visualizer.struct  import C1visualizerFile, C1visualizerPass
+from file_format.checker.struct       import CheckerFile, TestCase, TestAssertion
+from match.line                       import MatchLines
+
+MatchScope = namedtuple("MatchScope", ["start", "end"])
+MatchInfo = namedtuple("MatchInfo", ["scope", "variables"])
+
+class MatchFailedException(Exception):
+  def __init__(self, assertion, lineNo):
+    self.assertion = assertion
+    self.lineNo = lineNo
+
+def splitIntoGroups(assertions):
+  """ Breaks up a list of assertions, grouping instructions which should be
+      tested in the same scope (consecutive DAG and NOT instructions).
+   """
+  splitAssertions = []
+  lastVariant = None
+  for assertion in assertions:
+    if (assertion.variant == lastVariant and
+        assertion.variant in [TestAssertion.Variant.DAG, TestAssertion.Variant.Not]):
+      splitAssertions[-1].append(assertion)
+    else:
+      splitAssertions.append([assertion])
+      lastVariant = assertion.variant
+  return splitAssertions
+
+def findMatchingLine(assertion, c1Pass, scope, variables, excludeLines=[]):
+  """ Finds the first line in `c1Pass` which matches `assertion`.
+
+  Scan only lines numbered between `scope.start` and `scope.end` and not on the
+  `excludeLines` list.
+
+  Returns the index of the `c1Pass` line matching the assertion and variables
+  values after the match.
+
+  Raises MatchFailedException if no such `c1Pass` line can be found.
+  """
+  for i in range(scope.start, scope.end):
+    if i in excludeLines: continue
+    newVariables = MatchLines(assertion, c1Pass.body[i], variables)
+    if newVariables is not None:
+      return MatchInfo(MatchScope(i, i), newVariables)
+  raise MatchFailedException(assertion, scope.start)
+
+def matchDagGroup(assertions, c1Pass, scope, variables):
+  """ Attempts to find matching `c1Pass` lines for a group of DAG assertions.
+
+  Assertions are matched in the list order and variable values propagated. Only
+  lines in `scope` are scanned and each line can only match one assertion.
+
+  Returns the range of `c1Pass` lines covered by this group (min/max of matching
+  line numbers) and the variable values after the match of the last assertion.
+
+  Raises MatchFailedException when an assertion cannot be satisfied.
+  """
+  matchedLines = []
+  for assertion in assertions:
+    assert assertion.variant == TestAssertion.Variant.DAG
+    match = findMatchingLine(assertion, c1Pass, scope, variables, matchedLines)
+    variables = match.variables
+    assert match.scope.start == match.scope.end
+    assert match.scope.start not in matchedLines
+    matchedLines.append(match.scope.start)
+  return MatchInfo(MatchScope(min(matchedLines), max(matchedLines)), variables)
+
+def testNotGroup(assertions, c1Pass, scope, variables):
+  """ Verifies that none of the given NOT assertions matches a line inside
+      the given `scope` of `c1Pass` lines.
+
+  Raises MatchFailedException if an assertion matches a line in the scope.
+  """
+  for i in range(scope.start, scope.end):
+    line = c1Pass.body[i]
+    for assertion in assertions:
+      assert assertion.variant == TestAssertion.Variant.Not
+      if MatchLines(assertion, line, variables) is not None:
+        raise MatchFailedException(assertion, i)
+
+def MatchTestCase(testCase, c1Pass):
+  """ Runs a test case against a C1visualizer graph dump.
+
+  Raises MatchFailedException when an assertion cannot be satisfied.
+  """
+  assert testCase.name == c1Pass.name
+
+  matchFrom = 0
+  variables = ImmutableDict()
+  c1Length = len(c1Pass.body)
+
+  # NOT assertions are verified retrospectively, once the scope is known.
+  pendingNotAssertions = None
+
+  # Prepare assertions by grouping those that are verified in the same scope.
+  # We also add None as an EOF assertion that will set scope for NOTs.
+  assertionGroups = splitIntoGroups(testCase.assertions)
+  assertionGroups.append(None)
+
+  for assertionGroup in assertionGroups:
+    if assertionGroup is None:
+      # EOF marker always matches the last+1 line of c1Pass.
+      match = MatchInfo(MatchScope(c1Length, c1Length), None)
+    elif assertionGroup[0].variant == TestAssertion.Variant.Not:
+      # NOT assertions will be tested together with the next group.
+      assert not pendingNotAssertions
+      pendingNotAssertions = assertionGroup
+      continue
+    elif assertionGroup[0].variant == TestAssertion.Variant.InOrder:
+      # Single in-order assertion. Find the first line that matches.
+      assert len(assertionGroup) == 1
+      scope = MatchScope(matchFrom, c1Length)
+      match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
+    elif assertionGroup[0].variant == TestAssertion.Variant.NextLine:
+      # Single next-line assertion. Test if the current line matches.
+      assert len(assertionGroup) == 1
+      scope = MatchScope(matchFrom, matchFrom + 1)
+      match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
+    else:
+      # A group of DAG assertions. Match them all starting from the same point.
+      assert assertionGroup[0].variant == TestAssertion.Variant.DAG
+      scope = MatchScope(matchFrom, c1Length)
+      match = matchDagGroup(assertionGroup, c1Pass, scope, variables)
+
+    if pendingNotAssertions:
+      # Previous group were NOT assertions. Make sure they don't match any lines
+      # in the [matchFrom, match.start) scope.
+      scope = MatchScope(matchFrom, match.scope.start)
+      testNotGroup(pendingNotAssertions, c1Pass, scope, variables)
+      pendingNotAssertions = None
+
+    # Update state.
+    assert matchFrom <= match.scope.end
+    matchFrom = match.scope.end + 1
+    variables = match.variables
+
+def MatchFiles(checkerFile, c1File):
+  for testCase in checkerFile.testCases:
+    # TODO: Currently does not handle multiple occurrences of the same group
+    # name, e.g. when a pass is run multiple times. It will always try to
+    # match a check group against the first output group of the same name.
+    c1Pass = c1File.findPass(testCase.name)
+    if c1Pass is None:
+      Logger.fail("Test case \"{}\" not found in the CFG file".format(testCase.name),
+                  testCase.fileName, testCase.startLineNo)
+
+    Logger.startTest(testCase.name)
+    try:
+      MatchTestCase(testCase, c1Pass)
+      Logger.testPassed()
+    except MatchFailedException as e:
+      lineNo = c1Pass.startLineNo + e.lineNo
+      if e.assertion.variant == TestAssertion.Variant.Not:
+        Logger.testFailed("NOT assertion matched line {}".format(lineNo),
+                          e.assertion.fileName, e.assertion.lineNo)
+      else:
+        Logger.testFailed("Assertion could not be matched starting from line {}".format(lineNo),
+                          e.assertion.fileName, e.assertion.lineNo)
diff --git a/tools/checker/match/line.py b/tools/checker/match/line.py
new file mode 100644
index 0000000..711d814
--- /dev/null
+++ b/tools/checker/match/line.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.logger              import Logger
+from file_format.checker.struct import RegexExpression
+
+import re
+
+def headAndTail(list):
+  return list[0], list[1:]
+
+def splitAtSeparators(expressions):
+  """ Splits a list of RegexExpressions at separators. """
+  splitExpressions = []
+  wordStart = 0
+  for index, expression in enumerate(expressions):
+    if expression.variant == RegexExpression.Variant.Separator:
+      splitExpressions.append(expressions[wordStart:index])
+      wordStart = index + 1
+  splitExpressions.append(expressions[wordStart:])
+  return splitExpressions
+
+def matchWords(checkerWord, stringWord, variables, pos):
+  """ Attempts to match a list of RegexExpressions against a string.
+      Returns updated variable dictionary if successful and None otherwise.
+  """
+  for expression in checkerWord:
+    # If `expression` is a variable reference, replace it with the value.
+    if expression.variant == RegexExpression.Variant.VarRef:
+      if expression.name in variables:
+        pattern = re.escape(variables[expression.name])
+      else:
+        Logger.testFailed("Multiple definitions of variable \"{}\"".format(expression.name),
+                          pos.fileName, pos.lineNo)
+    else:
+      pattern = expression.pattern
+
+    # Match the expression's regex pattern against the remainder of the word.
+    # Note: re.match will succeed only if matched from the beginning.
+    match = re.match(pattern, stringWord)
+    if not match:
+      return None
+
+    # If `expression` was a variable definition, set the variable's value.
+    if expression.variant == RegexExpression.Variant.VarDef:
+      if expression.name not in variables:
+        variables = variables.copyWith(expression.name, stringWord[:match.end()])
+      else:
+        Logger.testFailed("Multiple definitions of variable \"{}\"".format(expression.name),
+                          pos.fileName, pos.lineNo)
+
+    # Move cursor by deleting the matched characters.
+    stringWord = stringWord[match.end():]
+
+  # Make sure the entire word matched, i.e. `stringWord` is empty.
+  if stringWord:
+    return None
+
+  return variables
+
+def MatchLines(checkerLine, stringLine, variables):
+  """ Attempts to match a CHECK line against a string. Returns variable state
+      after the match if successful and None otherwise.
+  """
+  checkerWords = splitAtSeparators(checkerLine.expressions)
+  stringWords = stringLine.split()
+
+  while checkerWords:
+    # Get the next run of RegexExpressions which must match one string word.
+    checkerWord, checkerWords = headAndTail(checkerWords)
+
+    # Keep reading words until a match is found.
+    wordMatched = False
+    while stringWords:
+      stringWord, stringWords = headAndTail(stringWords)
+      newVariables = matchWords(checkerWord, stringWord, variables, checkerLine)
+      if newVariables is not None:
+        wordMatched = True
+        variables = newVariables
+        break
+    if not wordMatched:
+      return None
+
+  # All RegexExpressions matched. Return new variable state.
+  return variables
diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py
new file mode 100644
index 0000000..348c1d2
--- /dev/null
+++ b/tools/checker/match/test.py
@@ -0,0 +1,388 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.immutables               import ImmutableDict
+from common.testing                  import ToUnicode
+from file_format.c1visualizer.parser import ParseC1visualizerStream
+from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
+from file_format.checker.parser      import ParseCheckerStream, ParseCheckerAssertion
+from file_format.checker.struct      import CheckerFile, TestCase, TestAssertion, RegexExpression
+from match.file                      import MatchTestCase, MatchFailedException
+from match.line                      import MatchLines
+
+import io
+import unittest
+
+CheckerException = SystemExit
+
+class MatchLines_Test(unittest.TestCase):
+
+  def createTestAssertion(self, checkerString):
+    checkerFile = CheckerFile("<checker-file>")
+    testCase = TestCase(checkerFile, "TestMethod TestPass", 0)
+    return ParseCheckerAssertion(testCase, checkerString, TestAssertion.Variant.InOrder, 0)
+
+  def tryMatch(self, checkerString, c1String, varState={}):
+    return MatchLines(self.createTestAssertion(checkerString),
+                      ToUnicode(c1String),
+                      ImmutableDict(varState))
+
+  def assertMatches(self, checkerString, c1String, varState={}):
+    self.assertIsNotNone(self.tryMatch(checkerString, c1String, varState))
+
+  def assertDoesNotMatch(self, checkerString, c1String, varState={}):
+    self.assertIsNone(self.tryMatch(checkerString, c1String, varState))
+
+  def test_TextAndWhitespace(self):
+    self.assertMatches("foo", "foo")
+    self.assertMatches("foo", "  foo  ")
+    self.assertMatches("foo", "foo bar")
+    self.assertDoesNotMatch("foo", "XfooX")
+    self.assertDoesNotMatch("foo", "zoo")
+
+    self.assertMatches("foo bar", "foo   bar")
+    self.assertMatches("foo bar", "abc foo bar def")
+    self.assertMatches("foo bar", "foo foo bar bar")
+
+    self.assertMatches("foo bar", "foo X bar")
+    self.assertDoesNotMatch("foo bar", "foo Xbar")
+
+  def test_Pattern(self):
+    self.assertMatches("foo{{A|B}}bar", "fooAbar")
+    self.assertMatches("foo{{A|B}}bar", "fooBbar")
+    self.assertDoesNotMatch("foo{{A|B}}bar", "fooCbar")
+
+  def test_VariableReference(self):
+    self.assertMatches("foo<<X>>bar", "foobar", {"X": ""})
+    self.assertMatches("foo<<X>>bar", "fooAbar", {"X": "A"})
+    self.assertMatches("foo<<X>>bar", "fooBbar", {"X": "B"})
+    self.assertDoesNotMatch("foo<<X>>bar", "foobar", {"X": "A"})
+    self.assertDoesNotMatch("foo<<X>>bar", "foo bar", {"X": "A"})
+    with self.assertRaises(CheckerException):
+      self.tryMatch("foo<<X>>bar", "foobar", {})
+
+  def test_VariableDefinition(self):
+    self.assertMatches("foo<<X:A|B>>bar", "fooAbar")
+    self.assertMatches("foo<<X:A|B>>bar", "fooBbar")
+    self.assertDoesNotMatch("foo<<X:A|B>>bar", "fooCbar")
+
+    env = self.tryMatch("foo<<X:A.*B>>bar", "fooABbar", {})
+    self.assertEqual(env, {"X": "AB"})
+    env = self.tryMatch("foo<<X:A.*B>>bar", "fooAxxBbar", {})
+    self.assertEqual(env, {"X": "AxxB"})
+
+    self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooAbarAbaz")
+    self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooBbarBbaz")
+    self.assertDoesNotMatch("foo<<X:A|B>>bar<<X>>baz", "fooAbarBbaz")
+
+  def test_NoVariableRedefinition(self):
+    with self.assertRaises(CheckerException):
+      self.tryMatch("<<X:...>><<X>><<X:...>><<X>>", "foofoobarbar")
+
+  def test_EnvNotChangedOnPartialMatch(self):
+    env = {"Y": "foo"}
+    self.assertDoesNotMatch("<<X:A>>bar", "Abaz", env)
+    self.assertFalse("X" in env.keys())
+
+  def test_VariableContentEscaped(self):
+    self.assertMatches("<<X:..>>foo<<X>>", ".*foo.*")
+    self.assertDoesNotMatch("<<X:..>>foo<<X>>", ".*fooAAAA")
+
+
+class MatchFiles_Test(unittest.TestCase):
+
+  def assertMatches(self, checkerString, c1String):
+    checkerString = \
+      """
+        // CHECK-START: MyMethod MyPass
+      """ + checkerString
+    c1String = \
+      """
+        begin_compilation
+          name "MyMethod"
+          method "MyMethod"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "MyPass"
+      """ + c1String + \
+      """
+        end_cfg
+      """
+    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(ToUnicode(checkerString)))
+    c1File = ParseC1visualizerStream("<c1-file>", io.StringIO(ToUnicode(c1String)))
+    assert len(checkerFile.testCases) == 1
+    assert len(c1File.passes) == 1
+    MatchTestCase(checkerFile.testCases[0], c1File.passes[0])
+
+  def assertDoesNotMatch(self, checkerString, c1String):
+    with self.assertRaises(MatchFailedException):
+      self.assertMatches(checkerString, c1String)
+
+  def test_Text(self):
+    self.assertMatches("// CHECK: foo bar", "foo bar")
+    self.assertDoesNotMatch("// CHECK: foo bar", "abc def")
+
+  def test_Pattern(self):
+    self.assertMatches("// CHECK: abc {{de.}}", "abc de#")
+    self.assertDoesNotMatch("// CHECK: abc {{de.}}", "abc d#f")
+
+  def test_Variables(self):
+    self.assertMatches(
+    """
+      // CHECK: foo<<X:.>>bar
+      // CHECK: abc<<X>>def
+    """,
+    """
+      foo0bar
+      abc0def
+    """)
+    self.assertMatches(
+    """
+      // CHECK: foo<<X:([0-9]+)>>bar
+      // CHECK: abc<<X>>def
+      // CHECK: ### <<X>> ###
+    """,
+    """
+      foo1234bar
+      abc1234def
+      ### 1234 ###
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK: foo<<X:([0-9]+)>>bar
+      // CHECK: abc<<X>>def
+    """,
+    """
+      foo1234bar
+      abc1235def
+    """)
+
+  def test_WholeWordMustMatch(self):
+    self.assertMatches("// CHECK: b{{.}}r", "abc bar def")
+    self.assertDoesNotMatch("// CHECK: b{{.}}r", "abc Xbar def")
+    self.assertDoesNotMatch("// CHECK: b{{.}}r", "abc barX def")
+    self.assertDoesNotMatch("// CHECK: b{{.}}r", "abc b r def")
+
+  def test_InOrderAssertions(self):
+    self.assertMatches(
+    """
+      // CHECK: foo
+      // CHECK: bar
+    """,
+    """
+      foo
+      bar
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK: foo
+      // CHECK: bar
+    """,
+    """
+      bar
+      foo
+    """)
+
+  def test_NextLineAssertions(self):
+    self.assertMatches(
+    """
+      // CHECK:      foo
+      // CHECK-NEXT: bar
+      // CHECK-NEXT: abc
+      // CHECK:      def
+    """,
+    """
+      foo
+      bar
+      abc
+      def
+    """)
+    self.assertMatches(
+    """
+      // CHECK:      foo
+      // CHECK-NEXT: bar
+      // CHECK:      def
+    """,
+    """
+      foo
+      bar
+      abc
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK:      foo
+      // CHECK-NEXT: bar
+    """,
+    """
+      foo
+      abc
+      bar
+    """)
+
+    self.assertDoesNotMatch(
+    """
+      // CHECK:      foo
+      // CHECK-NEXT: bar
+    """,
+    """
+      bar
+      foo
+      abc
+    """)
+
+  def test_DagAssertions(self):
+    self.assertMatches(
+    """
+      // CHECK-DAG: foo
+      // CHECK-DAG: bar
+    """,
+    """
+      foo
+      bar
+    """)
+    self.assertMatches(
+    """
+      // CHECK-DAG: foo
+      // CHECK-DAG: bar
+    """,
+    """
+      bar
+      foo
+    """)
+
+  def test_DagAssertionsScope(self):
+    self.assertMatches(
+    """
+      // CHECK:     foo
+      // CHECK-DAG: abc
+      // CHECK-DAG: def
+      // CHECK:     bar
+    """,
+    """
+      foo
+      def
+      abc
+      bar
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK:     foo
+      // CHECK-DAG: abc
+      // CHECK-DAG: def
+      // CHECK:     bar
+    """,
+    """
+      foo
+      abc
+      bar
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK:     foo
+      // CHECK-DAG: abc
+      // CHECK-DAG: def
+      // CHECK:     bar
+    """,
+    """
+      foo
+      def
+      bar
+      abc
+    """)
+
+  def test_NotAssertions(self):
+    self.assertMatches(
+    """
+      // CHECK-NOT: foo
+    """,
+    """
+      abc
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK-NOT: foo
+    """,
+    """
+      abc foo
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK-NOT: foo
+      // CHECK-NOT: bar
+    """,
+    """
+      abc
+      def bar
+    """)
+
+  def test_NotAssertionsScope(self):
+    self.assertMatches(
+    """
+      // CHECK:     abc
+      // CHECK-NOT: foo
+      // CHECK:     def
+    """,
+    """
+      abc
+      def
+    """)
+    self.assertMatches(
+    """
+      // CHECK:     abc
+      // CHECK-NOT: foo
+      // CHECK:     def
+    """,
+    """
+      abc
+      def
+      foo
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK:     abc
+      // CHECK-NOT: foo
+      // CHECK:     def
+    """,
+    """
+      abc
+      foo
+      def
+    """)
+
+  def test_LineOnlyMatchesOnce(self):
+    self.assertMatches(
+    """
+      // CHECK-DAG: foo
+      // CHECK-DAG: foo
+    """,
+    """
+      foo
+      abc
+      foo
+    """)
+    self.assertDoesNotMatch(
+    """
+      // CHECK-DAG: foo
+      // CHECK-DAG: foo
+    """,
+    """
+      foo
+      abc
+      bar
+    """)
diff --git a/tools/checker/run_unit_tests.py b/tools/checker/run_unit_tests.py
new file mode 100755
index 0000000..01708db
--- /dev/null
+++ b/tools/checker/run_unit_tests.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from common.logger                 import Logger
+from file_format.c1visualizer.test import C1visualizerParser_Test
+from file_format.checker.test      import CheckerParser_PrefixTest, \
+                                          CheckerParser_RegexExpressionTest, \
+                                          CheckerParser_FileLayoutTest
+from match.test                    import MatchLines_Test, \
+                                          MatchFiles_Test
+
+import unittest
+
+if __name__ == '__main__':
+  Logger.Verbosity = Logger.Level.NoOutput
+  unittest.main(verbosity=2)
diff --git a/tools/checker_test.py b/tools/checker_test.py
deleted file mode 100755
index 667ca90..0000000
--- a/tools/checker_test.py
+++ /dev/null
@@ -1,474 +0,0 @@
-#!/usr/bin/env python2
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This is a test file which exercises all feautres supported by the domain-
-# specific markup language implemented by Checker.
-
-import checker
-import io
-import unittest
-
-# The parent type of exception expected to be thrown by Checker during tests.
-# It must be specific enough to not cover exceptions thrown due to actual flaws
-# in Checker.
-CheckerException = SystemExit
-
-
-class TestCheckFile_PrefixExtraction(unittest.TestCase):
-  def __tryParse(self, string):
-    checkFile = checker.CheckFile(None, [])
-    return checkFile._extractLine("CHECK", string)
-
-  def test_InvalidFormat(self):
-    self.assertIsNone(self.__tryParse("CHECK"))
-    self.assertIsNone(self.__tryParse(":CHECK"))
-    self.assertIsNone(self.__tryParse("CHECK:"))
-    self.assertIsNone(self.__tryParse("//CHECK"))
-    self.assertIsNone(self.__tryParse("#CHECK"))
-
-    self.assertIsNotNone(self.__tryParse("//CHECK:foo"))
-    self.assertIsNotNone(self.__tryParse("#CHECK:bar"))
-
-  def test_InvalidLabel(self):
-    self.assertIsNone(self.__tryParse("//ACHECK:foo"))
-    self.assertIsNone(self.__tryParse("#ACHECK:foo"))
-
-  def test_NotFirstOnTheLine(self):
-    self.assertIsNone(self.__tryParse("A// CHECK: foo"))
-    self.assertIsNone(self.__tryParse("A # CHECK: foo"))
-    self.assertIsNone(self.__tryParse("// // CHECK: foo"))
-    self.assertIsNone(self.__tryParse("# # CHECK: foo"))
-
-  def test_WhitespaceAgnostic(self):
-    self.assertIsNotNone(self.__tryParse("  //CHECK: foo"))
-    self.assertIsNotNone(self.__tryParse("//  CHECK: foo"))
-    self.assertIsNotNone(self.__tryParse("    //CHECK: foo"))
-    self.assertIsNotNone(self.__tryParse("//    CHECK: foo"))
-
-
-class TestCheckLine_Parse(unittest.TestCase):
-  def __getPartPattern(self, linePart):
-    if linePart.variant == checker.CheckElement.Variant.Separator:
-      return "\s+"
-    else:
-      return linePart.pattern
-
-  def __getRegex(self, checkLine):
-    return "".join(map(lambda x: "(" + self.__getPartPattern(x) + ")", checkLine.lineParts))
-
-  def __tryParse(self, string):
-    return checker.CheckLine(string)
-
-  def __parsesTo(self, string, expected):
-    self.assertEqual(expected, self.__getRegex(self.__tryParse(string)))
-
-  def __tryParseNot(self, string):
-    return checker.CheckLine(string, checker.CheckLine.Variant.Not)
-
-  def __parsesPattern(self, string, pattern):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertEqual(checker.CheckElement.Variant.Pattern, line.lineParts[0].variant)
-    self.assertEqual(pattern, line.lineParts[0].pattern)
-
-  def __parsesVarRef(self, string, name):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertEqual(checker.CheckElement.Variant.VarRef, line.lineParts[0].variant)
-    self.assertEqual(name, line.lineParts[0].name)
-
-  def __parsesVarDef(self, string, name, body):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertEqual(checker.CheckElement.Variant.VarDef, line.lineParts[0].variant)
-    self.assertEqual(name, line.lineParts[0].name)
-    self.assertEqual(body, line.lineParts[0].pattern)
-
-  def __doesNotParse(self, string, partType):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertNotEqual(partType, line.lineParts[0].variant)
-
-  # Test that individual parts of the line are recognized
-
-  def test_TextOnly(self):
-    self.__parsesTo("foo", "(foo)")
-    self.__parsesTo("  foo  ", "(foo)")
-    self.__parsesTo("f$o^o", "(f\$o\^o)")
-
-  def test_TextWithWhitespace(self):
-    self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
-    self.__parsesTo("foo   bar", "(foo)(\s+)(bar)")
-
-  def test_RegexOnly(self):
-    self.__parsesPattern("{{a?b.c}}", "a?b.c")
-
-  def test_VarRefOnly(self):
-    self.__parsesVarRef("[[ABC]]", "ABC")
-
-  def test_VarDefOnly(self):
-    self.__parsesVarDef("[[ABC:a?b.c]]", "ABC", "a?b.c")
-
-  def test_TextWithRegex(self):
-    self.__parsesTo("foo{{abc}}bar", "(foo)(abc)(bar)")
-
-  def test_TextWithVar(self):
-    self.__parsesTo("foo[[ABC:abc]]bar", "(foo)(abc)(bar)")
-
-  def test_PlainWithRegexAndWhitespaces(self):
-    self.__parsesTo("foo {{abc}}bar", "(foo)(\s+)(abc)(bar)")
-    self.__parsesTo("foo{{abc}} bar", "(foo)(abc)(\s+)(bar)")
-    self.__parsesTo("foo {{abc}} bar", "(foo)(\s+)(abc)(\s+)(bar)")
-
-  def test_PlainWithVarAndWhitespaces(self):
-    self.__parsesTo("foo [[ABC:abc]]bar", "(foo)(\s+)(abc)(bar)")
-    self.__parsesTo("foo[[ABC:abc]] bar", "(foo)(abc)(\s+)(bar)")
-    self.__parsesTo("foo [[ABC:abc]] bar", "(foo)(\s+)(abc)(\s+)(bar)")
-
-  def test_AllKinds(self):
-    self.__parsesTo("foo [[ABC:abc]]{{def}}bar", "(foo)(\s+)(abc)(def)(bar)")
-    self.__parsesTo("foo[[ABC:abc]] {{def}}bar", "(foo)(abc)(\s+)(def)(bar)")
-    self.__parsesTo("foo [[ABC:abc]] {{def}} bar", "(foo)(\s+)(abc)(\s+)(def)(\s+)(bar)")
-
-  # Test that variables and patterns are parsed correctly
-
-  def test_ValidPattern(self):
-    self.__parsesPattern("{{abc}}", "abc")
-    self.__parsesPattern("{{a[b]c}}", "a[b]c")
-    self.__parsesPattern("{{(a{bc})}}", "(a{bc})")
-
-  def test_ValidRef(self):
-    self.__parsesVarRef("[[ABC]]", "ABC")
-    self.__parsesVarRef("[[A1BC2]]", "A1BC2")
-
-  def test_ValidDef(self):
-    self.__parsesVarDef("[[ABC:abc]]", "ABC", "abc")
-    self.__parsesVarDef("[[ABC:ab:c]]", "ABC", "ab:c")
-    self.__parsesVarDef("[[ABC:a[b]c]]", "ABC", "a[b]c")
-    self.__parsesVarDef("[[ABC:(a[bc])]]", "ABC", "(a[bc])")
-
-  def test_Empty(self):
-    self.__doesNotParse("{{}}", checker.CheckElement.Variant.Pattern)
-    self.__doesNotParse("[[]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[:]]", checker.CheckElement.Variant.VarDef)
-
-  def test_InvalidVarName(self):
-    self.__doesNotParse("[[0ABC]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[AB=C]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[ABC=]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[0ABC:abc]]", checker.CheckElement.Variant.VarDef)
-    self.__doesNotParse("[[AB=C:abc]]", checker.CheckElement.Variant.VarDef)
-    self.__doesNotParse("[[ABC=:abc]]", checker.CheckElement.Variant.VarDef)
-
-  def test_BodyMatchNotGreedy(self):
-    self.__parsesTo("{{abc}}{{def}}", "(abc)(def)")
-    self.__parsesTo("[[ABC:abc]][[DEF:def]]", "(abc)(def)")
-
-  def test_NoVarDefsInNotChecks(self):
-    with self.assertRaises(CheckerException):
-      self.__tryParseNot("[[ABC:abc]]")
-
-class TestCheckLine_Match(unittest.TestCase):
-  def __matchSingle(self, checkString, outputString, varState={}):
-    checkLine = checker.CheckLine(checkString)
-    newVarState = checkLine.match(outputString, varState)
-    self.assertIsNotNone(newVarState)
-    return newVarState
-
-  def __notMatchSingle(self, checkString, outputString, varState={}):
-    checkLine = checker.CheckLine(checkString)
-    self.assertIsNone(checkLine.match(outputString, varState))
-
-  def test_TextAndWhitespace(self):
-    self.__matchSingle("foo", "foo")
-    self.__matchSingle("foo", "  foo  ")
-    self.__matchSingle("foo", "foo bar")
-    self.__notMatchSingle("foo", "XfooX")
-    self.__notMatchSingle("foo", "zoo")
-
-    self.__matchSingle("foo bar", "foo   bar")
-    self.__matchSingle("foo bar", "abc foo bar def")
-    self.__matchSingle("foo bar", "foo foo bar bar")
-
-    self.__matchSingle("foo bar", "foo X bar")
-    self.__notMatchSingle("foo bar", "foo Xbar")
-
-  def test_Pattern(self):
-    self.__matchSingle("foo{{A|B}}bar", "fooAbar")
-    self.__matchSingle("foo{{A|B}}bar", "fooBbar")
-    self.__notMatchSingle("foo{{A|B}}bar", "fooCbar")
-
-  def test_VariableReference(self):
-    self.__matchSingle("foo[[X]]bar", "foobar", {"X": ""})
-    self.__matchSingle("foo[[X]]bar", "fooAbar", {"X": "A"})
-    self.__matchSingle("foo[[X]]bar", "fooBbar", {"X": "B"})
-    self.__notMatchSingle("foo[[X]]bar", "foobar", {"X": "A"})
-    self.__notMatchSingle("foo[[X]]bar", "foo bar", {"X": "A"})
-    with self.assertRaises(CheckerException):
-      self.__matchSingle("foo[[X]]bar", "foobar", {})
-
-  def test_VariableDefinition(self):
-    self.__matchSingle("foo[[X:A|B]]bar", "fooAbar")
-    self.__matchSingle("foo[[X:A|B]]bar", "fooBbar")
-    self.__notMatchSingle("foo[[X:A|B]]bar", "fooCbar")
-
-    env = self.__matchSingle("foo[[X:A.*B]]bar", "fooABbar", {})
-    self.assertEqual(env, {"X": "AB"})
-    env = self.__matchSingle("foo[[X:A.*B]]bar", "fooAxxBbar", {})
-    self.assertEqual(env, {"X": "AxxB"})
-
-    self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarAbaz")
-    self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooBbarBbaz")
-    self.__notMatchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarBbaz")
-
-  def test_NoVariableRedefinition(self):
-    with self.assertRaises(CheckerException):
-      self.__matchSingle("[[X:...]][[X]][[X:...]][[X]]", "foofoobarbar")
-
-  def test_EnvNotChangedOnPartialMatch(self):
-    env = {"Y": "foo"}
-    self.__notMatchSingle("[[X:A]]bar", "Abaz", env)
-    self.assertFalse("X" in env.keys())
-
-  def test_VariableContentEscaped(self):
-    self.__matchSingle("[[X:..]]foo[[X]]", ".*foo.*")
-    self.__notMatchSingle("[[X:..]]foo[[X]]", ".*fooAAAA")
-
-
-CheckVariant = checker.CheckLine.Variant
-
-def prepareSingleCheck(line):
-  if isinstance(line, str):
-    return checker.CheckLine(line)
-  else:
-    return checker.CheckLine(line[0], line[1])
-
-def prepareChecks(lines):
-  if isinstance(lines, str):
-    lines = lines.splitlines()
-  return list(map(lambda line: prepareSingleCheck(line), lines))
-
-
-class TestCheckGroup_Match(unittest.TestCase):
-  def __matchMulti(self, checkLines, outputString):
-    checkGroup = checker.CheckGroup("MyGroup", prepareChecks(checkLines))
-    outputGroup = checker.OutputGroup("MyGroup", outputString.splitlines())
-    return checkGroup.match(outputGroup)
-
-  def __notMatchMulti(self, checkString, outputString):
-    with self.assertRaises(CheckerException):
-      self.__matchMulti(checkString, outputString)
-
-  def test_TextAndPattern(self):
-    self.__matchMulti("""foo bar
-                         abc {{def}}""",
-                      """foo bar
-                         abc def""");
-    self.__matchMulti("""foo bar
-                         abc {{de.}}""",
-                      """=======
-                         foo bar
-                         =======
-                         abc de#
-                         =======""");
-    self.__notMatchMulti("""//XYZ: foo bar
-                            //XYZ: abc {{def}}""",
-                         """=======
-                            foo bar
-                            =======
-                            abc de#
-                            =======""");
-
-  def test_Variables(self):
-    self.__matchMulti("""foo[[X:.]]bar
-                         abc[[X]]def""",
-                      """foo bar
-                         abc def""");
-    self.__matchMulti("""foo[[X:([0-9]+)]]bar
-                         abc[[X]]def
-                         ### [[X]] ###""",
-                      """foo1234bar
-                         abc1234def
-                         ### 1234 ###""");
-
-  def test_Ordering(self):
-    self.__matchMulti([("foo", CheckVariant.InOrder),
-                       ("bar", CheckVariant.InOrder)],
-                      """foo
-                         bar""")
-    self.__notMatchMulti([("foo", CheckVariant.InOrder),
-                          ("bar", CheckVariant.InOrder)],
-                         """bar
-                            foo""")
-    self.__matchMulti([("abc", CheckVariant.DAG),
-                       ("def", CheckVariant.DAG)],
-                      """abc
-                         def""")
-    self.__matchMulti([("abc", CheckVariant.DAG),
-                       ("def", CheckVariant.DAG)],
-                      """def
-                         abc""")
-    self.__matchMulti([("foo", CheckVariant.InOrder),
-                       ("abc", CheckVariant.DAG),
-                       ("def", CheckVariant.DAG),
-                       ("bar", CheckVariant.InOrder)],
-                      """foo
-                         def
-                         abc
-                         bar""")
-    self.__notMatchMulti([("foo", CheckVariant.InOrder),
-                          ("abc", CheckVariant.DAG),
-                          ("def", CheckVariant.DAG),
-                          ("bar", CheckVariant.InOrder)],
-                         """foo
-                            abc
-                            bar""")
-    self.__notMatchMulti([("foo", CheckVariant.InOrder),
-                          ("abc", CheckVariant.DAG),
-                          ("def", CheckVariant.DAG),
-                          ("bar", CheckVariant.InOrder)],
-                         """foo
-                            def
-                            bar""")
-
-  def test_NotAssertions(self):
-    self.__matchMulti([("foo", CheckVariant.Not)],
-                      """abc
-                         def""")
-    self.__notMatchMulti([("foo", CheckVariant.Not)],
-                         """abc foo
-                            def""")
-    self.__notMatchMulti([("foo", CheckVariant.Not),
-                          ("bar", CheckVariant.Not)],
-                         """abc
-                            def bar""")
-
-  def test_LineOnlyMatchesOnce(self):
-    self.__matchMulti([("foo", CheckVariant.DAG),
-                       ("foo", CheckVariant.DAG)],
-                       """foo
-                          foo""")
-    self.__notMatchMulti([("foo", CheckVariant.DAG),
-                          ("foo", CheckVariant.DAG)],
-                          """foo
-                             bar""")
-
-class TestOutputFile_Parse(unittest.TestCase):
-  def __parsesTo(self, string, expected):
-    if isinstance(string, str):
-      string = unicode(string)
-    outputStream = io.StringIO(string)
-    return self.assertEqual(checker.OutputFile(outputStream).groups, expected)
-
-  def test_NoInput(self):
-    self.__parsesTo(None, [])
-    self.__parsesTo("", [])
-
-  def test_SingleGroup(self):
-    self.__parsesTo("""begin_compilation
-                         method "MyMethod"
-                       end_compilation
-                       begin_cfg
-                         name "pass1"
-                         foo
-                         bar
-                       end_cfg""",
-                    [ checker.OutputGroup("MyMethod pass1", [ "foo", "bar" ]) ])
-
-  def test_MultipleGroups(self):
-    self.__parsesTo("""begin_compilation
-                         name "xyz1"
-                         method "MyMethod1"
-                         date 1234
-                       end_compilation
-                       begin_cfg
-                         name "pass1"
-                         foo
-                         bar
-                       end_cfg
-                       begin_cfg
-                         name "pass2"
-                         abc
-                         def
-                       end_cfg""",
-                    [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
-                      checker.OutputGroup("MyMethod1 pass2", [ "abc", "def" ]) ])
-
-    self.__parsesTo("""begin_compilation
-                         name "xyz1"
-                         method "MyMethod1"
-                         date 1234
-                       end_compilation
-                       begin_cfg
-                         name "pass1"
-                         foo
-                         bar
-                       end_cfg
-                       begin_compilation
-                         name "xyz2"
-                         method "MyMethod2"
-                         date 5678
-                       end_compilation
-                       begin_cfg
-                         name "pass2"
-                         abc
-                         def
-                       end_cfg""",
-                    [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
-                      checker.OutputGroup("MyMethod2 pass2", [ "abc", "def" ]) ])
-
-class TestCheckFile_Parse(unittest.TestCase):
-  def __parsesTo(self, string, expected):
-    if isinstance(string, str):
-      string = unicode(string)
-    checkStream = io.StringIO(string)
-    return self.assertEqual(checker.CheckFile("CHECK", checkStream).groups, expected)
-
-  def test_NoInput(self):
-    self.__parsesTo(None, [])
-    self.__parsesTo("", [])
-
-  def test_SingleGroup(self):
-    self.__parsesTo("""// CHECK-START: Example Group
-                       // CHECK:  foo
-                       // CHECK:    bar""",
-                    [ checker.CheckGroup("Example Group", prepareChecks([ "foo", "bar" ])) ])
-
-  def test_MultipleGroups(self):
-    self.__parsesTo("""// CHECK-START: Example Group1
-                       // CHECK: foo
-                       // CHECK: bar
-                       // CHECK-START: Example Group2
-                       // CHECK: abc
-                       // CHECK: def""",
-                    [ checker.CheckGroup("Example Group1", prepareChecks([ "foo", "bar" ])),
-                      checker.CheckGroup("Example Group2", prepareChecks([ "abc", "def" ])) ])
-
-  def test_CheckVariants(self):
-    self.__parsesTo("""// CHECK-START: Example Group
-                       // CHECK:     foo
-                       // CHECK-NOT: bar
-                       // CHECK-DAG: abc
-                       // CHECK-DAG: def""",
-                    [ checker.CheckGroup("Example Group",
-                                         prepareChecks([ ("foo", CheckVariant.InOrder),
-                                                         ("bar", CheckVariant.Not),
-                                                         ("abc", CheckVariant.DAG),
-                                                         ("def", CheckVariant.DAG) ])) ])
-
-if __name__ == '__main__':
-  checker.Logger.Verbosity = checker.Logger.Level.NoOutput
-  unittest.main()
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index a387036..064abc1 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -21,12 +21,19 @@
   name: "libcore.java.lang.SystemTest#testSystemProperties_mutable"
 },
 {
-  description: "Differences between vogar and cts",
+  description: "Differences between vogar and cts. Passes with --mode activity",
   result: EXEC_FAILED,
   modes: [device],
-  names: ["libcore.java.lang.OldSystemTest#test_getProperties",
-          "org.apache.harmony.tests.java.lang.Process2Test#test_getErrorStream",
-          "org.apache.harmony.tests.java.lang.ProcessTest#test_exitValue"]
+  names: ["libcore.java.lang.OldSystemTest#test_getProperties"]
+},
+{
+  description: "Differences between vogar and cts. EACCESS when run with vogar.
+                Passes on host, passes with cts. Passes with vogar with su
+                (--invoke-with \"su root\"). Does not pass after setting chmod
+                777 all directories on path to socket (on device without su).",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.io.OsTest#testUnixDomainSockets_in_file_system"]
 },
 {
   description: "Failures needing investigation",
@@ -34,15 +41,9 @@
   modes: [device],
   names: ["libcore.java.util.TimeZoneTest#testDisplayNames",
           "libcore.java.util.TimeZoneTest#test_useDaylightTime_Taiwan",
-          "libcore.java.util.TimeZoneTest#testAllDisplayNames",
-          "libcore.io.OsTest#testUnixDomainSockets_in_file_system",
-          "org.apache.harmony.luni.tests.java.net.URLConnectionTest#test_setReadTimeoutI",
           "org.apache.harmony.tests.java.util.DateTest#test_Constructor",
           "org.apache.harmony.tests.java.util.ScannerTest#test_Constructor_LReadableByteChannel",
-          "org.apache.harmony.tests.java.util.TimeZoneTest#test_hasSameRules_Ljava_util_TimeZone",
-          "org.apache.harmony.tests.java.text.ChoiceFormatTest#testEscapedPatternWithConsecutiveQuotes",
-          "org.apache.harmony.tests.java.text.ChoiceFormatTest#testToPatternWithInfinities",
-          "org.apache.harmony.tests.java.text.MessageFormatTest#test19011159"]
+          "org.apache.harmony.tests.java.util.TimeZoneTest#test_hasSameRules_Ljava_util_TimeZone"]
 },
 {
   description: "Failing due to a locale problem on hammerhead.",
@@ -109,18 +110,6 @@
   bug: 19165288
 },
 {
-  description: "Bug in libcore",
-  result: EXEC_FAILED,
-  names: ["libcore.javax.crypto.ECDHKeyAgreementTest#testInit_withUnsupportedPrivateKeyType"],
-  bug: 19730263
-},
-{
-  description: "Needs to be run as root",
-  result: EXEC_FAILED,
-  modes: [host],
-  names: ["libcore.io.OsTest#test_PacketSocketAddress"]
-},
-{
   description: "Needs kernel updates on host/device",
   result: EXEC_FAILED,
   names: ["libcore.io.OsTest#test_socketPing"]
@@ -130,5 +119,11 @@
   modes: [device],
   result: EXEC_FAILED,
   names: ["org.apache.harmony.tests.java.lang.ProcessManagerTest#testEnvironment"]
+},
+{
+  description: "Crypto failures",
+  result: EXEC_FAILED,
+  names: ["libcore.javax.crypto.CipherTest#testCipher_ShortBlock_Failure",
+          "libcore.javax.crypto.CipherTest#testCipher_Success"]
 }
 ]
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 1dd443b..77e8004 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -21,11 +21,10 @@
 
 # Jar containing all the tests.
 test_jar=out/host/linux-x86/framework/apache-harmony-jdwp-tests-hostdex.jar
-junit_jar=out/host/linux-x86/framework/junit.jar
 
-if [ ! -f $test_jar -o ! -f $junit_jar ]; then
+if [ ! -f $test_jar ]; then
   echo "Before running, you must build jdwp tests and vogar:" \
-       "make junit apache-harmony-jdwp-tests-hostdex vogar vogar.jar"
+       "make apache-harmony-jdwp-tests-hostdex vogar vogar.jar"
   exit 1
 fi
 
@@ -80,7 +79,6 @@
       --vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \
       --vm-arg -Djpda.settings.debuggeeJavaPath="\"$art_debugee $image $debuggee_args\"" \
       --classpath $test_jar \
-      --classpath $junit_jar \
       --vm-arg -Xcompiler-option --vm-arg --compiler-backend=Optimizing \
       --vm-arg -Xcompiler-option --vm-arg --debuggable \
       org.apache.harmony.jpda.tests.share.AllTests