Merge "Template BitTable based on the accessors."
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index ba3ef05..08b1e10 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -96,7 +96,7 @@
 $$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
 	@echo "host dex2oat: $$@"
 	@mkdir -p $$(dir $$@)
-	$$(hide) $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
+	$$(hide) ANDROID_LOG_TAGS="*:e" $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
 	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
 	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(HOST_CORE_DEX_FILES)) \
 	  $$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index 4863718..e6b6326 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -479,7 +479,10 @@
     HInstruction* next = current->GetNext();
     // Do not kill the set with the side effects of the instruction just now: if
     // the instruction is GVN'ed, we don't need to kill.
-    if (current->CanBeMoved()) {
+    //
+    // BoundType is a special case example of an instruction which shouldn't be moved but can be
+    // GVN'ed.
+    if (current->CanBeMoved() || current->IsBoundType()) {
       if (current->IsBinaryOperation() && current->AsBinaryOperation()->IsCommutative()) {
         // For commutative ops, (x op y) will be treated the same as (y op x)
         // after fixed ordering.
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index ef8a757..661f66a 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2786,6 +2786,14 @@
   SetPackedFlag<kFlagReferenceTypeIsExact>(rti.IsExact());
 }
 
+bool HBoundType::InstructionDataEquals(const HInstruction* other) const {
+  const HBoundType* other_bt = other->AsBoundType();
+  ScopedObjectAccess soa(Thread::Current());
+  return GetUpperBound().IsEqual(other_bt->GetUpperBound()) &&
+         GetUpperCanBeNull() == other_bt->GetUpperCanBeNull() &&
+         CanBeNull() == other_bt->CanBeNull();
+}
+
 void HBoundType::SetUpperBound(const ReferenceTypeInfo& upper_bound, bool can_be_null) {
   if (kIsDebugBuild) {
     ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 2037879..975ad1c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -7142,6 +7142,7 @@
     SetRawInputAt(0, input);
   }
 
+  bool InstructionDataEquals(const HInstruction* other) const OVERRIDE;
   bool IsClonable() const OVERRIDE { return true; }
 
   // {Get,Set}Upper* should only be used in reference type propagation.
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index f6bd052..2f782f3 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -195,14 +195,19 @@
         // SsaLivenessAnalysis.
         for (size_t i = 0, e = environment->Size(); i < e; ++i) {
           HInstruction* instruction = environment->GetInstructionAt(i);
+          if (instruction == nullptr) {
+            continue;
+          }
           bool should_be_live = ShouldBeLiveForEnvironment(current, instruction);
+          // If this environment use does not keep the instruction live, it does not
+          // affect the live range of that instruction.
           if (should_be_live) {
             CHECK(instruction->HasSsaIndex()) << instruction->DebugName();
             live_in->SetBit(instruction->GetSsaIndex());
-          }
-          if (instruction != nullptr) {
-            instruction->GetLiveInterval()->AddUse(
-                current, environment, i, /* actual_user */ nullptr, should_be_live);
+            instruction->GetLiveInterval()->AddUse(current,
+                                                   environment,
+                                                   i,
+                                                   /* actual_user */ nullptr);
           }
         }
       }
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index f83bb52..83ca5bd 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -300,8 +300,7 @@
   void AddUse(HInstruction* instruction,
               HEnvironment* environment,
               size_t input_index,
-              HInstruction* actual_user = nullptr,
-              bool keep_alive = false) {
+              HInstruction* actual_user = nullptr) {
     bool is_environment = (environment != nullptr);
     LocationSummary* locations = instruction->GetLocations();
     if (actual_user == nullptr) {
@@ -359,12 +358,6 @@
       uses_.push_front(*new_use);
     }
 
-    if (is_environment && !keep_alive) {
-      // If this environment use does not keep the instruction live, it does not
-      // affect the live range of that instruction.
-      return;
-    }
-
     size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
     if (first_range_ == nullptr) {
       // First time we see a use of that interval.
@@ -1157,8 +1150,11 @@
  *     of an instruction that has a primitive type make the instruction live.
  *     If the graph does not have the debuggable property, the environment
  *     use has no effect, and may get a 'none' value after register allocation.
+ * (d) When compiling in OSR mode, all loops in the compiled method may be entered
+ *     from the interpreter via SuspendCheck; such use in SuspendCheck makes the instruction
+ *     live.
  *
- * (b) and (c) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
+ * (b), (c) and (d) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
  */
 class SsaLivenessAnalysis : public ValueObject {
  public:
@@ -1259,14 +1255,18 @@
   // Returns whether `instruction` in an HEnvironment held by `env_holder`
   // should be kept live by the HEnvironment.
   static bool ShouldBeLiveForEnvironment(HInstruction* env_holder, HInstruction* instruction) {
-    if (instruction == nullptr) return false;
+    DCHECK(instruction != nullptr);
     // A value that's not live in compiled code may still be needed in interpreter,
     // due to code motion, etc.
     if (env_holder->IsDeoptimize()) return true;
     // A value live at a throwing instruction in a try block may be copied by
     // the exception handler to its location at the top of the catch block.
     if (env_holder->CanThrowIntoCatchBlock()) return true;
-    if (instruction->GetBlock()->GetGraph()->IsDebuggable()) return true;
+    HGraph* graph = instruction->GetBlock()->GetGraph();
+    if (graph->IsDebuggable()) return true;
+    // When compiling in OSR mode, all loops in the compiled method may be entered
+    // from the interpreter via SuspendCheck; thus we need to preserve the environment.
+    if (env_holder->IsSuspendCheck() && graph->IsCompilingOsr()) return true;
     return instruction->GetType() == DataType::Type::kReference;
   }
 
diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc
index b9bfbaa..ae5e4e7 100644
--- a/compiler/optimizing/ssa_liveness_analysis_test.cc
+++ b/compiler/optimizing/ssa_liveness_analysis_test.cc
@@ -134,12 +134,12 @@
   static const char* const expected[] = {
       "ranges: { [2,21) }, uses: { 15 17 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [4,21) }, uses: { 19 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
+      "ranges: { [4,21) }, uses: { 19 21 }, { } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [6,21) }, uses: { 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
+      "ranges: { [6,21) }, uses: { 21 }, { } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
       // Environment uses do not keep the non-reference argument alive.
-      "ranges: { [8,10) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+      "ranges: { [8,10) }, uses: { }, { } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
       // Environment uses keep the reference argument alive.
       "ranges: { [10,19) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
   };
@@ -207,11 +207,11 @@
   static const char* const expected[] = {
       "ranges: { [2,23) }, uses: { 15 17 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [4,23) }, uses: { 19 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 "
+      "ranges: { [4,23) }, uses: { 19 23 }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [6,23) }, uses: { 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+      "ranges: { [6,23) }, uses: { 23 }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
       // Environment use in HDeoptimize keeps even the non-reference argument alive.
-      "ranges: { [8,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+      "ranges: { [8,21) }, uses: { }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
       // Environment uses keep the reference argument alive.
       "ranges: { [10,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
   };
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 3f5dbcf..00fb0af 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -40,9 +40,8 @@
 
 uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) {
   const uint32_t start_offset = stream->Tell();
-  const dex_ir::Collections& collections = header_->GetCollections();
   // Debug offsets for method indexes. 0 means no debug info.
-  std::vector<uint32_t> debug_info_offsets(collections.MethodIdsSize(), 0u);
+  std::vector<uint32_t> debug_info_offsets(header_->MethodIds().Size(), 0u);
 
   static constexpr InvokeType invoke_types[] = {
     kDirect,
@@ -50,7 +49,7 @@
   };
 
   for (InvokeType invoke_type : invoke_types) {
-    for (const std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+    for (auto& class_def : header_->ClassDefs()) {
       // Skip classes that are not defined in this dex file.
       dex_ir::ClassData* class_data = class_def->GetClassData();
       if (class_data == nullptr) {
@@ -232,14 +231,13 @@
 }
 
 void CompactDexWriter::SortDebugInfosByMethodIndex() {
-  dex_ir::Collections& collections = header_->GetCollections();
   static constexpr InvokeType invoke_types[] = {
     kDirect,
     kVirtual
   };
   std::map<const dex_ir::DebugInfoItem*, uint32_t> method_idx_map;
   for (InvokeType invoke_type : invoke_types) {
-    for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+    for (auto& class_def : header_->ClassDefs()) {
       // Skip classes that are not defined in this dex file.
       dex_ir::ClassData* class_data = class_def->GetClassData();
       if (class_data == nullptr) {
@@ -257,8 +255,8 @@
       }
     }
   }
-  std::sort(collections.DebugInfoItems().begin(),
-            collections.DebugInfoItems().end(),
+  std::sort(header_->DebugInfoItems().begin(),
+            header_->DebugInfoItems().end(),
             [&](const std::unique_ptr<dex_ir::DebugInfoItem>& a,
                 const std::unique_ptr<dex_ir::DebugInfoItem>& b) {
     auto it_a = method_idx_map.find(a.get());
@@ -282,20 +280,19 @@
   header.endian_tag_ = header_->EndianTag();
   header.link_size_ = header_->LinkSize();
   header.link_off_ = header_->LinkOffset();
-  const dex_ir::Collections& collections = header_->GetCollections();
-  header.map_off_ = collections.MapListOffset();
-  header.string_ids_size_ = collections.StringIdsSize();
-  header.string_ids_off_ = collections.StringIdsOffset();
-  header.type_ids_size_ = collections.TypeIdsSize();
-  header.type_ids_off_ = collections.TypeIdsOffset();
-  header.proto_ids_size_ = collections.ProtoIdsSize();
-  header.proto_ids_off_ = collections.ProtoIdsOffset();
-  header.field_ids_size_ = collections.FieldIdsSize();
-  header.field_ids_off_ = collections.FieldIdsOffset();
-  header.method_ids_size_ = collections.MethodIdsSize();
-  header.method_ids_off_ = collections.MethodIdsOffset();
-  header.class_defs_size_ = collections.ClassDefsSize();
-  header.class_defs_off_ = collections.ClassDefsOffset();
+  header.map_off_ = header_->MapListOffset();
+  header.string_ids_size_ = header_->StringIds().Size();
+  header.string_ids_off_ = header_->StringIds().GetOffset();
+  header.type_ids_size_ = header_->TypeIds().Size();
+  header.type_ids_off_ = header_->TypeIds().GetOffset();
+  header.proto_ids_size_ = header_->ProtoIds().Size();
+  header.proto_ids_off_ = header_->ProtoIds().GetOffset();
+  header.field_ids_size_ = header_->FieldIds().Size();
+  header.field_ids_off_ = header_->FieldIds().GetOffset();
+  header.method_ids_size_ = header_->MethodIds().Size();
+  header.method_ids_off_ = header_->MethodIds().GetOffset();
+  header.class_defs_size_ = header_->ClassDefs().Size();
+  header.class_defs_off_ = header_->ClassDefs().GetOffset();
   header.data_size_ = header_->DataSize();
   header.data_off_ = header_->DataOffset();
   header.owned_data_begin_ = owned_data_begin_;
@@ -332,16 +329,15 @@
 }
 
 bool CompactDexWriter::CanGenerateCompactDex(std::string* error_msg) {
-  dex_ir::Collections& collections = header_->GetCollections();
   static constexpr InvokeType invoke_types[] = {
     kDirect,
     kVirtual
   };
-  std::vector<bool> saw_method_id(collections.MethodIdsSize(), false);
-  std::vector<dex_ir::CodeItem*> method_id_code_item(collections.MethodIdsSize(), nullptr);
-  std::vector<dex_ir::DebugInfoItem*> method_id_debug_info(collections.MethodIdsSize(), nullptr);
+  std::vector<bool> saw_method_id(header_->MethodIds().Size(), false);
+  std::vector<dex_ir::CodeItem*> method_id_code_item(header_->MethodIds().Size(), nullptr);
+  std::vector<dex_ir::DebugInfoItem*> method_id_debug_info(header_->MethodIds().Size(), nullptr);
   for (InvokeType invoke_type : invoke_types) {
-    for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+    for (auto& class_def : header_->ClassDefs()) {
       // Skip classes that are not defined in this dex file.
       dex_ir::ClassData* class_data = class_def->GetClassData();
       if (class_data == nullptr) {
@@ -407,8 +403,6 @@
   // Starting offset is right after the header.
   main_stream->Seek(GetHeaderSize());
 
-  dex_ir::Collections& collection = header_->GetCollections();
-
   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
   // Since the offsets may not be calculated already, the writing must be done in the correct order.
   const uint32_t string_ids_offset = main_stream->Tell();
@@ -469,16 +463,16 @@
   // Write the map list.
   if (compute_offsets_) {
     data_stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
-    collection.SetMapListOffset(data_stream->Tell());
+    header_->SetMapListOffset(data_stream->Tell());
   } else {
-    data_stream->Seek(collection.MapListOffset());
+    data_stream->Seek(header_->MapListOffset());
   }
 
   // Map items are included in the data section.
   GenerateAndWriteMapItems(data_stream);
 
   // Write link data if it exists.
-  const std::vector<uint8_t>& link_data = collection.LinkData();
+  const std::vector<uint8_t>& link_data = header_->LinkData();
   if (link_data.size() > 0) {
     CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
     if (compute_offsets_) {
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 15e3baf..3917847 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -30,873 +30,11 @@
 namespace art {
 namespace dex_ir {
 
-static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
-  uint64_t value = 0;
-  for (uint32_t i = 0; i <= length; i++) {
-    value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
-  }
-  if (sign_extend) {
-    int shift = (7 - length) * 8;
-    return (static_cast<int64_t>(value) << shift) >> shift;
-  }
-  return value;
-}
-
-static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
-  const uint8_t* stream = debug_info_stream;
-  DecodeUnsignedLeb128(&stream);  // line_start
-  uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
-  for (uint32_t i = 0; i < parameters_size; ++i) {
-    DecodeUnsignedLeb128P1(&stream);  // Parameter name.
-  }
-
-  for (;;)  {
-    uint8_t opcode = *stream++;
-    switch (opcode) {
-      case DexFile::DBG_END_SEQUENCE:
-        return stream - debug_info_stream;  // end of stream.
-      case DexFile::DBG_ADVANCE_PC:
-        DecodeUnsignedLeb128(&stream);  // addr_diff
-        break;
-      case DexFile::DBG_ADVANCE_LINE:
-        DecodeSignedLeb128(&stream);  // line_diff
-        break;
-      case DexFile::DBG_START_LOCAL:
-        DecodeUnsignedLeb128(&stream);  // register_num
-        DecodeUnsignedLeb128P1(&stream);  // name_idx
-        DecodeUnsignedLeb128P1(&stream);  // type_idx
-        break;
-      case DexFile::DBG_START_LOCAL_EXTENDED:
-        DecodeUnsignedLeb128(&stream);  // register_num
-        DecodeUnsignedLeb128P1(&stream);  // name_idx
-        DecodeUnsignedLeb128P1(&stream);  // type_idx
-        DecodeUnsignedLeb128P1(&stream);  // sig_idx
-        break;
-      case DexFile::DBG_END_LOCAL:
-      case DexFile::DBG_RESTART_LOCAL:
-        DecodeUnsignedLeb128(&stream);  // register_num
-        break;
-      case DexFile::DBG_SET_PROLOGUE_END:
-      case DexFile::DBG_SET_EPILOGUE_BEGIN:
-        break;
-      case DexFile::DBG_SET_FILE: {
-        DecodeUnsignedLeb128P1(&stream);  // name_idx
-        break;
-      }
-      default: {
-        break;
-      }
-    }
-  }
-}
-
-static bool GetIdFromInstruction(Collections& collections,
-                                 const Instruction* dec_insn,
-                                 std::vector<TypeId*>* type_ids,
-                                 std::vector<StringId*>* string_ids,
-                                 std::vector<MethodId*>* method_ids,
-                                 std::vector<FieldId*>* field_ids) {
-  // Determine index and width of the string.
-  uint32_t index = 0;
-  switch (Instruction::FormatOf(dec_insn->Opcode())) {
-    // SOME NOT SUPPORTED:
-    // case Instruction::k20bc:
-    case Instruction::k21c:
-    case Instruction::k35c:
-    // case Instruction::k35ms:
-    case Instruction::k3rc:
-    // case Instruction::k3rms:
-    // case Instruction::k35mi:
-    // case Instruction::k3rmi:
-    case Instruction::k45cc:
-    case Instruction::k4rcc:
-      index = dec_insn->VRegB();
-      break;
-    case Instruction::k31c:
-      index = dec_insn->VRegB();
-      break;
-    case Instruction::k22c:
-    // case Instruction::k22cs:
-      index = dec_insn->VRegC();
-      break;
-    default:
-      break;
-  }  // switch
-
-  // Determine index type, and add reference to the appropriate collection.
-  switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
-    case Instruction::kIndexTypeRef:
-      if (index < collections.TypeIdsSize()) {
-        type_ids->push_back(collections.GetTypeId(index));
-        return true;
-      }
-      break;
-    case Instruction::kIndexStringRef:
-      if (index < collections.StringIdsSize()) {
-        string_ids->push_back(collections.GetStringId(index));
-        return true;
-      }
-      break;
-    case Instruction::kIndexMethodRef:
-    case Instruction::kIndexMethodAndProtoRef:
-      if (index < collections.MethodIdsSize()) {
-        method_ids->push_back(collections.GetMethodId(index));
-        return true;
-      }
-      break;
-    case Instruction::kIndexFieldRef:
-      if (index < collections.FieldIdsSize()) {
-        field_ids->push_back(collections.GetFieldId(index));
-        return true;
-      }
-      break;
-    case Instruction::kIndexUnknown:
-    case Instruction::kIndexNone:
-    case Instruction::kIndexVtableOffset:
-    case Instruction::kIndexFieldOffset:
-    default:
-      break;
-  }  // switch
-  return false;
-}
-
-/*
- * Get all the types, strings, methods, and fields referred to from bytecode.
- */
-static bool GetIdsFromByteCode(Collections& collections,
-                               const CodeItem* code,
-                               std::vector<TypeId*>* type_ids,
-                               std::vector<StringId*>* string_ids,
-                               std::vector<MethodId*>* method_ids,
-                               std::vector<FieldId*>* field_ids) {
-  bool has_id = false;
-  IterationRange<DexInstructionIterator> instructions = code->Instructions();
-  SafeDexInstructionIterator it(instructions.begin(), instructions.end());
-  for (; !it.IsErrorState() && it < instructions.end(); ++it) {
-    // In case the instruction goes past the end of the code item, make sure to not process it.
-    SafeDexInstructionIterator next = it;
-    ++next;
-    if (next.IsErrorState()) {
-      break;
-    }
-    has_id |= GetIdFromInstruction(collections,
-                                   &it.Inst(),
-                                   type_ids,
-                                   string_ids,
-                                   method_ids,
-                                   field_ids);
-  }  // for
-  return has_id;
-}
-
-EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) {
-  const uint8_t encoded_value = *(*data)++;
-  const uint8_t type = encoded_value & 0x1f;
-  EncodedValue* item = new EncodedValue(type);
-  ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item);
-  return item;
-}
-
-EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file,
-                                            const uint8_t** data,
-                                            uint8_t type,
-                                            uint8_t length) {
-  EncodedValue* item = new EncodedValue(type);
-  ReadEncodedValue(dex_file, data, type, length, item);
-  return item;
-}
-
-void Collections::ReadEncodedValue(const DexFile& dex_file,
-                                   const uint8_t** data,
-                                   uint8_t type,
-                                   uint8_t length,
-                                   EncodedValue* item) {
-  switch (type) {
-    case DexFile::kDexAnnotationByte:
-      item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
-      break;
-    case DexFile::kDexAnnotationShort:
-      item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true)));
-      break;
-    case DexFile::kDexAnnotationChar:
-      item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false)));
-      break;
-    case DexFile::kDexAnnotationInt:
-      item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true)));
-      break;
-    case DexFile::kDexAnnotationLong:
-      item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true)));
-      break;
-    case DexFile::kDexAnnotationFloat: {
-      // Fill on right.
-      union {
-        float f;
-        uint32_t data;
-      } conv;
-      conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
-      item->SetFloat(conv.f);
-      break;
-    }
-    case DexFile::kDexAnnotationDouble: {
-      // Fill on right.
-      union {
-        double d;
-        uint64_t data;
-      } conv;
-      conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
-      item->SetDouble(conv.d);
-      break;
-    }
-    case DexFile::kDexAnnotationMethodType: {
-      const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->SetProtoId(GetProtoId(proto_index));
-      break;
-    }
-    case DexFile::kDexAnnotationMethodHandle: {
-      const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->SetMethodHandle(GetMethodHandle(method_handle_index));
-      break;
-    }
-    case DexFile::kDexAnnotationString: {
-      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->SetStringId(GetStringId(string_index));
-      break;
-    }
-    case DexFile::kDexAnnotationType: {
-      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->SetTypeId(GetTypeId(string_index));
-      break;
-    }
-    case DexFile::kDexAnnotationField:
-    case DexFile::kDexAnnotationEnum: {
-      const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->SetFieldId(GetFieldId(field_index));
-      break;
-    }
-    case DexFile::kDexAnnotationMethod: {
-      const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->SetMethodId(GetMethodId(method_index));
-      break;
-    }
-    case DexFile::kDexAnnotationArray: {
-      EncodedValueVector* values = new EncodedValueVector();
-      const uint32_t offset = *data - dex_file.DataBegin();
-      const uint32_t size = DecodeUnsignedLeb128(data);
-      // Decode all elements.
-      for (uint32_t i = 0; i < size; i++) {
-        values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data)));
-      }
-      EncodedArrayItem* array_item = new EncodedArrayItem(values);
-      if (eagerly_assign_offsets_) {
-        array_item->SetOffset(offset);
-      }
-      item->SetEncodedArray(array_item);
-      break;
-    }
-    case DexFile::kDexAnnotationAnnotation: {
-      AnnotationElementVector* elements = new AnnotationElementVector();
-      const uint32_t type_idx = DecodeUnsignedLeb128(data);
-      const uint32_t size = DecodeUnsignedLeb128(data);
-      // Decode all name=value pairs.
-      for (uint32_t i = 0; i < size; i++) {
-        const uint32_t name_index = DecodeUnsignedLeb128(data);
-        elements->push_back(std::unique_ptr<AnnotationElement>(
-            new AnnotationElement(GetStringId(name_index), ReadEncodedValue(dex_file, data))));
-      }
-      item->SetEncodedAnnotation(new EncodedAnnotation(GetTypeId(type_idx), elements));
-      break;
-    }
-    case DexFile::kDexAnnotationNull:
-      break;
-    case DexFile::kDexAnnotationBoolean:
-      item->SetBoolean(length != 0);
-      break;
-    default:
-      break;
-  }
-}
-
-void Collections::CreateStringId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
-  StringData* string_data = CreateAndAddItem(string_datas_map_,
-                                             string_datas_,
-                                             disk_string_id.string_data_off_,
-                                             dex_file.GetStringData(disk_string_id));
-  CreateAndAddIndexedItem(string_ids_,
-                          StringIdsOffset() + i * StringId::ItemSize(),
-                          i,
-                          string_data);
-}
-
-void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
-  CreateAndAddIndexedItem(type_ids_,
-                          TypeIdsOffset() + i * TypeId::ItemSize(),
-                          i,
-                          GetStringId(disk_type_id.descriptor_idx_.index_));
-}
-
-void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i));
-  const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
-  TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
-
-  CreateAndAddIndexedItem(proto_ids_,
-                          ProtoIdsOffset() + i * ProtoId::ItemSize(),
-                          i,
-                          GetStringId(disk_proto_id.shorty_idx_.index_),
-                          GetTypeId(disk_proto_id.return_type_idx_.index_),
-                          parameter_type_list);
-}
-
-void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
-  CreateAndAddIndexedItem(field_ids_,
-                          FieldIdsOffset() + i * FieldId::ItemSize(),
-                          i,
-                          GetTypeId(disk_field_id.class_idx_.index_),
-                          GetTypeId(disk_field_id.type_idx_.index_),
-                          GetStringId(disk_field_id.name_idx_.index_));
-}
-
-void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
-  CreateAndAddIndexedItem(method_ids_,
-                          MethodIdsOffset() + i * MethodId::ItemSize(),
-                          i,
-                          GetTypeId(disk_method_id.class_idx_.index_),
-                          GetProtoId(disk_method_id.proto_idx_.index_),
-                          GetStringId(disk_method_id.name_idx_.index_));
-}
-
-void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
-  const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
-  const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
-  uint32_t access_flags = disk_class_def.access_flags_;
-  const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
-
-  const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
-  TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
-
-  const StringId* source_file = GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_);
-  // Annotations.
-  AnnotationsDirectoryItem* annotations = nullptr;
-  const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
-      dex_file.GetAnnotationsDirectory(disk_class_def);
-  if (disk_annotations_directory_item != nullptr) {
-    annotations = CreateAnnotationsDirectoryItem(
-        dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_);
-  }
-  // Static field initializers.
-  const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
-  EncodedArrayItem* static_values =
-      CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_);
-  ClassData* class_data = CreateClassData(
-      dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
-  CreateAndAddIndexedItem(class_defs_,
-                          ClassDefsOffset() + i * ClassDef::ItemSize(),
-                          i,
-                          class_type,
-                          access_flags,
-                          superclass,
-                          interfaces_type_list,
-                          source_file,
-                          annotations,
-                          static_values,
-                          class_data);
-}
-
-TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
-  if (dex_type_list == nullptr) {
-    return nullptr;
-  }
-  TypeList* type_list = type_lists_map_.GetExistingObject(offset);
-  if (type_list == nullptr) {
-    TypeIdVector* type_vector = new TypeIdVector();
-    uint32_t size = dex_type_list->Size();
-    for (uint32_t index = 0; index < size; ++index) {
-      type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
-    }
-    type_list = CreateAndAddItem(type_lists_map_, type_lists_, offset, type_vector);
-  }
-  return type_list;
-}
-
-EncodedArrayItem* Collections::CreateEncodedArrayItem(const DexFile& dex_file,
-                                                      const uint8_t* static_data,
-                                                      uint32_t offset) {
-  if (static_data == nullptr) {
-    return nullptr;
-  }
-  EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset);
-  if (encoded_array_item == nullptr) {
-    uint32_t size = DecodeUnsignedLeb128(&static_data);
-    EncodedValueVector* values = new EncodedValueVector();
-    for (uint32_t i = 0; i < size; ++i) {
-      values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data)));
-    }
-    // TODO: Calculate the size of the encoded array.
-    encoded_array_item = CreateAndAddItem(encoded_array_items_map_,
-                                          encoded_array_items_,
-                                          offset,
-                                          values);
-  }
-  return encoded_array_item;
-}
-
-void Collections::AddAnnotationsFromMapListSection(const DexFile& dex_file,
-                                                   uint32_t start_offset,
-                                                   uint32_t count) {
-  uint32_t current_offset = start_offset;
-  for (size_t i = 0; i < count; ++i) {
-    // Annotation that we didn't process already, add it to the set.
-    const DexFile::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset);
-    AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
-    DCHECK(annotation_item != nullptr);
-    current_offset += annotation_item->GetSize();
-  }
-}
-
-AnnotationItem* Collections::CreateAnnotationItem(const DexFile& dex_file,
-                                                  const DexFile::AnnotationItem* annotation) {
-  const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
-  const uint32_t offset = start_data - dex_file.DataBegin();
-  AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
-  if (annotation_item == nullptr) {
-    uint8_t visibility = annotation->visibility_;
-    const uint8_t* annotation_data = annotation->annotation_;
-    std::unique_ptr<EncodedValue> encoded_value(
-        ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0));
-    annotation_item = CreateAndAddItem(annotation_items_map_,
-                                       annotation_items_,
-                                       offset,
-                                       visibility,
-                                       encoded_value->ReleaseEncodedAnnotation());
-    annotation_item->SetSize(annotation_data - start_data);
-  }
-  return annotation_item;
-}
-
-
-AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
-    const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
-  if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
-    return nullptr;
-  }
-  AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset);
-  if (annotation_set_item == nullptr) {
-    std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
-    for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
-      const DexFile::AnnotationItem* annotation =
-          dex_file.GetAnnotationItem(disk_annotations_item, i);
-      if (annotation == nullptr) {
-        continue;
-      }
-      AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
-      items->push_back(annotation_item);
-    }
-    annotation_set_item = CreateAndAddItem(annotation_set_items_map_,
-                                           annotation_set_items_,
-                                           offset,
-                                           items);
-  }
-  return annotation_set_item;
-}
-
-AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
-    const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
-  AnnotationsDirectoryItem* annotations_directory_item =
-      annotations_directory_items_map_.GetExistingObject(offset);
-  if (annotations_directory_item != nullptr) {
-    return annotations_directory_item;
-  }
-  const DexFile::AnnotationSetItem* class_set_item =
-      dex_file.GetClassAnnotationSet(disk_annotations_item);
-  AnnotationSetItem* class_annotation = nullptr;
-  if (class_set_item != nullptr) {
-    uint32_t item_offset = disk_annotations_item->class_annotations_off_;
-    class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset);
-  }
-  const DexFile::FieldAnnotationsItem* fields =
-      dex_file.GetFieldAnnotations(disk_annotations_item);
-  FieldAnnotationVector* field_annotations = nullptr;
-  if (fields != nullptr) {
-    field_annotations = new FieldAnnotationVector();
-    for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
-      FieldId* field_id = GetFieldId(fields[i].field_idx_);
-      const DexFile::AnnotationSetItem* field_set_item =
-          dex_file.GetFieldAnnotationSetItem(fields[i]);
-      uint32_t annotation_set_offset = fields[i].annotations_off_;
-      AnnotationSetItem* annotation_set_item =
-          CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
-      field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
-          new FieldAnnotation(field_id, annotation_set_item)));
-    }
-  }
-  const DexFile::MethodAnnotationsItem* methods =
-      dex_file.GetMethodAnnotations(disk_annotations_item);
-  MethodAnnotationVector* method_annotations = nullptr;
-  if (methods != nullptr) {
-    method_annotations = new MethodAnnotationVector();
-    for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
-      MethodId* method_id = GetMethodId(methods[i].method_idx_);
-      const DexFile::AnnotationSetItem* method_set_item =
-          dex_file.GetMethodAnnotationSetItem(methods[i]);
-      uint32_t annotation_set_offset = methods[i].annotations_off_;
-      AnnotationSetItem* annotation_set_item =
-          CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
-      method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
-          new MethodAnnotation(method_id, annotation_set_item)));
-    }
-  }
-  const DexFile::ParameterAnnotationsItem* parameters =
-      dex_file.GetParameterAnnotations(disk_annotations_item);
-  ParameterAnnotationVector* parameter_annotations = nullptr;
-  if (parameters != nullptr) {
-    parameter_annotations = new ParameterAnnotationVector();
-    for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
-      MethodId* method_id = GetMethodId(parameters[i].method_idx_);
-      const DexFile::AnnotationSetRefList* list =
-          dex_file.GetParameterAnnotationSetRefList(&parameters[i]);
-      parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
-          GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_)));
-    }
-  }
-  // TODO: Calculate the size of the annotations directory.
-  return CreateAndAddItem(annotations_directory_items_map_,
-                          annotations_directory_items_,
-                          offset,
-                          class_annotation,
-                          field_annotations,
-                          method_annotations,
-                          parameter_annotations);
-}
-
-ParameterAnnotation* Collections::GenerateParameterAnnotation(
-    const DexFile& dex_file, MethodId* method_id,
-    const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
-  AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset);
-  if (set_ref_list == nullptr) {
-    std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
-    for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
-      const DexFile::AnnotationSetItem* annotation_set_item =
-          dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
-      uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
-      annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
-    }
-    set_ref_list = CreateAndAddItem(annotation_set_ref_lists_map_,
-                                    annotation_set_ref_lists_,
-                                    offset,
-                                    annotations);
-  }
-  return new ParameterAnnotation(method_id, set_ref_list);
-}
-
-CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file,
-                                              const DexFile::CodeItem* disk_code_item,
-                                              uint32_t offset,
-                                              uint32_t dex_method_index) {
-  if (disk_code_item == nullptr) {
-    return nullptr;
-  }
-  CodeItemDebugInfoAccessor accessor(dex_file, disk_code_item, dex_method_index);
-  const uint32_t debug_info_offset = accessor.DebugInfoOffset();
-
-  // Create the offsets pair and dedupe based on it.
-  std::pair<uint32_t, uint32_t> offsets_pair(offset, debug_info_offset);
-  auto existing = code_items_map_.find(offsets_pair);
-  if (existing != code_items_map_.end()) {
-    return existing->second;
-  }
-
-  const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset);
-  DebugInfoItem* debug_info = nullptr;
-  if (debug_info_stream != nullptr) {
-    debug_info = debug_info_items_map_.GetExistingObject(debug_info_offset);
-    if (debug_info == nullptr) {
-      uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
-      uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
-      memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
-      debug_info = CreateAndAddItem(debug_info_items_map_,
-                                    debug_info_items_,
-                                    debug_info_offset,
-                                    debug_info_size,
-                                    debug_info_buffer);
-    }
-  }
-
-  uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
-  uint16_t* insns = new uint16_t[insns_size];
-  memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t));
-
-  TryItemVector* tries = nullptr;
-  CatchHandlerVector* handler_list = nullptr;
-  if (accessor.TriesSize() > 0) {
-    tries = new TryItemVector();
-    handler_list = new CatchHandlerVector();
-    for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) {
-      uint32_t start_addr = disk_try_item.start_addr_;
-      uint16_t insn_count = disk_try_item.insn_count_;
-      uint16_t handler_off = disk_try_item.handler_off_;
-      const CatchHandler* handlers = nullptr;
-      for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
-        if (handler_off == existing_handlers->GetListOffset()) {
-          handlers = existing_handlers.get();
-          break;
-        }
-      }
-      if (handlers == nullptr) {
-        bool catch_all = false;
-        TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
-        for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) {
-          const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
-          const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
-          catch_all |= type_id == nullptr;
-          addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
-              new TypeAddrPair(type_id, it.GetHandlerAddress())));
-        }
-        handlers = new CatchHandler(catch_all, handler_off, addr_pairs);
-        handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers));
-      }
-      TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
-      tries->push_back(std::unique_ptr<const TryItem>(try_item));
-    }
-    // Manually walk catch handlers list and add any missing handlers unreferenced by try items.
-    const uint8_t* handlers_base = accessor.GetCatchHandlerData();
-    const uint8_t* handlers_data = handlers_base;
-    uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data);
-    while (handlers_size > handler_list->size()) {
-      bool already_added = false;
-      uint16_t handler_off = handlers_data - handlers_base;
-      for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
-        if (handler_off == existing_handlers->GetListOffset()) {
-          already_added = true;
-          break;
-        }
-      }
-      int32_t size = DecodeSignedLeb128(&handlers_data);
-      bool has_catch_all = size <= 0;
-      if (has_catch_all) {
-        size = -size;
-      }
-      if (already_added) {
-        for (int32_t i = 0; i < size; i++) {
-          DecodeUnsignedLeb128(&handlers_data);
-          DecodeUnsignedLeb128(&handlers_data);
-        }
-        if (has_catch_all) {
-          DecodeUnsignedLeb128(&handlers_data);
-        }
-        continue;
-      }
-      TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
-      for (int32_t i = 0; i < size; i++) {
-        const TypeId* type_id = GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data));
-        uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
-        addr_pairs->push_back(
-            std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr)));
-      }
-      if (has_catch_all) {
-        uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
-        addr_pairs->push_back(
-            std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr)));
-      }
-      const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs);
-      handler_list->push_back(std::unique_ptr<const CatchHandler>(handler));
-    }
-  }
-
-  uint32_t size = dex_file.GetCodeItemSize(*disk_code_item);
-  CodeItem* code_item = code_items_.CreateAndAddItem(accessor.RegistersSize(),
-                                                     accessor.InsSize(),
-                                                     accessor.OutsSize(),
-                                                     debug_info,
-                                                     insns_size,
-                                                     insns,
-                                                     tries,
-                                                     handler_list);
-  code_item->SetSize(size);
-
-  // Add the code item to the map.
-  DCHECK(!code_item->OffsetAssigned());
-  if (eagerly_assign_offsets_) {
-    code_item->SetOffset(offset);
-  }
-  code_items_map_.emplace(offsets_pair, code_item);
-
-  // Add "fixup" references to types, strings, methods, and fields.
-  // This is temporary, as we will probably want more detailed parsing of the
-  // instructions here.
-  std::vector<TypeId*> type_ids;
-  std::vector<StringId*> string_ids;
-  std::vector<MethodId*> method_ids;
-  std::vector<FieldId*> field_ids;
-  if (GetIdsFromByteCode(*this,
-                         code_item,
-                         /*out*/ &type_ids,
-                         /*out*/ &string_ids,
-                         /*out*/ &method_ids,
-                         /*out*/ &field_ids)) {
-    CodeFixups* fixups = new CodeFixups(std::move(type_ids),
-                                        std::move(string_ids),
-                                        std::move(method_ids),
-                                        std::move(field_ids));
-    code_item->SetCodeFixups(fixups);
-  }
-
-  return code_item;
-}
-
-MethodItem Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
-  MethodId* method_id = GetMethodId(cdii.GetMemberIndex());
-  uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-  const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
-  // Temporary hack to prevent incorrectly deduping code items if they have the same offset since
-  // they may have different debug info streams.
-  CodeItem* code_item = DedupeOrCreateCodeItem(dex_file,
-                                               disk_code_item,
-                                               cdii.GetMethodCodeItemOffset(),
-                                               cdii.GetMemberIndex());
-  return MethodItem(access_flags, method_id, code_item);
-}
-
-ClassData* Collections::CreateClassData(
-    const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
-  // Read the fields and methods defined by the class, resolving the circular reference from those
-  // to classes by setting class at the same time.
-  ClassData* class_data = class_datas_map_.GetExistingObject(offset);
-  if (class_data == nullptr && encoded_data != nullptr) {
-    ClassDataItemIterator cdii(dex_file, encoded_data);
-    // Static fields.
-    FieldItemVector* static_fields = new FieldItemVector();
-    for (; cdii.HasNextStaticField(); cdii.Next()) {
-      FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
-      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-      static_fields->emplace_back(access_flags, field_item);
-    }
-    // Instance fields.
-    FieldItemVector* instance_fields = new FieldItemVector();
-    for (; cdii.HasNextInstanceField(); cdii.Next()) {
-      FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
-      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-      instance_fields->emplace_back(access_flags, field_item);
-    }
-    // Direct methods.
-    MethodItemVector* direct_methods = new MethodItemVector();
-    for (; cdii.HasNextDirectMethod(); cdii.Next()) {
-      direct_methods->push_back(GenerateMethodItem(dex_file, cdii));
-    }
-    // Virtual methods.
-    MethodItemVector* virtual_methods = new MethodItemVector();
-    for (; cdii.HasNextVirtualMethod(); cdii.Next()) {
-      virtual_methods->push_back(GenerateMethodItem(dex_file, cdii));
-    }
-    class_data = CreateAndAddItem(class_datas_map_,
-                                  class_datas_,
-                                  offset,
-                                  static_fields,
-                                  instance_fields,
-                                  direct_methods,
-                                  virtual_methods);
-    class_data->SetSize(cdii.EndDataPointer() - encoded_data);
-  }
-  return class_data;
-}
-
-void Collections::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
-  // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
-  const DexFile::MapList* map = dex_file.GetMapList();
-  for (uint32_t i = 0; i < map->size_; ++i) {
-    const DexFile::MapItem* item = map->list_ + i;
-    switch (item->type_) {
-      case DexFile::kDexTypeCallSiteIdItem:
-        SetCallSiteIdsOffset(item->offset_);
-        break;
-      case DexFile::kDexTypeMethodHandleItem:
-        SetMethodHandleItemsOffset(item->offset_);
-        break;
-      default:
-        break;
-    }
-  }
-  // Populate MethodHandleItems first (CallSiteIds may depend on them).
-  for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) {
-    CreateMethodHandleItem(dex_file, i);
-  }
-  // Populate CallSiteIds.
-  for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) {
-    CreateCallSiteId(dex_file, i);
-  }
-}
-
-void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
-  const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_;
-  EncodedArrayItem* call_site_item =
-      CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
-
-  CreateAndAddIndexedItem(call_site_ids_,
-                          CallSiteIdsOffset() + i * CallSiteId::ItemSize(),
-                          i,
-                          call_site_item);
-}
-
-void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
-  const DexFile::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i);
-  uint16_t index = disk_method_handle.field_or_method_idx_;
-  DexFile::MethodHandleType type =
-      static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
-  bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
-                   type == DexFile::MethodHandleType::kInvokeInstance ||
-                   type == DexFile::MethodHandleType::kInvokeConstructor ||
-                   type == DexFile::MethodHandleType::kInvokeDirect ||
-                   type == DexFile::MethodHandleType::kInvokeInterface;
-  static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface,
-                "Unexpected method handle types.");
-  IndexedItem* field_or_method_id;
-  if (is_invoke) {
-    field_or_method_id = GetMethodId(index);
-  } else {
-    field_or_method_id = GetFieldId(index);
-  }
-  CreateAndAddIndexedItem(method_handle_items_,
-                          MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(),
-                          i,
-                          type,
-                          field_or_method_id);
-}
-
-void Collections::SortVectorsByMapOrder() {
-  string_datas_.SortByMapOrder(string_datas_map_.Collection());
-  type_lists_.SortByMapOrder(type_lists_map_.Collection());
-  encoded_array_items_.SortByMapOrder(encoded_array_items_map_.Collection());
-  annotation_items_.SortByMapOrder(annotation_items_map_.Collection());
-  annotation_set_items_.SortByMapOrder(annotation_set_items_map_.Collection());
-  annotation_set_ref_lists_.SortByMapOrder(annotation_set_ref_lists_map_.Collection());
-  annotations_directory_items_.SortByMapOrder(annotations_directory_items_map_.Collection());
-  debug_info_items_.SortByMapOrder(debug_info_items_map_.Collection());
-  code_items_.SortByMapOrder(code_items_map_);
-  class_datas_.SortByMapOrder(class_datas_map_.Collection());
-}
-
-void Collections::ClearMaps() {
-  string_datas_map_.Collection().clear();
-  type_lists_map_.Collection().clear();
-  encoded_array_items_map_.Collection().clear();
-  annotation_items_map_.Collection().clear();
-  annotation_set_items_map_.Collection().clear();
-  annotation_set_ref_lists_map_.Collection().clear();
-  annotations_directory_items_map_.Collection().clear();
-  debug_info_items_map_.Collection().clear();
-  code_items_map_.clear();
-  class_datas_map_.Collection().clear();
-}
-
-static uint32_t HeaderOffset(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
+static uint32_t HeaderOffset(const dex_ir::Header* header ATTRIBUTE_UNUSED) {
   return 0;
 }
 
-static uint32_t HeaderSize(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
+static uint32_t HeaderSize(const dex_ir::Header* header ATTRIBUTE_UNUSED) {
   // Size is in elements, so there is only one header.
   return 1;
 }
@@ -907,9 +45,9 @@
   std::string name;
   uint16_t type;
   // A function that when applied to a collection object, gives the size of the section.
-  std::function<uint32_t(const dex_ir::Collections&)> size_fn;
+  std::function<uint32_t(dex_ir::Header*)> size_fn;
   // A function that when applied to a collection object, gives the offset of the section.
-  std::function<uint32_t(const dex_ir::Collections&)> offset_fn;
+  std::function<uint32_t(dex_ir::Header*)> offset_fn;
 };
 
 static const FileSectionDescriptor kFileSectionDescriptors[] = {
@@ -921,106 +59,105 @@
   }, {
     "StringId",
     DexFile::kDexTypeStringIdItem,
-    &dex_ir::Collections::StringIdsSize,
-    &dex_ir::Collections::StringIdsOffset
+    [](const dex_ir::Header* h) { return h->StringIds().Size(); },
+    [](const dex_ir::Header* h) { return h->StringIds().GetOffset(); }
   }, {
     "TypeId",
     DexFile::kDexTypeTypeIdItem,
-    &dex_ir::Collections::TypeIdsSize,
-    &dex_ir::Collections::TypeIdsOffset
+    [](const dex_ir::Header* h) { return h->TypeIds().Size(); },
+    [](const dex_ir::Header* h) { return h->TypeIds().GetOffset(); }
   }, {
     "ProtoId",
     DexFile::kDexTypeProtoIdItem,
-    &dex_ir::Collections::ProtoIdsSize,
-    &dex_ir::Collections::ProtoIdsOffset
+    [](const dex_ir::Header* h) { return h->ProtoIds().Size(); },
+    [](const dex_ir::Header* h) { return h->ProtoIds().GetOffset(); }
   }, {
     "FieldId",
     DexFile::kDexTypeFieldIdItem,
-    &dex_ir::Collections::FieldIdsSize,
-    &dex_ir::Collections::FieldIdsOffset
+    [](const dex_ir::Header* h) { return h->FieldIds().Size(); },
+    [](const dex_ir::Header* h) { return h->FieldIds().GetOffset(); }
   }, {
     "MethodId",
     DexFile::kDexTypeMethodIdItem,
-    &dex_ir::Collections::MethodIdsSize,
-    &dex_ir::Collections::MethodIdsOffset
+    [](const dex_ir::Header* h) { return h->MethodIds().Size(); },
+    [](const dex_ir::Header* h) { return h->MethodIds().GetOffset(); }
   }, {
     "ClassDef",
     DexFile::kDexTypeClassDefItem,
-    &dex_ir::Collections::ClassDefsSize,
-    &dex_ir::Collections::ClassDefsOffset
+    [](const dex_ir::Header* h) { return h->ClassDefs().Size(); },
+    [](const dex_ir::Header* h) { return h->ClassDefs().GetOffset(); }
   }, {
     "CallSiteId",
     DexFile::kDexTypeCallSiteIdItem,
-    &dex_ir::Collections::CallSiteIdsSize,
-    &dex_ir::Collections::CallSiteIdsOffset
+    [](const dex_ir::Header* h) { return h->CallSiteIds().Size(); },
+    [](const dex_ir::Header* h) { return h->CallSiteIds().GetOffset(); }
   }, {
     "MethodHandle",
     DexFile::kDexTypeMethodHandleItem,
-    &dex_ir::Collections::MethodHandleItemsSize,
-    &dex_ir::Collections::MethodHandleItemsOffset
+    [](const dex_ir::Header* h) { return h->MethodHandleItems().Size(); },
+    [](const dex_ir::Header* h) { return h->MethodHandleItems().GetOffset(); }
   }, {
     "StringData",
     DexFile::kDexTypeStringDataItem,
-    &dex_ir::Collections::StringDatasSize,
-    &dex_ir::Collections::StringDatasOffset
+    [](const dex_ir::Header* h) { return h->StringDatas().Size(); },
+    [](const dex_ir::Header* h) { return h->StringDatas().GetOffset(); }
   }, {
     "TypeList",
     DexFile::kDexTypeTypeList,
-    &dex_ir::Collections::TypeListsSize,
-    &dex_ir::Collections::TypeListsOffset
+    [](const dex_ir::Header* h) { return h->TypeLists().Size(); },
+    [](const dex_ir::Header* h) { return h->TypeLists().GetOffset(); }
   }, {
     "EncArr",
     DexFile::kDexTypeEncodedArrayItem,
-    &dex_ir::Collections::EncodedArrayItemsSize,
-    &dex_ir::Collections::EncodedArrayItemsOffset
+    [](const dex_ir::Header* h) { return h->EncodedArrayItems().Size(); },
+    [](const dex_ir::Header* h) { return h->EncodedArrayItems().GetOffset(); }
   }, {
     "Annotation",
     DexFile::kDexTypeAnnotationItem,
-    &dex_ir::Collections::AnnotationItemsSize,
-    &dex_ir::Collections::AnnotationItemsOffset
+    [](const dex_ir::Header* h) { return h->AnnotationItems().Size(); },
+    [](const dex_ir::Header* h) { return h->AnnotationItems().GetOffset(); }
   }, {
     "AnnoSet",
     DexFile::kDexTypeAnnotationSetItem,
-    &dex_ir::Collections::AnnotationSetItemsSize,
-    &dex_ir::Collections::AnnotationSetItemsOffset
+    [](const dex_ir::Header* h) { return h->AnnotationSetItems().Size(); },
+    [](const dex_ir::Header* h) { return h->AnnotationSetItems().GetOffset(); }
   }, {
     "AnnoSetRL",
     DexFile::kDexTypeAnnotationSetRefList,
-    &dex_ir::Collections::AnnotationSetRefListsSize,
-    &dex_ir::Collections::AnnotationSetRefListsOffset
+    [](const dex_ir::Header* h) { return h->AnnotationSetRefLists().Size(); },
+    [](const dex_ir::Header* h) { return h->AnnotationSetRefLists().GetOffset(); }
   }, {
     "AnnoDir",
     DexFile::kDexTypeAnnotationsDirectoryItem,
-    &dex_ir::Collections::AnnotationsDirectoryItemsSize,
-    &dex_ir::Collections::AnnotationsDirectoryItemsOffset
+    [](const dex_ir::Header* h) { return h->AnnotationsDirectoryItems().Size(); },
+    [](const dex_ir::Header* h) { return h->AnnotationsDirectoryItems().GetOffset(); }
   }, {
     "DebugInfo",
     DexFile::kDexTypeDebugInfoItem,
-    &dex_ir::Collections::DebugInfoItemsSize,
-    &dex_ir::Collections::DebugInfoItemsOffset
+    [](const dex_ir::Header* h) { return h->DebugInfoItems().Size(); },
+    [](const dex_ir::Header* h) { return h->DebugInfoItems().GetOffset(); }
   }, {
     "CodeItem",
     DexFile::kDexTypeCodeItem,
-    &dex_ir::Collections::CodeItemsSize,
-    &dex_ir::Collections::CodeItemsOffset
+    [](const dex_ir::Header* h) { return h->CodeItems().Size(); },
+    [](const dex_ir::Header* h) { return h->CodeItems().GetOffset(); }
   }, {
     "ClassData",
     DexFile::kDexTypeClassDataItem,
-    &dex_ir::Collections::ClassDatasSize,
-    &dex_ir::Collections::ClassDatasOffset
+    [](const dex_ir::Header* h) { return h->ClassDatas().Size(); },
+    [](const dex_ir::Header* h) { return h->ClassDatas().GetOffset(); }
   }
 };
 
 std::vector<dex_ir::DexFileSection> GetSortedDexFileSections(dex_ir::Header* header,
                                                              dex_ir::SortDirection direction) {
-  const dex_ir::Collections& collections = header->GetCollections();
   std::vector<dex_ir::DexFileSection> sorted_sections;
   // Build the table that will map from offset to color
   for (const FileSectionDescriptor& s : kFileSectionDescriptors) {
     sorted_sections.push_back(dex_ir::DexFileSection(s.name,
                                                      s.type,
-                                                     s.size_fn(collections),
-                                                     s.offset_fn(collections)));
+                                                     s.size_fn(header),
+                                                     s.offset_fn(header)));
   }
   // Sort by offset.
   std::sort(sorted_sections.begin(),
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 54ff105..9f355ba 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -24,6 +24,7 @@
 #include <map>
 #include <vector>
 
+#include "base/iteration_range.h"
 #include "base/leb128.h"
 #include "base/stl_util.h"
 #include "dex/dex_file-inl.h"
@@ -107,17 +108,114 @@
   DISALLOW_COPY_AND_ASSIGN(AbstractDispatcher);
 };
 
+template<class T> class Iterator : public std::iterator<std::random_access_iterator_tag, T> {
+ public:
+  using value_type = typename std::iterator<std::random_access_iterator_tag, T>::value_type;
+  using difference_type =
+      typename std::iterator<std::random_access_iterator_tag, value_type>::difference_type;
+  using pointer = typename std::iterator<std::random_access_iterator_tag, value_type>::pointer;
+  using reference = typename std::iterator<std::random_access_iterator_tag, value_type>::reference;
+
+  Iterator(const Iterator&) = default;
+  Iterator(Iterator&&) = default;
+  Iterator& operator=(const Iterator&) = default;
+  Iterator& operator=(Iterator&&) = default;
+
+  Iterator(const std::vector<T>& vector,
+           uint32_t position,
+           uint32_t iterator_end)
+      : vector_(&vector),
+        position_(position),
+        iterator_end_(iterator_end) { }
+  Iterator() : vector_(nullptr), position_(0U), iterator_end_(0U) { }
+
+  bool IsValid() const { return position_ < iterator_end_; }
+
+  bool operator==(const Iterator& rhs) const { return position_ == rhs.position_; }
+  bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
+  bool operator<(const Iterator& rhs) const { return position_ < rhs.position_; }
+  bool operator>(const Iterator& rhs) const { return rhs < *this; }
+  bool operator<=(const Iterator& rhs) const { return !(rhs < *this); }
+  bool operator>=(const Iterator& rhs) const { return !(*this < rhs); }
+
+  Iterator& operator++() {  // Value after modification.
+    ++position_;
+    return *this;
+  }
+
+  Iterator operator++(int) {
+    Iterator temp = *this;
+    ++position_;
+    return temp;
+  }
+
+  Iterator& operator+=(difference_type delta) {
+    position_ += delta;
+    return *this;
+  }
+
+  Iterator operator+(difference_type delta) const {
+    Iterator temp = *this;
+    temp += delta;
+    return temp;
+  }
+
+  Iterator& operator--() {  // Value after modification.
+    --position_;
+    return *this;
+  }
+
+  Iterator operator--(int) {
+    Iterator temp = *this;
+    --position_;
+    return temp;
+  }
+
+  Iterator& operator-=(difference_type delta) {
+    position_ -= delta;
+    return *this;
+  }
+
+  Iterator operator-(difference_type delta) const {
+    Iterator temp = *this;
+    temp -= delta;
+    return temp;
+  }
+
+  difference_type operator-(const Iterator& rhs) {
+    return position_ - rhs.position_;
+  }
+
+  reference operator*() const {
+    return const_cast<reference>((*vector_)[position_]);
+  }
+
+  pointer operator->() const {
+    return const_cast<pointer>(&((*vector_)[position_]));
+  }
+
+  reference operator[](difference_type n) const {
+    return (*vector_)[position_ + n];
+  }
+
+ private:
+  const std::vector<T>* vector_;
+  uint32_t position_;
+  uint32_t iterator_end_;
+
+  template <typename U>
+  friend bool operator<(const Iterator<U>& lhs, const Iterator<U>& rhs);
+};
+
 // Collections become owners of the objects added by moving them into unique pointers.
-template<class T> class CollectionBase {
+class CollectionBase {
  public:
   CollectionBase() = default;
+  virtual ~CollectionBase() { }
 
-  uint32_t GetOffset() const {
-    return offset_;
-  }
-  void SetOffset(uint32_t new_offset) {
-    offset_ = new_offset;
-  }
+  uint32_t GetOffset() const { return offset_; }
+  void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+  virtual uint32_t Size() const { return 0U; }
 
  private:
   // Start out unassigned.
@@ -126,18 +224,37 @@
   DISALLOW_COPY_AND_ASSIGN(CollectionBase);
 };
 
-template<class T> class CollectionVector : public CollectionBase<T> {
+template<class T> class CollectionVector : public CollectionBase {
  public:
-  using Vector = std::vector<std::unique_ptr<T>>;
+  using ElementType = std::unique_ptr<T>;
+
   CollectionVector() { }
   explicit CollectionVector(size_t size) {
     // Preallocate so that assignment does not invalidate pointers into the vector.
     collection_.reserve(size);
   }
+  virtual ~CollectionVector() OVERRIDE { }
 
-  uint32_t Size() const { return collection_.size(); }
-  Vector& Collection() { return collection_; }
-  const Vector& Collection() const { return collection_; }
+  template<class... Args>
+  T* CreateAndAddItem(Args&&... args) {
+    T* object = new T(std::forward<Args>(args)...);
+    collection_.push_back(std::unique_ptr<T>(object));
+    return object;
+  }
+
+  virtual uint32_t Size() const OVERRIDE { return collection_.size(); }
+
+  Iterator<ElementType> begin() const { return Iterator<ElementType>(collection_, 0U, Size()); }
+  Iterator<ElementType> end() const { return Iterator<ElementType>(collection_, Size(), Size()); }
+
+  const ElementType& operator[](size_t index) const {
+    DCHECK_LT(index, Size());
+    return collection_[index];
+  }
+  ElementType& operator[](size_t index) {
+    DCHECK_LT(index, Size());
+    return collection_[index];
+  }
 
   // Sort the vector by copying pointers over.
   template <typename MapType>
@@ -147,24 +264,16 @@
     for (size_t i = 0; i < Size(); ++i) {
       // There are times when the array will temporarily contain the same pointer twice, doing the
       // release here sure there is no double free errors.
-      Collection()[i].release();
-      Collection()[i].reset(it->second);
+      collection_[i].release();
+      collection_[i].reset(it->second);
       ++it;
     }
   }
 
  protected:
-  Vector collection_;
-
-  template<class... Args>
-  T* CreateAndAddItem(Args&&... args) {
-    T* object = new T(std::forward<Args>(args)...);
-    collection_.push_back(std::unique_ptr<T>(object));
-    return object;
-  }
+  std::vector<ElementType> collection_;
 
  private:
-  friend class Collections;
   DISALLOW_COPY_AND_ASSIGN(CollectionVector);
 };
 
@@ -174,7 +283,6 @@
   IndexedCollectionVector() = default;
   explicit IndexedCollectionVector(size_t size) : CollectionVector<T>(size) { }
 
- private:
   template <class... Args>
   T* CreateAndAddIndexedItem(uint32_t index, Args&&... args) {
     T* object = CollectionVector<T>::CreateAndAddItem(std::forward<Args>(args)...);
@@ -182,332 +290,15 @@
     return object;
   }
 
-  T* GetElement(uint32_t index) {
-    DCHECK_LT(index, CollectionVector<T>::Size());
+  T* operator[](size_t index) const {
     DCHECK_NE(CollectionVector<T>::collection_[index].get(), static_cast<T*>(nullptr));
     return CollectionVector<T>::collection_[index].get();
   }
 
-  friend class Collections;
+ private:
   DISALLOW_COPY_AND_ASSIGN(IndexedCollectionVector);
 };
 
-template<class T> class CollectionMap : public CollectionBase<T> {
- public:
-  CollectionMap() = default;
-
-  // Returns the existing item if it is already inserted, null otherwise.
-  T* GetExistingObject(uint32_t offset) {
-    auto it = collection_.find(offset);
-    return it != collection_.end() ? it->second : nullptr;
-  }
-
-  // Lower case for template interop with std::map.
-  uint32_t size() const { return collection_.size(); }
-  std::map<uint32_t, T*>& Collection() { return collection_; }
-
- private:
-  std::map<uint32_t, T*> collection_;
-
-  // CollectionMaps do not own the objects they contain, therefore AddItem is supported
-  // rather than CreateAndAddItem.
-  void AddItem(T* object, uint32_t offset) {
-    auto it = collection_.emplace(offset, object);
-    CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
-                     << " and address " << it.first->second;
-  }
-
-  friend class Collections;
-  DISALLOW_COPY_AND_ASSIGN(CollectionMap);
-};
-
-class Collections {
- public:
-  Collections() = default;
-  Collections(uint32_t num_string_ids,
-              uint32_t num_type_ids,
-              uint32_t num_proto_ids,
-              uint32_t num_field_ids,
-              uint32_t num_method_ids,
-              uint32_t num_class_defs)
-      : string_ids_(num_string_ids),
-        type_ids_(num_type_ids),
-        proto_ids_(num_proto_ids),
-        field_ids_(num_field_ids),
-        method_ids_(num_method_ids),
-        class_defs_(num_class_defs) { }
-
-  IndexedCollectionVector<StringId>::Vector& StringIds() { return string_ids_.Collection(); }
-  IndexedCollectionVector<TypeId>::Vector& TypeIds() { return type_ids_.Collection(); }
-  IndexedCollectionVector<ProtoId>::Vector& ProtoIds() { return proto_ids_.Collection(); }
-  IndexedCollectionVector<FieldId>::Vector& FieldIds() { return field_ids_.Collection(); }
-  IndexedCollectionVector<MethodId>::Vector& MethodIds() { return method_ids_.Collection(); }
-  IndexedCollectionVector<ClassDef>::Vector& ClassDefs() { return class_defs_.Collection(); }
-  CollectionVector<CallSiteId>::Vector& CallSiteIds() { return call_site_ids_.Collection(); }
-  CollectionVector<MethodHandleItem>::Vector& MethodHandleItems()
-      { return method_handle_items_.Collection(); }
-  CollectionVector<StringData>::Vector& StringDatas() { return string_datas_.Collection(); }
-  CollectionVector<TypeList>::Vector& TypeLists() { return type_lists_.Collection(); }
-  CollectionVector<EncodedArrayItem>::Vector& EncodedArrayItems()
-      { return encoded_array_items_.Collection(); }
-  CollectionVector<AnnotationItem>::Vector& AnnotationItems()
-      { return annotation_items_.Collection(); }
-  CollectionVector<AnnotationSetItem>::Vector& AnnotationSetItems()
-      { return annotation_set_items_.Collection(); }
-  CollectionVector<AnnotationSetRefList>::Vector& AnnotationSetRefLists()
-      { return annotation_set_ref_lists_.Collection(); }
-  CollectionVector<AnnotationsDirectoryItem>::Vector& AnnotationsDirectoryItems()
-      { return annotations_directory_items_.Collection(); }
-  CollectionVector<DebugInfoItem>::Vector& DebugInfoItems()
-      { return debug_info_items_.Collection(); }
-  CollectionVector<CodeItem>::Vector& CodeItems() { return code_items_.Collection(); }
-  CollectionVector<ClassData>::Vector& ClassDatas() { return class_datas_.Collection(); }
-
-  const CollectionVector<ClassDef>::Vector& ClassDefs() const { return class_defs_.Collection(); }
-
-  void CreateStringId(const DexFile& dex_file, uint32_t i);
-  void CreateTypeId(const DexFile& dex_file, uint32_t i);
-  void CreateProtoId(const DexFile& dex_file, uint32_t i);
-  void CreateFieldId(const DexFile& dex_file, uint32_t i);
-  void CreateMethodId(const DexFile& dex_file, uint32_t i);
-  void CreateClassDef(const DexFile& dex_file, uint32_t i);
-  void CreateCallSiteId(const DexFile& dex_file, uint32_t i);
-  void CreateMethodHandleItem(const DexFile& dex_file, uint32_t i);
-
-  void CreateCallSitesAndMethodHandles(const DexFile& dex_file);
-
-  TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
-  EncodedArrayItem* CreateEncodedArrayItem(const DexFile& dex_file,
-                                           const uint8_t* static_data,
-                                           uint32_t offset);
-  AnnotationItem* CreateAnnotationItem(const DexFile& dex_file,
-                                       const DexFile::AnnotationItem* annotation);
-  AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
-      const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
-  AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
-      const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
-  CodeItem* DedupeOrCreateCodeItem(const DexFile& dex_file,
-                                   const DexFile::CodeItem* disk_code_item,
-                                   uint32_t offset,
-                                   uint32_t dex_method_index);
-  ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
-  void AddAnnotationsFromMapListSection(const DexFile& dex_file,
-                                        uint32_t start_offset,
-                                        uint32_t count);
-
-  StringId* GetStringId(uint32_t index) {
-    return string_ids_.GetElement(index);
-  }
-  TypeId* GetTypeId(uint32_t index) {
-    return type_ids_.GetElement(index);
-  }
-  ProtoId* GetProtoId(uint32_t index) {
-    return proto_ids_.GetElement(index);
-  }
-  FieldId* GetFieldId(uint32_t index) {
-    return field_ids_.GetElement(index);
-  }
-  MethodId* GetMethodId(uint32_t index) {
-    return method_ids_.GetElement(index);
-  }
-  ClassDef* GetClassDef(uint32_t index) {
-    return class_defs_.GetElement(index);
-  }
-  CallSiteId* GetCallSiteId(uint32_t index) {
-    CHECK_LT(index, CallSiteIdsSize());
-    return CallSiteIds()[index].get();
-  }
-  MethodHandleItem* GetMethodHandle(uint32_t index) {
-    CHECK_LT(index, MethodHandleItemsSize());
-    return MethodHandleItems()[index].get();
-  }
-
-  StringId* GetStringIdOrNullPtr(uint32_t index) {
-    return index == dex::kDexNoIndex ? nullptr : GetStringId(index);
-  }
-  TypeId* GetTypeIdOrNullPtr(uint16_t index) {
-    return index == DexFile::kDexNoIndex16 ? nullptr : GetTypeId(index);
-  }
-
-  uint32_t StringIdsOffset() const { return string_ids_.GetOffset(); }
-  uint32_t TypeIdsOffset() const { return type_ids_.GetOffset(); }
-  uint32_t ProtoIdsOffset() const { return proto_ids_.GetOffset(); }
-  uint32_t FieldIdsOffset() const { return field_ids_.GetOffset(); }
-  uint32_t MethodIdsOffset() const { return method_ids_.GetOffset(); }
-  uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); }
-  uint32_t CallSiteIdsOffset() const { return call_site_ids_.GetOffset(); }
-  uint32_t MethodHandleItemsOffset() const { return method_handle_items_.GetOffset(); }
-  uint32_t StringDatasOffset() const { return string_datas_.GetOffset(); }
-  uint32_t TypeListsOffset() const { return type_lists_.GetOffset(); }
-  uint32_t EncodedArrayItemsOffset() const { return encoded_array_items_.GetOffset(); }
-  uint32_t AnnotationItemsOffset() const { return annotation_items_.GetOffset(); }
-  uint32_t AnnotationSetItemsOffset() const { return annotation_set_items_.GetOffset(); }
-  uint32_t AnnotationSetRefListsOffset() const { return annotation_set_ref_lists_.GetOffset(); }
-  uint32_t AnnotationsDirectoryItemsOffset() const
-      { return annotations_directory_items_.GetOffset(); }
-  uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
-  uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
-  uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
-  uint32_t MapListOffset() const { return map_list_offset_; }
-
-  void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
-  void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
-  void SetProtoIdsOffset(uint32_t new_offset) { proto_ids_.SetOffset(new_offset); }
-  void SetFieldIdsOffset(uint32_t new_offset) { field_ids_.SetOffset(new_offset); }
-  void SetMethodIdsOffset(uint32_t new_offset) { method_ids_.SetOffset(new_offset); }
-  void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); }
-  void SetCallSiteIdsOffset(uint32_t new_offset) { call_site_ids_.SetOffset(new_offset); }
-  void SetMethodHandleItemsOffset(uint32_t new_offset)
-      { method_handle_items_.SetOffset(new_offset); }
-  void SetStringDatasOffset(uint32_t new_offset) { string_datas_.SetOffset(new_offset); }
-  void SetTypeListsOffset(uint32_t new_offset) { type_lists_.SetOffset(new_offset); }
-  void SetEncodedArrayItemsOffset(uint32_t new_offset)
-      { encoded_array_items_.SetOffset(new_offset); }
-  void SetAnnotationItemsOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); }
-  void SetAnnotationSetItemsOffset(uint32_t new_offset)
-      { annotation_set_items_.SetOffset(new_offset); }
-  void SetAnnotationSetRefListsOffset(uint32_t new_offset)
-      { annotation_set_ref_lists_.SetOffset(new_offset); }
-  void SetAnnotationsDirectoryItemsOffset(uint32_t new_offset)
-      { annotations_directory_items_.SetOffset(new_offset); }
-  void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
-  void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
-  void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
-  void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
-
-  uint32_t StringIdsSize() const { return string_ids_.Size(); }
-  uint32_t TypeIdsSize() const { return type_ids_.Size(); }
-  uint32_t ProtoIdsSize() const { return proto_ids_.Size(); }
-  uint32_t FieldIdsSize() const { return field_ids_.Size(); }
-  uint32_t MethodIdsSize() const { return method_ids_.Size(); }
-  uint32_t ClassDefsSize() const { return class_defs_.Size(); }
-  uint32_t CallSiteIdsSize() const { return call_site_ids_.Size(); }
-  uint32_t MethodHandleItemsSize() const { return method_handle_items_.Size(); }
-  uint32_t StringDatasSize() const { return string_datas_.Size(); }
-  uint32_t TypeListsSize() const { return type_lists_.Size(); }
-  uint32_t EncodedArrayItemsSize() const { return encoded_array_items_.Size(); }
-  uint32_t AnnotationItemsSize() const { return annotation_items_.Size(); }
-  uint32_t AnnotationSetItemsSize() const { return annotation_set_items_.Size(); }
-  uint32_t AnnotationSetRefListsSize() const { return annotation_set_ref_lists_.Size(); }
-  uint32_t AnnotationsDirectoryItemsSize() const { return annotations_directory_items_.Size(); }
-  uint32_t DebugInfoItemsSize() const { return debug_info_items_.Size(); }
-  uint32_t CodeItemsSize() const { return code_items_.Size(); }
-  uint32_t ClassDatasSize() const { return class_datas_.Size(); }
-
-  // Sort the vectors buy map order (same order that was used in the input file).
-  void SortVectorsByMapOrder();
-  // Empty the maps, which are only used for IR construction.
-  void ClearMaps();
-
-  template <typename Type, class... Args>
-  Type* CreateAndAddItem(CollectionMap<Type>& map,
-                         CollectionVector<Type>& vector,
-                         uint32_t offset,
-                         Args&&... args) {
-    Type* item = vector.CreateAndAddItem(std::forward<Args>(args)...);
-    DCHECK(!map.GetExistingObject(offset));
-    DCHECK(!item->OffsetAssigned());
-    if (eagerly_assign_offsets_) {
-      item->SetOffset(offset);
-    }
-    map.AddItem(item, offset);
-    return item;
-  }
-
-  template <typename Type, class... Args>
-  Type* CreateAndAddIndexedItem(IndexedCollectionVector<Type>& vector,
-                                uint32_t offset,
-                                uint32_t index,
-                                Args&&... args) {
-    Type* item = vector.CreateAndAddIndexedItem(index, std::forward<Args>(args)...);
-    DCHECK(!item->OffsetAssigned());
-    if (eagerly_assign_offsets_) {
-      item->SetOffset(offset);
-    }
-    return item;
-  }
-
-  void SetEagerlyAssignOffsets(bool eagerly_assign_offsets) {
-    eagerly_assign_offsets_ = eagerly_assign_offsets;
-  }
-
-  void SetLinkData(std::vector<uint8_t>&& link_data) {
-    link_data_ = std::move(link_data);
-  }
-
-  const std::vector<uint8_t>& LinkData() const {
-    return link_data_;
-  }
-
- private:
-  EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data);
-  EncodedValue* ReadEncodedValue(const DexFile& dex_file,
-                                 const uint8_t** data,
-                                 uint8_t type,
-                                 uint8_t length);
-  void ReadEncodedValue(const DexFile& dex_file,
-                        const uint8_t** data,
-                        uint8_t type,
-                        uint8_t length,
-                        EncodedValue* item);
-
-  ParameterAnnotation* GenerateParameterAnnotation(const DexFile& dex_file, MethodId* method_id,
-      const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
-  MethodItem GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
-
-  // Collection vectors own the IR data.
-  IndexedCollectionVector<StringId> string_ids_;
-  IndexedCollectionVector<TypeId> type_ids_;
-  IndexedCollectionVector<ProtoId> proto_ids_;
-  IndexedCollectionVector<FieldId> field_ids_;
-  IndexedCollectionVector<MethodId> method_ids_;
-  IndexedCollectionVector<ClassDef> class_defs_;
-  IndexedCollectionVector<CallSiteId> call_site_ids_;
-  IndexedCollectionVector<MethodHandleItem> method_handle_items_;
-  IndexedCollectionVector<StringData> string_datas_;
-  IndexedCollectionVector<TypeList> type_lists_;
-  IndexedCollectionVector<EncodedArrayItem> encoded_array_items_;
-  IndexedCollectionVector<AnnotationItem> annotation_items_;
-  IndexedCollectionVector<AnnotationSetItem> annotation_set_items_;
-  IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_;
-  IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_;
-  // The order of the vectors controls the layout of the output file by index order, to change the
-  // layout just sort the vector. Note that you may only change the order of the non indexed vectors
-  // below. Indexed vectors are accessed by indices in other places, changing the sorting order will
-  // invalidate the existing indices and is not currently supported.
-  CollectionVector<DebugInfoItem> debug_info_items_;
-  CollectionVector<CodeItem> code_items_;
-  CollectionVector<ClassData> class_datas_;
-
-  // Note that the maps do not have ownership, the vectors do.
-  // TODO: These maps should only be required for building the IR and should be put in a separate
-  // IR builder class.
-  CollectionMap<StringData> string_datas_map_;
-  CollectionMap<TypeList> type_lists_map_;
-  CollectionMap<EncodedArrayItem> encoded_array_items_map_;
-  CollectionMap<AnnotationItem> annotation_items_map_;
-  CollectionMap<AnnotationSetItem> annotation_set_items_map_;
-  CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_map_;
-  CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_map_;
-  CollectionMap<DebugInfoItem> debug_info_items_map_;
-  // Code item maps need to check both the debug info offset and debug info offset, do not use
-  // CollectionMap.
-  // First offset is the code item offset, second is the debug info offset.
-  std::map<std::pair<uint32_t, uint32_t>, CodeItem*> code_items_map_;
-  CollectionMap<ClassData> class_datas_map_;
-
-  uint32_t map_list_offset_ = 0;
-
-  // Link data.
-  std::vector<uint8_t> link_data_;
-
-  // If we eagerly assign offsets during IR building or later after layout. Must be false if
-  // changing the layout is enabled.
-  bool eagerly_assign_offsets_;
-
-  DISALLOW_COPY_AND_ASSIGN(Collections);
-};
-
 class Item {
  public:
   Item() { }
@@ -598,12 +389,12 @@
          uint32_t num_class_defs)
       : Item(0, kHeaderItemSize),
         support_default_methods_(support_default_methods),
-        collections_(num_string_ids,
-                     num_type_ids,
-                     num_proto_ids,
-                     num_field_ids,
-                     num_method_ids,
-                     num_class_defs) {
+        string_ids_(num_string_ids),
+        type_ids_(num_type_ids),
+        proto_ids_(num_proto_ids),
+        field_ids_(num_field_ids),
+        method_ids_(num_method_ids),
+        class_defs_(num_class_defs) {
     ConstructorHelper(magic,
                       checksum,
                       signature,
@@ -641,7 +432,69 @@
   void SetDataSize(uint32_t new_data_size) { data_size_ = new_data_size; }
   void SetDataOffset(uint32_t new_data_offset) { data_offset_ = new_data_offset; }
 
-  Collections& GetCollections() { return collections_; }
+  IndexedCollectionVector<StringId>& StringIds() { return string_ids_; }
+  const IndexedCollectionVector<StringId>& StringIds() const { return string_ids_; }
+  IndexedCollectionVector<TypeId>& TypeIds() { return type_ids_; }
+  const IndexedCollectionVector<TypeId>& TypeIds() const { return type_ids_; }
+  IndexedCollectionVector<ProtoId>& ProtoIds() { return proto_ids_; }
+  const IndexedCollectionVector<ProtoId>& ProtoIds() const { return proto_ids_; }
+  IndexedCollectionVector<FieldId>& FieldIds() { return field_ids_; }
+  const IndexedCollectionVector<FieldId>& FieldIds() const { return field_ids_; }
+  IndexedCollectionVector<MethodId>& MethodIds() { return method_ids_; }
+  const IndexedCollectionVector<MethodId>& MethodIds() const { return method_ids_; }
+  IndexedCollectionVector<ClassDef>& ClassDefs() { return class_defs_; }
+  const IndexedCollectionVector<ClassDef>& ClassDefs() const { return class_defs_; }
+  IndexedCollectionVector<CallSiteId>& CallSiteIds() { return call_site_ids_; }
+  const IndexedCollectionVector<CallSiteId>& CallSiteIds() const { return call_site_ids_; }
+  IndexedCollectionVector<MethodHandleItem>& MethodHandleItems() { return method_handle_items_; }
+  const IndexedCollectionVector<MethodHandleItem>& MethodHandleItems() const {
+    return method_handle_items_;
+  }
+  CollectionVector<StringData>& StringDatas() { return string_datas_; }
+  const CollectionVector<StringData>& StringDatas() const { return string_datas_; }
+  CollectionVector<TypeList>& TypeLists() { return type_lists_; }
+  const CollectionVector<TypeList>& TypeLists() const { return type_lists_; }
+  CollectionVector<EncodedArrayItem>& EncodedArrayItems() { return encoded_array_items_; }
+  const CollectionVector<EncodedArrayItem>& EncodedArrayItems() const {
+    return encoded_array_items_;
+  }
+  CollectionVector<AnnotationItem>& AnnotationItems() { return annotation_items_; }
+  const CollectionVector<AnnotationItem>& AnnotationItems() const { return annotation_items_; }
+  CollectionVector<AnnotationSetItem>& AnnotationSetItems() { return annotation_set_items_; }
+  const CollectionVector<AnnotationSetItem>& AnnotationSetItems() const {
+    return annotation_set_items_;
+  }
+  CollectionVector<AnnotationSetRefList>& AnnotationSetRefLists() {
+    return annotation_set_ref_lists_;
+  }
+  const CollectionVector<AnnotationSetRefList>& AnnotationSetRefLists() const {
+    return annotation_set_ref_lists_;
+  }
+  CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() {
+    return annotations_directory_items_;
+  }
+  const CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() const {
+    return annotations_directory_items_;
+  }
+  CollectionVector<DebugInfoItem>& DebugInfoItems() { return debug_info_items_; }
+  const CollectionVector<DebugInfoItem>& DebugInfoItems() const { return debug_info_items_; }
+  CollectionVector<CodeItem>& CodeItems() { return code_items_; }
+  const CollectionVector<CodeItem>& CodeItems() const { return code_items_; }
+  CollectionVector<ClassData>& ClassDatas() { return class_datas_; }
+  const CollectionVector<ClassData>& ClassDatas() const { return class_datas_; }
+
+  StringId* GetStringIdOrNullPtr(uint32_t index) {
+    return index == dex::kDexNoIndex ? nullptr : StringIds()[index];
+  }
+  TypeId* GetTypeIdOrNullPtr(uint16_t index) {
+    return index == DexFile::kDexNoIndex16 ? nullptr : TypeIds()[index];
+  }
+
+  uint32_t MapListOffset() const { return map_list_offset_; }
+  void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
+
+  const std::vector<uint8_t>& LinkData() const { return link_data_; }
+  void SetLinkData(std::vector<uint8_t>&& link_data) { link_data_ = std::move(link_data); }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
@@ -683,7 +536,35 @@
     memcpy(magic_, magic, sizeof(magic_));
     memcpy(signature_, signature, sizeof(signature_));
   }
-  Collections collections_;
+
+  // Collection vectors own the IR data.
+  IndexedCollectionVector<StringId> string_ids_;
+  IndexedCollectionVector<TypeId> type_ids_;
+  IndexedCollectionVector<ProtoId> proto_ids_;
+  IndexedCollectionVector<FieldId> field_ids_;
+  IndexedCollectionVector<MethodId> method_ids_;
+  IndexedCollectionVector<ClassDef> class_defs_;
+  IndexedCollectionVector<CallSiteId> call_site_ids_;
+  IndexedCollectionVector<MethodHandleItem> method_handle_items_;
+  IndexedCollectionVector<StringData> string_datas_;
+  IndexedCollectionVector<TypeList> type_lists_;
+  IndexedCollectionVector<EncodedArrayItem> encoded_array_items_;
+  IndexedCollectionVector<AnnotationItem> annotation_items_;
+  IndexedCollectionVector<AnnotationSetItem> annotation_set_items_;
+  IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_;
+  IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_;
+  // The order of the vectors controls the layout of the output file by index order, to change the
+  // layout just sort the vector. Note that you may only change the order of the non indexed vectors
+  // below. Indexed vectors are accessed by indices in other places, changing the sorting order will
+  // invalidate the existing indices and is not currently supported.
+  CollectionVector<DebugInfoItem> debug_info_items_;
+  CollectionVector<CodeItem> code_items_;
+  CollectionVector<ClassData> class_datas_;
+
+  uint32_t map_list_offset_ = 0;
+
+  // Link data.
+  std::vector<uint8_t> link_data_;
 
   DISALLOW_COPY_AND_ASSIGN(Header);
 };
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 9468f76..a04a234 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -20,14 +20,226 @@
 #include <vector>
 
 #include "dex_ir_builder.h"
+
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file_exception_helpers.h"
 #include "dexlayout.h"
 
 namespace art {
 namespace dex_ir {
 
-static void CheckAndSetRemainingOffsets(const DexFile& dex_file,
-                                        Collections* collections,
-                                        const Options& options);
+static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
+  uint64_t value = 0;
+  for (uint32_t i = 0; i <= length; i++) {
+    value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
+  }
+  if (sign_extend) {
+    int shift = (7 - length) * 8;
+    return (static_cast<int64_t>(value) << shift) >> shift;
+  }
+  return value;
+}
+
+static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
+  const uint8_t* stream = debug_info_stream;
+  DecodeUnsignedLeb128(&stream);  // line_start
+  uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+  for (uint32_t i = 0; i < parameters_size; ++i) {
+    DecodeUnsignedLeb128P1(&stream);  // Parameter name.
+  }
+
+  for (;;)  {
+    uint8_t opcode = *stream++;
+    switch (opcode) {
+      case DexFile::DBG_END_SEQUENCE:
+        return stream - debug_info_stream;  // end of stream.
+      case DexFile::DBG_ADVANCE_PC:
+        DecodeUnsignedLeb128(&stream);  // addr_diff
+        break;
+      case DexFile::DBG_ADVANCE_LINE:
+        DecodeSignedLeb128(&stream);  // line_diff
+        break;
+      case DexFile::DBG_START_LOCAL:
+        DecodeUnsignedLeb128(&stream);  // register_num
+        DecodeUnsignedLeb128P1(&stream);  // name_idx
+        DecodeUnsignedLeb128P1(&stream);  // type_idx
+        break;
+      case DexFile::DBG_START_LOCAL_EXTENDED:
+        DecodeUnsignedLeb128(&stream);  // register_num
+        DecodeUnsignedLeb128P1(&stream);  // name_idx
+        DecodeUnsignedLeb128P1(&stream);  // type_idx
+        DecodeUnsignedLeb128P1(&stream);  // sig_idx
+        break;
+      case DexFile::DBG_END_LOCAL:
+      case DexFile::DBG_RESTART_LOCAL:
+        DecodeUnsignedLeb128(&stream);  // register_num
+        break;
+      case DexFile::DBG_SET_PROLOGUE_END:
+      case DexFile::DBG_SET_EPILOGUE_BEGIN:
+        break;
+      case DexFile::DBG_SET_FILE: {
+        DecodeUnsignedLeb128P1(&stream);  // name_idx
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+  }
+}
+
+template<class T> class CollectionMap : public CollectionBase {
+ public:
+  CollectionMap() = default;
+  virtual ~CollectionMap() OVERRIDE { }
+
+  template <class... Args>
+  T* CreateAndAddItem(CollectionVector<T>& vector,
+                      bool eagerly_assign_offsets,
+                      uint32_t offset,
+                      Args&&... args) {
+    T* item = vector.CreateAndAddItem(std::forward<Args>(args)...);
+    DCHECK(!GetExistingObject(offset));
+    DCHECK(!item->OffsetAssigned());
+    if (eagerly_assign_offsets) {
+      item->SetOffset(offset);
+    }
+    AddItem(item, offset);
+    return item;
+  }
+
+  // Returns the existing item if it is already inserted, null otherwise.
+  T* GetExistingObject(uint32_t offset) {
+    auto it = collection_.find(offset);
+    return it != collection_.end() ? it->second : nullptr;
+  }
+
+  // Lower case for template interop with std::map.
+  uint32_t size() const { return collection_.size(); }
+  std::map<uint32_t, T*>& Collection() { return collection_; }
+
+ private:
+  std::map<uint32_t, T*> collection_;
+
+  // CollectionMaps do not own the objects they contain, therefore AddItem is supported
+  // rather than CreateAndAddItem.
+  void AddItem(T* object, uint32_t offset) {
+    auto it = collection_.emplace(offset, object);
+    CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
+                     << " and address " << it.first->second;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(CollectionMap);
+};
+
+class BuilderMaps {
+ public:
+  BuilderMaps(Header* header, bool eagerly_assign_offsets)
+      : header_(header), eagerly_assign_offsets_(eagerly_assign_offsets) { }
+
+  void CreateStringId(const DexFile& dex_file, uint32_t i);
+  void CreateTypeId(const DexFile& dex_file, uint32_t i);
+  void CreateProtoId(const DexFile& dex_file, uint32_t i);
+  void CreateFieldId(const DexFile& dex_file, uint32_t i);
+  void CreateMethodId(const DexFile& dex_file, uint32_t i);
+  void CreateClassDef(const DexFile& dex_file, uint32_t i);
+  void CreateCallSiteId(const DexFile& dex_file, uint32_t i);
+  void CreateMethodHandleItem(const DexFile& dex_file, uint32_t i);
+
+  void CreateCallSitesAndMethodHandles(const DexFile& dex_file);
+
+  TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
+  EncodedArrayItem* CreateEncodedArrayItem(const DexFile& dex_file,
+                                           const uint8_t* static_data,
+                                           uint32_t offset);
+  AnnotationItem* CreateAnnotationItem(const DexFile& dex_file,
+                                       const DexFile::AnnotationItem* annotation);
+  AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
+      const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
+  AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
+      const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
+  CodeItem* DedupeOrCreateCodeItem(const DexFile& dex_file,
+                                   const DexFile::CodeItem* disk_code_item,
+                                   uint32_t offset,
+                                   uint32_t dex_method_index);
+  ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
+
+  void AddAnnotationsFromMapListSection(const DexFile& dex_file,
+                                        uint32_t start_offset,
+                                        uint32_t count);
+
+  void CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options);
+
+  // Sort the vectors buy map order (same order that was used in the input file).
+  void SortVectorsByMapOrder();
+
+ private:
+  bool GetIdsFromByteCode(const CodeItem* code,
+                          std::vector<TypeId*>* type_ids,
+                          std::vector<StringId*>* string_ids,
+                          std::vector<MethodId*>* method_ids,
+                          std::vector<FieldId*>* field_ids);
+
+  bool GetIdFromInstruction(const Instruction* dec_insn,
+                            std::vector<TypeId*>* type_ids,
+                            std::vector<StringId*>* string_ids,
+                            std::vector<MethodId*>* method_ids,
+                            std::vector<FieldId*>* field_ids);
+
+  EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data);
+  EncodedValue* ReadEncodedValue(const DexFile& dex_file,
+                                 const uint8_t** data,
+                                 uint8_t type,
+                                 uint8_t length);
+  void ReadEncodedValue(const DexFile& dex_file,
+                        const uint8_t** data,
+                        uint8_t type,
+                        uint8_t length,
+                        EncodedValue* item);
+
+  MethodItem GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
+
+  ParameterAnnotation* GenerateParameterAnnotation(
+      const DexFile& dex_file,
+      MethodId* method_id,
+      const DexFile::AnnotationSetRefList* annotation_set_ref_list,
+      uint32_t offset);
+
+  template <typename Type, class... Args>
+  Type* CreateAndAddIndexedItem(IndexedCollectionVector<Type>& vector,
+                                uint32_t offset,
+                                uint32_t index,
+                                Args&&... args) {
+    Type* item = vector.CreateAndAddIndexedItem(index, std::forward<Args>(args)...);
+    DCHECK(!item->OffsetAssigned());
+    if (eagerly_assign_offsets_) {
+      item->SetOffset(offset);
+    }
+    return item;
+  }
+
+  Header* header_;
+  // If we eagerly assign offsets during IR building or later after layout. Must be false if
+  // changing the layout is enabled.
+  bool eagerly_assign_offsets_;
+
+  // Note: maps do not have ownership.
+  CollectionMap<StringData> string_datas_map_;
+  CollectionMap<TypeList> type_lists_map_;
+  CollectionMap<EncodedArrayItem> encoded_array_items_map_;
+  CollectionMap<AnnotationItem> annotation_items_map_;
+  CollectionMap<AnnotationSetItem> annotation_set_items_map_;
+  CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_map_;
+  CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_map_;
+  CollectionMap<DebugInfoItem> debug_info_items_map_;
+  // Code item maps need to check both the debug info offset and debug info offset, do not use
+  // CollectionMap.
+  // First offset is the code item offset, second is the debug info offset.
+  std::map<std::pair<uint32_t, uint32_t>, CodeItem*> code_items_map_;
+  CollectionMap<ClassData> class_datas_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(BuilderMaps);
+};
 
 Header* DexIrBuilder(const DexFile& dex_file,
                      bool eagerly_assign_offsets,
@@ -50,36 +262,35 @@
                               dex_file.NumFieldIds(),
                               dex_file.NumMethodIds(),
                               dex_file.NumClassDefs());
-  Collections& collections = header->GetCollections();
-  collections.SetEagerlyAssignOffsets(eagerly_assign_offsets);
+  BuilderMaps builder_maps(header, eagerly_assign_offsets);
   // Walk the rest of the header fields.
   // StringId table.
-  collections.SetStringIdsOffset(disk_header.string_ids_off_);
+  header->StringIds().SetOffset(disk_header.string_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) {
-    collections.CreateStringId(dex_file, i);
+    builder_maps.CreateStringId(dex_file, i);
   }
   // TypeId table.
-  collections.SetTypeIdsOffset(disk_header.type_ids_off_);
+  header->TypeIds().SetOffset(disk_header.type_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
-    collections.CreateTypeId(dex_file, i);
+    builder_maps.CreateTypeId(dex_file, i);
   }
   // ProtoId table.
-  collections.SetProtoIdsOffset(disk_header.proto_ids_off_);
+  header->ProtoIds().SetOffset(disk_header.proto_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) {
-    collections.CreateProtoId(dex_file, i);
+    builder_maps.CreateProtoId(dex_file, i);
   }
   // FieldId table.
-  collections.SetFieldIdsOffset(disk_header.field_ids_off_);
+  header->FieldIds().SetOffset(disk_header.field_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) {
-    collections.CreateFieldId(dex_file, i);
+    builder_maps.CreateFieldId(dex_file, i);
   }
   // MethodId table.
-  collections.SetMethodIdsOffset(disk_header.method_ids_off_);
+  header->MethodIds().SetOffset(disk_header.method_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) {
-    collections.CreateMethodId(dex_file, i);
+    builder_maps.CreateMethodId(dex_file, i);
   }
   // ClassDef table.
-  collections.SetClassDefsOffset(disk_header.class_defs_off_);
+  header->ClassDefs().SetOffset(disk_header.class_defs_off_);
   for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
     if (!options.class_filter_.empty()) {
       // If the filter is enabled (not empty), filter out classes that don't have a matching
@@ -90,29 +301,29 @@
         continue;
       }
     }
-    collections.CreateClassDef(dex_file, i);
+    builder_maps.CreateClassDef(dex_file, i);
   }
   // MapItem.
-  collections.SetMapListOffset(disk_header.map_off_);
+  header->SetMapListOffset(disk_header.map_off_);
   // CallSiteIds and MethodHandleItems.
-  collections.CreateCallSitesAndMethodHandles(dex_file);
-  CheckAndSetRemainingOffsets(dex_file, &collections, options);
+  builder_maps.CreateCallSitesAndMethodHandles(dex_file);
+  builder_maps.CheckAndSetRemainingOffsets(dex_file, options);
 
   // Sort the vectors by the map order (same order as the file).
-  collections.SortVectorsByMapOrder();
-  collections.ClearMaps();
+  builder_maps.SortVectorsByMapOrder();
 
   // Load the link data if it exists.
-  collections.SetLinkData(std::vector<uint8_t>(
+  header->SetLinkData(std::vector<uint8_t>(
       dex_file.DataBegin() + dex_file.GetHeader().link_off_,
       dex_file.DataBegin() + dex_file.GetHeader().link_off_ + dex_file.GetHeader().link_size_));
 
   return header;
 }
 
-static void CheckAndSetRemainingOffsets(const DexFile& dex_file,
-                                        Collections* collections,
-                                        const Options& options) {
+/*
+ * Get all the types, strings, methods, and fields referred to from bytecode.
+ */
+void BuilderMaps::CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options) {
   const DexFile::Header& disk_header = dex_file.GetHeader();
   // Read MapItems and validate/set remaining offsets.
   const DexFile::MapList* map = dex_file.GetMapList();
@@ -125,74 +336,74 @@
         CHECK_EQ(item->offset_, 0u);
         break;
       case DexFile::kDexTypeStringIdItem:
-        CHECK_EQ(item->size_, collections->StringIdsSize());
-        CHECK_EQ(item->offset_, collections->StringIdsOffset());
+        CHECK_EQ(item->size_, header_->StringIds().Size());
+        CHECK_EQ(item->offset_, header_->StringIds().GetOffset());
         break;
       case DexFile::kDexTypeTypeIdItem:
-        CHECK_EQ(item->size_, collections->TypeIdsSize());
-        CHECK_EQ(item->offset_, collections->TypeIdsOffset());
+        CHECK_EQ(item->size_, header_->TypeIds().Size());
+        CHECK_EQ(item->offset_, header_->TypeIds().GetOffset());
         break;
       case DexFile::kDexTypeProtoIdItem:
-        CHECK_EQ(item->size_, collections->ProtoIdsSize());
-        CHECK_EQ(item->offset_, collections->ProtoIdsOffset());
+        CHECK_EQ(item->size_, header_->ProtoIds().Size());
+        CHECK_EQ(item->offset_, header_->ProtoIds().GetOffset());
         break;
       case DexFile::kDexTypeFieldIdItem:
-        CHECK_EQ(item->size_, collections->FieldIdsSize());
-        CHECK_EQ(item->offset_, collections->FieldIdsOffset());
+        CHECK_EQ(item->size_, header_->FieldIds().Size());
+        CHECK_EQ(item->offset_, header_->FieldIds().GetOffset());
         break;
       case DexFile::kDexTypeMethodIdItem:
-        CHECK_EQ(item->size_, collections->MethodIdsSize());
-        CHECK_EQ(item->offset_, collections->MethodIdsOffset());
+        CHECK_EQ(item->size_, header_->MethodIds().Size());
+        CHECK_EQ(item->offset_, header_->MethodIds().GetOffset());
         break;
       case DexFile::kDexTypeClassDefItem:
         if (options.class_filter_.empty()) {
           // The filter may have removed some classes, this will get fixed up during writing.
-          CHECK_EQ(item->size_, collections->ClassDefsSize());
+          CHECK_EQ(item->size_, header_->ClassDefs().Size());
         }
-        CHECK_EQ(item->offset_, collections->ClassDefsOffset());
+        CHECK_EQ(item->offset_, header_->ClassDefs().GetOffset());
         break;
       case DexFile::kDexTypeCallSiteIdItem:
-        CHECK_EQ(item->size_, collections->CallSiteIdsSize());
-        CHECK_EQ(item->offset_, collections->CallSiteIdsOffset());
+        CHECK_EQ(item->size_, header_->CallSiteIds().Size());
+        CHECK_EQ(item->offset_, header_->CallSiteIds().GetOffset());
         break;
       case DexFile::kDexTypeMethodHandleItem:
-        CHECK_EQ(item->size_, collections->MethodHandleItemsSize());
-        CHECK_EQ(item->offset_, collections->MethodHandleItemsOffset());
+        CHECK_EQ(item->size_, header_->MethodHandleItems().Size());
+        CHECK_EQ(item->offset_, header_->MethodHandleItems().GetOffset());
         break;
       case DexFile::kDexTypeMapList:
         CHECK_EQ(item->size_, 1u);
         CHECK_EQ(item->offset_, disk_header.map_off_);
         break;
       case DexFile::kDexTypeTypeList:
-        collections->SetTypeListsOffset(item->offset_);
+        header_->TypeLists().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeAnnotationSetRefList:
-        collections->SetAnnotationSetRefListsOffset(item->offset_);
+        header_->AnnotationSetRefLists().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeAnnotationSetItem:
-        collections->SetAnnotationSetItemsOffset(item->offset_);
+        header_->AnnotationSetItems().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeClassDataItem:
-        collections->SetClassDatasOffset(item->offset_);
+        header_->ClassDatas().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeCodeItem:
-        collections->SetCodeItemsOffset(item->offset_);
+        header_->CodeItems().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeStringDataItem:
-        collections->SetStringDatasOffset(item->offset_);
+        header_->StringDatas().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeDebugInfoItem:
-        collections->SetDebugInfoItemsOffset(item->offset_);
+        header_->DebugInfoItems().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeAnnotationItem:
-        collections->SetAnnotationItemsOffset(item->offset_);
-        collections->AddAnnotationsFromMapListSection(dex_file, item->offset_, item->size_);
+        header_->AnnotationItems().SetOffset(item->offset_);
+        AddAnnotationsFromMapListSection(dex_file, item->offset_, item->size_);
         break;
       case DexFile::kDexTypeEncodedArrayItem:
-        collections->SetEncodedArrayItemsOffset(item->offset_);
+        header_->EncodedArrayItems().SetOffset(item->offset_);
         break;
       case DexFile::kDexTypeAnnotationsDirectoryItem:
-        collections->SetAnnotationsDirectoryItemsOffset(item->offset_);
+        header_->AnnotationsDirectoryItems().SetOffset(item->offset_);
         break;
       default:
         LOG(ERROR) << "Unknown map list item type.";
@@ -200,5 +411,798 @@
   }
 }
 
+void BuilderMaps::CreateStringId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
+  StringData* string_data =
+      string_datas_map_.CreateAndAddItem(header_->StringDatas(),
+                                         eagerly_assign_offsets_,
+                                         disk_string_id.string_data_off_,
+                                         dex_file.GetStringData(disk_string_id));
+  CreateAndAddIndexedItem(header_->StringIds(),
+                          header_->StringIds().GetOffset() + i * StringId::ItemSize(),
+                          i,
+                          string_data);
+}
+
+void BuilderMaps::CreateTypeId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
+  CreateAndAddIndexedItem(header_->TypeIds(),
+                          header_->TypeIds().GetOffset() + i * TypeId::ItemSize(),
+                          i,
+                          header_->StringIds()[disk_type_id.descriptor_idx_.index_]);
+}
+
+void BuilderMaps::CreateProtoId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i));
+  const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
+  TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
+
+  CreateAndAddIndexedItem(header_->ProtoIds(),
+                          header_->ProtoIds().GetOffset() + i * ProtoId::ItemSize(),
+                          i,
+                          header_->StringIds()[disk_proto_id.shorty_idx_.index_],
+                          header_->TypeIds()[disk_proto_id.return_type_idx_.index_],
+                          parameter_type_list);
+}
+
+void BuilderMaps::CreateFieldId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
+  CreateAndAddIndexedItem(header_->FieldIds(),
+                          header_->FieldIds().GetOffset() + i * FieldId::ItemSize(),
+                          i,
+                          header_->TypeIds()[disk_field_id.class_idx_.index_],
+                          header_->TypeIds()[disk_field_id.type_idx_.index_],
+                          header_->StringIds()[disk_field_id.name_idx_.index_]);
+}
+
+void BuilderMaps::CreateMethodId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
+  CreateAndAddIndexedItem(header_->MethodIds(),
+                          header_->MethodIds().GetOffset() + i * MethodId::ItemSize(),
+                          i,
+                          header_->TypeIds()[disk_method_id.class_idx_.index_],
+                          header_->ProtoIds()[disk_method_id.proto_idx_.index_],
+                          header_->StringIds()[disk_method_id.name_idx_.index_]);
+}
+
+void BuilderMaps::CreateClassDef(const DexFile& dex_file, uint32_t i) {
+  const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
+  const TypeId* class_type = header_->TypeIds()[disk_class_def.class_idx_.index_];
+  uint32_t access_flags = disk_class_def.access_flags_;
+  const TypeId* superclass = header_->GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
+
+  const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
+  TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
+
+  const StringId* source_file =
+      header_->GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_);
+  // Annotations.
+  AnnotationsDirectoryItem* annotations = nullptr;
+  const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
+      dex_file.GetAnnotationsDirectory(disk_class_def);
+  if (disk_annotations_directory_item != nullptr) {
+    annotations = CreateAnnotationsDirectoryItem(
+        dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_);
+  }
+  // Static field initializers.
+  const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
+  EncodedArrayItem* static_values =
+      CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_);
+  ClassData* class_data = CreateClassData(
+      dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
+  CreateAndAddIndexedItem(header_->ClassDefs(),
+                          header_->ClassDefs().GetOffset() + i * ClassDef::ItemSize(),
+                          i,
+                          class_type,
+                          access_flags,
+                          superclass,
+                          interfaces_type_list,
+                          source_file,
+                          annotations,
+                          static_values,
+                          class_data);
+}
+
+void BuilderMaps::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
+  const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_;
+  EncodedArrayItem* call_site_item =
+      CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
+
+  CreateAndAddIndexedItem(header_->CallSiteIds(),
+                          header_->CallSiteIds().GetOffset() + i * CallSiteId::ItemSize(),
+                          i,
+                          call_site_item);
+}
+
+void BuilderMaps::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
+  const DexFile::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i);
+  uint16_t index = disk_method_handle.field_or_method_idx_;
+  DexFile::MethodHandleType type =
+      static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
+  bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
+                   type == DexFile::MethodHandleType::kInvokeInstance ||
+                   type == DexFile::MethodHandleType::kInvokeConstructor ||
+                   type == DexFile::MethodHandleType::kInvokeDirect ||
+                   type == DexFile::MethodHandleType::kInvokeInterface;
+  static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface,
+                "Unexpected method handle types.");
+  IndexedItem* field_or_method_id;
+  if (is_invoke) {
+    field_or_method_id = header_->MethodIds()[index];
+  } else {
+    field_or_method_id = header_->FieldIds()[index];
+  }
+  CreateAndAddIndexedItem(header_->MethodHandleItems(),
+                          header_->MethodHandleItems().GetOffset() +
+                              i * MethodHandleItem::ItemSize(),
+                          i,
+                          type,
+                          field_or_method_id);
+}
+
+void BuilderMaps::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
+  // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
+  const DexFile::MapList* map = dex_file.GetMapList();
+  for (uint32_t i = 0; i < map->size_; ++i) {
+    const DexFile::MapItem* item = map->list_ + i;
+    switch (item->type_) {
+      case DexFile::kDexTypeCallSiteIdItem:
+        header_->CallSiteIds().SetOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeMethodHandleItem:
+        header_->MethodHandleItems().SetOffset(item->offset_);
+        break;
+      default:
+        break;
+    }
+  }
+  // Populate MethodHandleItems first (CallSiteIds may depend on them).
+  for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) {
+    CreateMethodHandleItem(dex_file, i);
+  }
+  // Populate CallSiteIds.
+  for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) {
+    CreateCallSiteId(dex_file, i);
+  }
+}
+
+TypeList* BuilderMaps::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
+  if (dex_type_list == nullptr) {
+    return nullptr;
+  }
+  TypeList* type_list = type_lists_map_.GetExistingObject(offset);
+  if (type_list == nullptr) {
+    TypeIdVector* type_vector = new TypeIdVector();
+    uint32_t size = dex_type_list->Size();
+    for (uint32_t index = 0; index < size; ++index) {
+      type_vector->push_back(header_->TypeIds()[
+                             dex_type_list->GetTypeItem(index).type_idx_.index_]);
+    }
+    type_list = type_lists_map_.CreateAndAddItem(header_->TypeLists(),
+                                                 eagerly_assign_offsets_,
+                                                 offset,
+                                                 type_vector);
+  }
+  return type_list;
+}
+
+EncodedArrayItem* BuilderMaps::CreateEncodedArrayItem(const DexFile& dex_file,
+                                                      const uint8_t* static_data,
+                                                      uint32_t offset) {
+  if (static_data == nullptr) {
+    return nullptr;
+  }
+  EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset);
+  if (encoded_array_item == nullptr) {
+    uint32_t size = DecodeUnsignedLeb128(&static_data);
+    EncodedValueVector* values = new EncodedValueVector();
+    for (uint32_t i = 0; i < size; ++i) {
+      values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data)));
+    }
+    // TODO: Calculate the size of the encoded array.
+    encoded_array_item = encoded_array_items_map_.CreateAndAddItem(header_->EncodedArrayItems(),
+                                                                   eagerly_assign_offsets_,
+                                                                   offset,
+                                                                   values);
+  }
+  return encoded_array_item;
+}
+
+void BuilderMaps::AddAnnotationsFromMapListSection(const DexFile& dex_file,
+                                                   uint32_t start_offset,
+                                                   uint32_t count) {
+  uint32_t current_offset = start_offset;
+  for (size_t i = 0; i < count; ++i) {
+    // Annotation that we didn't process already, add it to the set.
+    const DexFile::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset);
+    AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
+    DCHECK(annotation_item != nullptr);
+    current_offset += annotation_item->GetSize();
+  }
+}
+
+AnnotationItem* BuilderMaps::CreateAnnotationItem(const DexFile& dex_file,
+                                                  const DexFile::AnnotationItem* annotation) {
+  const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
+  const uint32_t offset = start_data - dex_file.DataBegin();
+  AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
+  if (annotation_item == nullptr) {
+    uint8_t visibility = annotation->visibility_;
+    const uint8_t* annotation_data = annotation->annotation_;
+    std::unique_ptr<EncodedValue> encoded_value(
+        ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0));
+    annotation_item =
+        annotation_items_map_.CreateAndAddItem(header_->AnnotationItems(),
+                                               eagerly_assign_offsets_,
+                                               offset,
+                                               visibility,
+                                               encoded_value->ReleaseEncodedAnnotation());
+    annotation_item->SetSize(annotation_data - start_data);
+  }
+  return annotation_item;
+}
+
+
+AnnotationSetItem* BuilderMaps::CreateAnnotationSetItem(const DexFile& dex_file,
+    const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
+  if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
+    return nullptr;
+  }
+  AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset);
+  if (annotation_set_item == nullptr) {
+    std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
+    for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
+      const DexFile::AnnotationItem* annotation =
+          dex_file.GetAnnotationItem(disk_annotations_item, i);
+      if (annotation == nullptr) {
+        continue;
+      }
+      AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
+      items->push_back(annotation_item);
+    }
+    annotation_set_item =
+        annotation_set_items_map_.CreateAndAddItem(header_->AnnotationSetItems(),
+                                                   eagerly_assign_offsets_,
+                                                   offset,
+                                                   items);
+  }
+  return annotation_set_item;
+}
+
+AnnotationsDirectoryItem* BuilderMaps::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
+    const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
+  AnnotationsDirectoryItem* annotations_directory_item =
+      annotations_directory_items_map_.GetExistingObject(offset);
+  if (annotations_directory_item != nullptr) {
+    return annotations_directory_item;
+  }
+  const DexFile::AnnotationSetItem* class_set_item =
+      dex_file.GetClassAnnotationSet(disk_annotations_item);
+  AnnotationSetItem* class_annotation = nullptr;
+  if (class_set_item != nullptr) {
+    uint32_t item_offset = disk_annotations_item->class_annotations_off_;
+    class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset);
+  }
+  const DexFile::FieldAnnotationsItem* fields =
+      dex_file.GetFieldAnnotations(disk_annotations_item);
+  FieldAnnotationVector* field_annotations = nullptr;
+  if (fields != nullptr) {
+    field_annotations = new FieldAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
+      FieldId* field_id = header_->FieldIds()[fields[i].field_idx_];
+      const DexFile::AnnotationSetItem* field_set_item =
+          dex_file.GetFieldAnnotationSetItem(fields[i]);
+      uint32_t annotation_set_offset = fields[i].annotations_off_;
+      AnnotationSetItem* annotation_set_item =
+          CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
+      field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
+          new FieldAnnotation(field_id, annotation_set_item)));
+    }
+  }
+  const DexFile::MethodAnnotationsItem* methods =
+      dex_file.GetMethodAnnotations(disk_annotations_item);
+  MethodAnnotationVector* method_annotations = nullptr;
+  if (methods != nullptr) {
+    method_annotations = new MethodAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
+      MethodId* method_id = header_->MethodIds()[methods[i].method_idx_];
+      const DexFile::AnnotationSetItem* method_set_item =
+          dex_file.GetMethodAnnotationSetItem(methods[i]);
+      uint32_t annotation_set_offset = methods[i].annotations_off_;
+      AnnotationSetItem* annotation_set_item =
+          CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
+      method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
+          new MethodAnnotation(method_id, annotation_set_item)));
+    }
+  }
+  const DexFile::ParameterAnnotationsItem* parameters =
+      dex_file.GetParameterAnnotations(disk_annotations_item);
+  ParameterAnnotationVector* parameter_annotations = nullptr;
+  if (parameters != nullptr) {
+    parameter_annotations = new ParameterAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
+      MethodId* method_id = header_->MethodIds()[parameters[i].method_idx_];
+      const DexFile::AnnotationSetRefList* list =
+          dex_file.GetParameterAnnotationSetRefList(&parameters[i]);
+      parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
+          GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_)));
+    }
+  }
+  // TODO: Calculate the size of the annotations directory.
+  return annotations_directory_items_map_.CreateAndAddItem(header_->AnnotationsDirectoryItems(),
+                                                           eagerly_assign_offsets_,
+                                                           offset,
+                                                           class_annotation,
+                                                           field_annotations,
+                                                           method_annotations,
+                                                           parameter_annotations);
+}
+
+CodeItem* BuilderMaps::DedupeOrCreateCodeItem(const DexFile& dex_file,
+                                              const DexFile::CodeItem* disk_code_item,
+                                              uint32_t offset,
+                                              uint32_t dex_method_index) {
+  if (disk_code_item == nullptr) {
+    return nullptr;
+  }
+  CodeItemDebugInfoAccessor accessor(dex_file, disk_code_item, dex_method_index);
+  const uint32_t debug_info_offset = accessor.DebugInfoOffset();
+
+  // Create the offsets pair and dedupe based on it.
+  std::pair<uint32_t, uint32_t> offsets_pair(offset, debug_info_offset);
+  auto existing = code_items_map_.find(offsets_pair);
+  if (existing != code_items_map_.end()) {
+    return existing->second;
+  }
+
+  const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset);
+  DebugInfoItem* debug_info = nullptr;
+  if (debug_info_stream != nullptr) {
+    debug_info = debug_info_items_map_.GetExistingObject(debug_info_offset);
+    if (debug_info == nullptr) {
+      uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
+      uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
+      memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
+      debug_info = debug_info_items_map_.CreateAndAddItem(header_->DebugInfoItems(),
+                                                          eagerly_assign_offsets_,
+                                                          debug_info_offset,
+                                                          debug_info_size,
+                                                          debug_info_buffer);
+    }
+  }
+
+  uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
+  uint16_t* insns = new uint16_t[insns_size];
+  memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t));
+
+  TryItemVector* tries = nullptr;
+  CatchHandlerVector* handler_list = nullptr;
+  if (accessor.TriesSize() > 0) {
+    tries = new TryItemVector();
+    handler_list = new CatchHandlerVector();
+    for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) {
+      uint32_t start_addr = disk_try_item.start_addr_;
+      uint16_t insn_count = disk_try_item.insn_count_;
+      uint16_t handler_off = disk_try_item.handler_off_;
+      const CatchHandler* handlers = nullptr;
+      for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
+        if (handler_off == existing_handlers->GetListOffset()) {
+          handlers = existing_handlers.get();
+          break;
+        }
+      }
+      if (handlers == nullptr) {
+        bool catch_all = false;
+        TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
+        for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) {
+          const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
+          const TypeId* type_id = header_->GetTypeIdOrNullPtr(type_index.index_);
+          catch_all |= type_id == nullptr;
+          addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
+              new TypeAddrPair(type_id, it.GetHandlerAddress())));
+        }
+        handlers = new CatchHandler(catch_all, handler_off, addr_pairs);
+        handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers));
+      }
+      TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
+      tries->push_back(std::unique_ptr<const TryItem>(try_item));
+    }
+    // Manually walk catch handlers list and add any missing handlers unreferenced by try items.
+    const uint8_t* handlers_base = accessor.GetCatchHandlerData();
+    const uint8_t* handlers_data = handlers_base;
+    uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data);
+    while (handlers_size > handler_list->size()) {
+      bool already_added = false;
+      uint16_t handler_off = handlers_data - handlers_base;
+      for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
+        if (handler_off == existing_handlers->GetListOffset()) {
+          already_added = true;
+          break;
+        }
+      }
+      int32_t size = DecodeSignedLeb128(&handlers_data);
+      bool has_catch_all = size <= 0;
+      if (has_catch_all) {
+        size = -size;
+      }
+      if (already_added) {
+        for (int32_t i = 0; i < size; i++) {
+          DecodeUnsignedLeb128(&handlers_data);
+          DecodeUnsignedLeb128(&handlers_data);
+        }
+        if (has_catch_all) {
+          DecodeUnsignedLeb128(&handlers_data);
+        }
+        continue;
+      }
+      TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
+      for (int32_t i = 0; i < size; i++) {
+        const TypeId* type_id =
+            header_->GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data));
+        uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
+        addr_pairs->push_back(
+            std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr)));
+      }
+      if (has_catch_all) {
+        uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
+        addr_pairs->push_back(
+            std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr)));
+      }
+      const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs);
+      handler_list->push_back(std::unique_ptr<const CatchHandler>(handler));
+    }
+  }
+
+  uint32_t size = dex_file.GetCodeItemSize(*disk_code_item);
+  CodeItem* code_item = header_->CodeItems().CreateAndAddItem(accessor.RegistersSize(),
+                                                                  accessor.InsSize(),
+                                                                  accessor.OutsSize(),
+                                                                  debug_info,
+                                                                  insns_size,
+                                                                  insns,
+                                                                  tries,
+                                                                  handler_list);
+  code_item->SetSize(size);
+
+  // Add the code item to the map.
+  DCHECK(!code_item->OffsetAssigned());
+  if (eagerly_assign_offsets_) {
+    code_item->SetOffset(offset);
+  }
+  code_items_map_.emplace(offsets_pair, code_item);
+
+  // Add "fixup" references to types, strings, methods, and fields.
+  // This is temporary, as we will probably want more detailed parsing of the
+  // instructions here.
+  std::vector<TypeId*> type_ids;
+  std::vector<StringId*> string_ids;
+  std::vector<MethodId*> method_ids;
+  std::vector<FieldId*> field_ids;
+  if (GetIdsFromByteCode(code_item,
+                         /*out*/ &type_ids,
+                         /*out*/ &string_ids,
+                         /*out*/ &method_ids,
+                         /*out*/ &field_ids)) {
+    CodeFixups* fixups = new CodeFixups(std::move(type_ids),
+                                        std::move(string_ids),
+                                        std::move(method_ids),
+                                        std::move(field_ids));
+    code_item->SetCodeFixups(fixups);
+  }
+
+  return code_item;
+}
+
+ClassData* BuilderMaps::CreateClassData(
+    const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
+  // Read the fields and methods defined by the class, resolving the circular reference from those
+  // to classes by setting class at the same time.
+  ClassData* class_data = class_datas_map_.GetExistingObject(offset);
+  if (class_data == nullptr && encoded_data != nullptr) {
+    ClassDataItemIterator cdii(dex_file, encoded_data);
+    // Static fields.
+    FieldItemVector* static_fields = new FieldItemVector();
+    for (; cdii.HasNextStaticField(); cdii.Next()) {
+      FieldId* field_item = header_->FieldIds()[cdii.GetMemberIndex()];
+      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+      static_fields->emplace_back(access_flags, field_item);
+    }
+    // Instance fields.
+    FieldItemVector* instance_fields = new FieldItemVector();
+    for (; cdii.HasNextInstanceField(); cdii.Next()) {
+      FieldId* field_item = header_->FieldIds()[cdii.GetMemberIndex()];
+      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+      instance_fields->emplace_back(access_flags, field_item);
+    }
+    // Direct methods.
+    MethodItemVector* direct_methods = new MethodItemVector();
+    for (; cdii.HasNextDirectMethod(); cdii.Next()) {
+      direct_methods->push_back(GenerateMethodItem(dex_file, cdii));
+    }
+    // Virtual methods.
+    MethodItemVector* virtual_methods = new MethodItemVector();
+    for (; cdii.HasNextVirtualMethod(); cdii.Next()) {
+      virtual_methods->push_back(GenerateMethodItem(dex_file, cdii));
+    }
+    class_data = class_datas_map_.CreateAndAddItem(header_->ClassDatas(),
+                                                   eagerly_assign_offsets_,
+                                                   offset,
+                                                   static_fields,
+                                                   instance_fields,
+                                                   direct_methods,
+                                                   virtual_methods);
+    class_data->SetSize(cdii.EndDataPointer() - encoded_data);
+  }
+  return class_data;
+}
+
+void BuilderMaps::SortVectorsByMapOrder() {
+  header_->StringDatas().SortByMapOrder(string_datas_map_.Collection());
+  header_->TypeLists().SortByMapOrder(type_lists_map_.Collection());
+  header_->EncodedArrayItems().SortByMapOrder(encoded_array_items_map_.Collection());
+  header_->AnnotationItems().SortByMapOrder(annotation_items_map_.Collection());
+  header_->AnnotationSetItems().SortByMapOrder(annotation_set_items_map_.Collection());
+  header_->AnnotationSetRefLists().SortByMapOrder(annotation_set_ref_lists_map_.Collection());
+  header_->AnnotationsDirectoryItems().SortByMapOrder(
+      annotations_directory_items_map_.Collection());
+  header_->DebugInfoItems().SortByMapOrder(debug_info_items_map_.Collection());
+  header_->CodeItems().SortByMapOrder(code_items_map_);
+  header_->ClassDatas().SortByMapOrder(class_datas_map_.Collection());
+}
+
+bool BuilderMaps::GetIdsFromByteCode(const CodeItem* code,
+                                     std::vector<TypeId*>* type_ids,
+                                     std::vector<StringId*>* string_ids,
+                                     std::vector<MethodId*>* method_ids,
+                                     std::vector<FieldId*>* field_ids) {
+  bool has_id = false;
+  IterationRange<DexInstructionIterator> instructions = code->Instructions();
+  SafeDexInstructionIterator it(instructions.begin(), instructions.end());
+  for (; !it.IsErrorState() && it < instructions.end(); ++it) {
+    // In case the instruction goes past the end of the code item, make sure to not process it.
+    SafeDexInstructionIterator next = it;
+    ++next;
+    if (next.IsErrorState()) {
+      break;
+    }
+    has_id |= GetIdFromInstruction(&it.Inst(), type_ids, string_ids, method_ids, field_ids);
+  }  // for
+  return has_id;
+}
+
+bool BuilderMaps::GetIdFromInstruction(const Instruction* dec_insn,
+                                       std::vector<TypeId*>* type_ids,
+                                       std::vector<StringId*>* string_ids,
+                                       std::vector<MethodId*>* method_ids,
+                                       std::vector<FieldId*>* field_ids) {
+  // Determine index and width of the string.
+  uint32_t index = 0;
+  switch (Instruction::FormatOf(dec_insn->Opcode())) {
+    // SOME NOT SUPPORTED:
+    // case Instruction::k20bc:
+    case Instruction::k21c:
+    case Instruction::k35c:
+    // case Instruction::k35ms:
+    case Instruction::k3rc:
+    // case Instruction::k3rms:
+    // case Instruction::k35mi:
+    // case Instruction::k3rmi:
+    case Instruction::k45cc:
+    case Instruction::k4rcc:
+      index = dec_insn->VRegB();
+      break;
+    case Instruction::k31c:
+      index = dec_insn->VRegB();
+      break;
+    case Instruction::k22c:
+    // case Instruction::k22cs:
+      index = dec_insn->VRegC();
+      break;
+    default:
+      break;
+  }  // switch
+
+  // Determine index type, and add reference to the appropriate collection.
+  switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
+    case Instruction::kIndexTypeRef:
+      if (index < header_->TypeIds().Size()) {
+        type_ids->push_back(header_->TypeIds()[index]);
+        return true;
+      }
+      break;
+    case Instruction::kIndexStringRef:
+      if (index < header_->StringIds().Size()) {
+        string_ids->push_back(header_->StringIds()[index]);
+        return true;
+      }
+      break;
+    case Instruction::kIndexMethodRef:
+    case Instruction::kIndexMethodAndProtoRef:
+      if (index < header_->MethodIds().Size()) {
+        method_ids->push_back(header_->MethodIds()[index]);
+        return true;
+      }
+      break;
+    case Instruction::kIndexFieldRef:
+      if (index < header_->FieldIds().Size()) {
+        field_ids->push_back(header_->FieldIds()[index]);
+        return true;
+      }
+      break;
+    case Instruction::kIndexUnknown:
+    case Instruction::kIndexNone:
+    case Instruction::kIndexVtableOffset:
+    case Instruction::kIndexFieldOffset:
+    default:
+      break;
+  }  // switch
+  return false;
+}
+
+EncodedValue* BuilderMaps::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) {
+  const uint8_t encoded_value = *(*data)++;
+  const uint8_t type = encoded_value & 0x1f;
+  EncodedValue* item = new EncodedValue(type);
+  ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item);
+  return item;
+}
+
+EncodedValue* BuilderMaps::ReadEncodedValue(const DexFile& dex_file,
+                                            const uint8_t** data,
+                                            uint8_t type,
+                                            uint8_t length) {
+  EncodedValue* item = new EncodedValue(type);
+  ReadEncodedValue(dex_file, data, type, length, item);
+  return item;
+}
+
+void BuilderMaps::ReadEncodedValue(const DexFile& dex_file,
+                                   const uint8_t** data,
+                                   uint8_t type,
+                                   uint8_t length,
+                                   EncodedValue* item) {
+  switch (type) {
+    case DexFile::kDexAnnotationByte:
+      item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
+      break;
+    case DexFile::kDexAnnotationShort:
+      item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true)));
+      break;
+    case DexFile::kDexAnnotationChar:
+      item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false)));
+      break;
+    case DexFile::kDexAnnotationInt:
+      item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true)));
+      break;
+    case DexFile::kDexAnnotationLong:
+      item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true)));
+      break;
+    case DexFile::kDexAnnotationFloat: {
+      // Fill on right.
+      union {
+        float f;
+        uint32_t data;
+      } conv;
+      conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
+      item->SetFloat(conv.f);
+      break;
+    }
+    case DexFile::kDexAnnotationDouble: {
+      // Fill on right.
+      union {
+        double d;
+        uint64_t data;
+      } conv;
+      conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
+      item->SetDouble(conv.d);
+      break;
+    }
+    case DexFile::kDexAnnotationMethodType: {
+      const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetProtoId(header_->ProtoIds()[proto_index]);
+      break;
+    }
+    case DexFile::kDexAnnotationMethodHandle: {
+      const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetMethodHandle(header_->MethodHandleItems()[method_handle_index]);
+      break;
+    }
+    case DexFile::kDexAnnotationString: {
+      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetStringId(header_->StringIds()[string_index]);
+      break;
+    }
+    case DexFile::kDexAnnotationType: {
+      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetTypeId(header_->TypeIds()[string_index]);
+      break;
+    }
+    case DexFile::kDexAnnotationField:
+    case DexFile::kDexAnnotationEnum: {
+      const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetFieldId(header_->FieldIds()[field_index]);
+      break;
+    }
+    case DexFile::kDexAnnotationMethod: {
+      const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetMethodId(header_->MethodIds()[method_index]);
+      break;
+    }
+    case DexFile::kDexAnnotationArray: {
+      EncodedValueVector* values = new EncodedValueVector();
+      const uint32_t offset = *data - dex_file.DataBegin();
+      const uint32_t size = DecodeUnsignedLeb128(data);
+      // Decode all elements.
+      for (uint32_t i = 0; i < size; i++) {
+        values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data)));
+      }
+      EncodedArrayItem* array_item = new EncodedArrayItem(values);
+      if (eagerly_assign_offsets_) {
+        array_item->SetOffset(offset);
+      }
+      item->SetEncodedArray(array_item);
+      break;
+    }
+    case DexFile::kDexAnnotationAnnotation: {
+      AnnotationElementVector* elements = new AnnotationElementVector();
+      const uint32_t type_idx = DecodeUnsignedLeb128(data);
+      const uint32_t size = DecodeUnsignedLeb128(data);
+      // Decode all name=value pairs.
+      for (uint32_t i = 0; i < size; i++) {
+        const uint32_t name_index = DecodeUnsignedLeb128(data);
+        elements->push_back(std::unique_ptr<AnnotationElement>(
+            new AnnotationElement(header_->StringIds()[name_index],
+                                  ReadEncodedValue(dex_file, data))));
+      }
+      item->SetEncodedAnnotation(new EncodedAnnotation(header_->TypeIds()[type_idx], elements));
+      break;
+    }
+    case DexFile::kDexAnnotationNull:
+      break;
+    case DexFile::kDexAnnotationBoolean:
+      item->SetBoolean(length != 0);
+      break;
+    default:
+      break;
+  }
+}
+
+MethodItem BuilderMaps::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
+  MethodId* method_id = header_->MethodIds()[cdii.GetMemberIndex()];
+  uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+  const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
+  // Temporary hack to prevent incorrectly deduping code items if they have the same offset since
+  // they may have different debug info streams.
+  CodeItem* code_item = DedupeOrCreateCodeItem(dex_file,
+                                               disk_code_item,
+                                               cdii.GetMethodCodeItemOffset(),
+                                               cdii.GetMemberIndex());
+  return MethodItem(access_flags, method_id, code_item);
+}
+
+ParameterAnnotation* BuilderMaps::GenerateParameterAnnotation(
+    const DexFile& dex_file,
+    MethodId* method_id,
+    const DexFile::AnnotationSetRefList* annotation_set_ref_list,
+    uint32_t offset) {
+  AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset);
+  if (set_ref_list == nullptr) {
+    std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
+    for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
+      const DexFile::AnnotationSetItem* annotation_set_item =
+          dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
+      uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
+      annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
+    }
+    set_ref_list =
+        annotation_set_ref_lists_map_.CreateAndAddItem(header_->AnnotationSetRefLists(),
+                                                       eagerly_assign_offsets_,
+                                                       offset,
+                                                       annotations);
+  }
+  return new ParameterAnnotation(method_id, set_ref_list);
+}
+
 }  // namespace dex_ir
 }  // namespace art
diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc
index 2e4756b..962798d 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -31,38 +31,42 @@
 bool VerifyOutputDexFile(dex_ir::Header* orig_header,
                          dex_ir::Header* output_header,
                          std::string* error_msg) {
-  dex_ir::Collections& orig = orig_header->GetCollections();
-  dex_ir::Collections& output = output_header->GetCollections();
-
   // Compare all id sections. They have a defined order that can't be changed by dexlayout.
-  if (!VerifyIds(orig.StringIds(), output.StringIds(), "string ids", error_msg) ||
-      !VerifyIds(orig.TypeIds(), output.TypeIds(), "type ids", error_msg) ||
-      !VerifyIds(orig.ProtoIds(), output.ProtoIds(), "proto ids", error_msg) ||
-      !VerifyIds(orig.FieldIds(), output.FieldIds(), "field ids", error_msg) ||
-      !VerifyIds(orig.MethodIds(), output.MethodIds(), "method ids", error_msg)) {
+  if (!VerifyIds(orig_header->StringIds(), output_header->StringIds(), "string ids", error_msg) ||
+      !VerifyIds(orig_header->TypeIds(), output_header->TypeIds(), "type ids", error_msg) ||
+      !VerifyIds(orig_header->ProtoIds(), output_header->ProtoIds(), "proto ids", error_msg) ||
+      !VerifyIds(orig_header->FieldIds(), output_header->FieldIds(), "field ids", error_msg) ||
+      !VerifyIds(orig_header->MethodIds(), output_header->MethodIds(), "method ids", error_msg)) {
     return false;
   }
   // Compare class defs. The order may have been changed by dexlayout.
-  if (!VerifyClassDefs(orig.ClassDefs(), output.ClassDefs(), error_msg)) {
+  if (!VerifyClassDefs(orig_header->ClassDefs(), output_header->ClassDefs(), error_msg)) {
     return false;
   }
   return true;
 }
 
-template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
-                                 std::vector<std::unique_ptr<T>>& output,
+template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig,
+                                 dex_ir::CollectionVector<T>& output,
                                  const char* section_name,
                                  std::string* error_msg) {
-  if (orig.size() != output.size()) {
-    *error_msg = StringPrintf(
-        "Mismatched size for %s section: %zu vs %zu.", section_name, orig.size(), output.size());
-    return false;
-  }
-  for (size_t i = 0; i < orig.size(); ++i) {
-    if (!VerifyId(orig[i].get(), output[i].get(), error_msg)) {
+  auto orig_iter = orig.begin();
+  auto output_iter = output.begin();
+  for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) {
+    if (!VerifyId(orig_iter->get(), output_iter->get(), error_msg)) {
       return false;
     }
   }
+  if (orig_iter != orig.end() || output_iter != output.end()) {
+    const char* longer;
+    if (orig_iter == orig.end()) {
+      longer = "output";
+    } else {
+      longer = "original";
+    }
+    *error_msg = StringPrintf("Mismatch for %s section: %s is longer.", section_name, longer);
+    return false;
+  }
   return true;
 }
 
@@ -181,29 +185,36 @@
 
 // The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
 // identify them and sort them for comparison.
-bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
-                     std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig,
+                     dex_ir::CollectionVector<dex_ir::ClassDef>& output,
                      std::string* error_msg) {
-  if (orig.size() != output.size()) {
-    *error_msg = StringPrintf(
-        "Mismatched size for class defs section: %zu vs %zu.", orig.size(), output.size());
-    return false;
-  }
   // Store the class defs into sets sorted by the class's type index.
   std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
   std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
-  for (size_t i = 0; i < orig.size(); ++i) {
-    orig_set.insert(orig[i].get());
-    output_set.insert(output[i].get());
+  auto orig_iter = orig.begin();
+  auto output_iter = output.begin();
+  for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) {
+    orig_set.insert(orig_iter->get());
+    output_set.insert(output_iter->get());
   }
-  auto orig_iter = orig_set.begin();
-  auto output_iter = output_set.begin();
-  while (orig_iter != orig_set.end() && output_iter != output_set.end()) {
-    if (!VerifyClassDef(*orig_iter, *output_iter, error_msg)) {
+  if (orig_iter != orig.end() || output_iter != output.end()) {
+    const char* longer;
+    if (orig_iter == orig.end()) {
+      longer = "output";
+    } else {
+      longer = "original";
+    }
+    *error_msg = StringPrintf("Mismatch for class defs section: %s is longer.", longer);
+    return false;
+  }
+  auto orig_set_iter = orig_set.begin();
+  auto output_set_iter = output_set.begin();
+  while (orig_set_iter != orig_set.end() && output_set_iter != output_set.end()) {
+    if (!VerifyClassDef(*orig_set_iter, *output_set_iter, error_msg)) {
       return false;
     }
-    orig_iter++;
-    output_iter++;
+    orig_set_iter++;
+    output_set_iter++;
   }
   return true;
 }
diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h
index 998939b..4943def 100644
--- a/dexlayout/dex_verify.h
+++ b/dexlayout/dex_verify.h
@@ -30,8 +30,8 @@
                          dex_ir::Header* output_header,
                          std::string* error_msg);
 
-template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
-                                 std::vector<std::unique_ptr<T>>& output,
+template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig,
+                                 dex_ir::CollectionVector<T>& output,
                                  const char* section_name,
                                  std::string* error_msg);
 bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg);
@@ -40,8 +40,8 @@
 bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg);
 bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg);
 
-bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
-                     std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig,
+                     dex_ir::CollectionVector<dex_ir::ClassDef>& output,
                      std::string* error_msg);
 bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg);
 
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 0e04c58..abcaffc 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -252,9 +252,9 @@
     return;
   }
 
-  const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+  const uint32_t class_defs_size = header->ClassDefs().Size();
   for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
-    dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
+    dex_ir::ClassDef* class_def = header->ClassDefs()[class_index];
     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
     if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
       continue;
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 9ed1312..a4c5cda 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -231,7 +231,7 @@
 // function that takes a CollectionVector<T> and uses overloading.
 void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) {
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
+  for (auto& string_id : header_->StringIds()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem));
     if (reserve_only) {
       stream->Skip(string_id->GetSize());
@@ -241,7 +241,7 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetStringIdsOffset(start);
+    header_->StringIds().SetOffset(start);
   }
 }
 
@@ -256,25 +256,25 @@
 
 void DexWriter::WriteStringDatas(Stream* stream) {
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) {
+  for (auto& string_data : header_->StringDatas()) {
     WriteStringData(stream, string_data.get());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetStringDatasOffset(start);
+    header_->StringDatas().SetOffset(start);
   }
 }
 
 void DexWriter::WriteTypeIds(Stream* stream) {
   uint32_t descriptor_idx[1];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
+  for (auto& type_id : header_->TypeIds()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem));
     ProcessOffset(stream, type_id.get());
     descriptor_idx[0] = type_id->GetStringId()->GetIndex();
     stream->Write(descriptor_idx, type_id->GetSize());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetTypeIdsOffset(start);
+    header_->TypeIds().SetOffset(start);
   }
 }
 
@@ -282,7 +282,7 @@
   uint32_t size[1];
   uint16_t list[1];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().TypeLists()) {
+  for (auto& type_list : header_->TypeLists()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList));
     size[0] = type_list->GetTypeList()->size();
     ProcessOffset(stream, type_list.get());
@@ -293,14 +293,14 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetTypeListsOffset(start);
+    header_->TypeLists().SetOffset(start);
   }
 }
 
 void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) {
   uint32_t buffer[3];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
+  for (auto& proto_id : header_->ProtoIds()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem));
     ProcessOffset(stream, proto_id.get());
     if (reserve_only) {
@@ -313,14 +313,14 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetProtoIdsOffset(start);
+    header_->ProtoIds().SetOffset(start);
   }
 }
 
 void DexWriter::WriteFieldIds(Stream* stream) {
   uint16_t buffer[4];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
+  for (auto& field_id : header_->FieldIds()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem));
     ProcessOffset(stream, field_id.get());
     buffer[0] = field_id->Class()->GetIndex();
@@ -330,14 +330,14 @@
     stream->Write(buffer, field_id->GetSize());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetFieldIdsOffset(start);
+    header_->FieldIds().SetOffset(start);
   }
 }
 
 void DexWriter::WriteMethodIds(Stream* stream) {
   uint16_t buffer[4];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
+  for (auto& method_id : header_->MethodIds()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem));
     ProcessOffset(stream, method_id.get());
     buffer[0] = method_id->Class()->GetIndex();
@@ -347,28 +347,26 @@
     stream->Write(buffer, method_id->GetSize());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetMethodIdsOffset(start);
+    header_->MethodIds().SetOffset(start);
   }
 }
 
 void DexWriter::WriteEncodedArrays(Stream* stream) {
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
-      header_->GetCollections().EncodedArrayItems()) {
+  for (auto& encoded_array : header_->EncodedArrayItems()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
     ProcessOffset(stream, encoded_array.get());
     WriteEncodedArray(stream, encoded_array->GetEncodedValues());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetEncodedArrayItemsOffset(start);
+    header_->EncodedArrayItems().SetOffset(start);
   }
 }
 
 void DexWriter::WriteAnnotations(Stream* stream) {
   uint8_t visibility[1];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
-      header_->GetCollections().AnnotationItems()) {
+  for (auto& annotation : header_->AnnotationItems()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem));
     visibility[0] = annotation->GetVisibility();
     ProcessOffset(stream, annotation.get());
@@ -376,7 +374,7 @@
     WriteEncodedAnnotation(stream, annotation->GetAnnotation());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetAnnotationItemsOffset(start);
+    header_->AnnotationItems().SetOffset(start);
   }
 }
 
@@ -384,8 +382,7 @@
   uint32_t size[1];
   uint32_t annotation_off[1];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
-      header_->GetCollections().AnnotationSetItems()) {
+  for (auto& annotation_set : header_->AnnotationSetItems()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
     size[0] = annotation_set->GetItems()->size();
     ProcessOffset(stream, annotation_set.get());
@@ -396,7 +393,7 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetAnnotationSetItemsOffset(start);
+    header_->AnnotationSetItems().SetOffset(start);
   }
 }
 
@@ -404,8 +401,7 @@
   uint32_t size[1];
   uint32_t annotations_off[1];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
-      header_->GetCollections().AnnotationSetRefLists()) {
+  for (auto& annotation_set_ref : header_->AnnotationSetRefLists()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
     size[0] = annotation_set_ref->GetItems()->size();
     ProcessOffset(stream, annotation_set_ref.get());
@@ -416,7 +412,7 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetAnnotationSetRefListsOffset(start);
+    header_->AnnotationSetRefLists().SetOffset(start);
   }
 }
 
@@ -424,8 +420,7 @@
   uint32_t directory_buffer[4];
   uint32_t annotation_buffer[2];
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
-      header_->GetCollections().AnnotationsDirectoryItems()) {
+  for (auto& annotations_directory : header_->AnnotationsDirectoryItems()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
     ProcessOffset(stream, annotations_directory.get());
     directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
@@ -463,7 +458,7 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start);
+    header_->AnnotationsDirectoryItems().SetOffset(start);
   }
 }
 
@@ -475,12 +470,11 @@
 
 void DexWriter::WriteDebugInfoItems(Stream* stream) {
   const uint32_t start = stream->Tell();
-  for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info :
-      header_->GetCollections().DebugInfoItems()) {
+  for (auto& debug_info : header_->DebugInfoItems()) {
     WriteDebugInfoItem(stream, debug_info.get());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetDebugInfoItemsOffset(start);
+    header_->DebugInfoItems().SetOffset(start);
   }
 }
 
@@ -558,7 +552,7 @@
         DexLayoutSections::SectionType::kSectionTypeCode)];
   }
   const uint32_t start = stream->Tell();
-  for (auto& code_item : header_->GetCollections().CodeItems()) {
+  for (auto& code_item : header_->CodeItems()) {
     uint32_t start_offset = stream->Tell();
     WriteCodeItem(stream, code_item.get(), reserve_only);
     // Only add the section hotness info once.
@@ -573,14 +567,14 @@
   }
 
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetCodeItemsOffset(start);
+    header_->CodeItems().SetOffset(start);
   }
 }
 
 void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) {
   const uint32_t start = stream->Tell();
   uint32_t class_def_buffer[8];
-  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+  for (auto& class_def : header_->ClassDefs()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem));
     if (reserve_only) {
       stream->Skip(class_def->GetSize());
@@ -602,14 +596,14 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetClassDefsOffset(start);
+    header_->ClassDefs().SetOffset(start);
   }
 }
 
 void DexWriter::WriteClassDatas(Stream* stream) {
   const uint32_t start = stream->Tell();
   for (const std::unique_ptr<dex_ir::ClassData>& class_data :
-      header_->GetCollections().ClassDatas()) {
+      header_->ClassDatas()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem));
     ProcessOffset(stream, class_data.get());
     stream->WriteUleb128(class_data->StaticFields()->size());
@@ -622,15 +616,14 @@
     WriteEncodedMethods(stream, class_data->VirtualMethods());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetClassDatasOffset(start);
+    header_->ClassDatas().SetOffset(start);
   }
 }
 
 void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) {
   const uint32_t start = stream->Tell();
   uint32_t call_site_off[1];
-  for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
-      header_->GetCollections().CallSiteIds()) {
+  for (auto& call_site_id : header_->CallSiteIds()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
     if (reserve_only) {
       stream->Skip(call_site_id->GetSize());
@@ -640,15 +633,14 @@
     }
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetCallSiteIdsOffset(start);
+    header_->CallSiteIds().SetOffset(start);
   }
 }
 
 void DexWriter::WriteMethodHandles(Stream* stream) {
   const uint32_t start = stream->Tell();
   uint16_t method_handle_buff[4];
-  for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
-      header_->GetCollections().MethodHandleItems()) {
+  for (auto& method_handle : header_->MethodHandleItems()) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem));
     method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
     method_handle_buff[1] = 0;  // unused.
@@ -657,7 +649,7 @@
     stream->Write(method_handle_buff, method_handle->GetSize());
   }
   if (compute_offsets_ && start != stream->Tell()) {
-    header_->GetCollections().SetMethodHandleItemsOffset(start);
+    header_->MethodHandleItems().SetOffset(start);
   }
 }
 
@@ -678,67 +670,66 @@
 }
 
 void DexWriter::GenerateAndWriteMapItems(Stream* stream) {
-  dex_ir::Collections& collection = header_->GetCollections();
   MapItemQueue queue;
 
   // Header and index section.
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem,
-                              collection.StringIdsSize(),
-                              collection.StringIdsOffset()));
+                              header_->StringIds().Size(),
+                              header_->StringIds().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem,
-                              collection.TypeIdsSize(),
-                              collection.TypeIdsOffset()));
+                              header_->TypeIds().Size(),
+                              header_->TypeIds().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem,
-                              collection.ProtoIdsSize(),
-                              collection.ProtoIdsOffset()));
+                              header_->ProtoIds().Size(),
+                              header_->ProtoIds().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem,
-                              collection.FieldIdsSize(),
-                              collection.FieldIdsOffset()));
+                              header_->FieldIds().Size(),
+                              header_->FieldIds().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem,
-                              collection.MethodIdsSize(),
-                              collection.MethodIdsOffset()));
+                              header_->MethodIds().Size(),
+                              header_->MethodIds().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem,
-                              collection.ClassDefsSize(),
-                              collection.ClassDefsOffset()));
+                              header_->ClassDefs().Size(),
+                              header_->ClassDefs().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem,
-                              collection.CallSiteIdsSize(),
-                              collection.CallSiteIdsOffset()));
+                              header_->CallSiteIds().Size(),
+                              header_->CallSiteIds().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem,
-                              collection.MethodHandleItemsSize(),
-                              collection.MethodHandleItemsOffset()));
+                              header_->MethodHandleItems().Size(),
+                              header_->MethodHandleItems().GetOffset()));
   // Data section.
-  queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
+  queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, header_->MapListOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList,
-                              collection.TypeListsSize(),
-                              collection.TypeListsOffset()));
+                              header_->TypeLists().Size(),
+                              header_->TypeLists().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList,
-                              collection.AnnotationSetRefListsSize(),
-                              collection.AnnotationSetRefListsOffset()));
+                              header_->AnnotationSetRefLists().Size(),
+                              header_->AnnotationSetRefLists().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem,
-                              collection.AnnotationSetItemsSize(),
-                              collection.AnnotationSetItemsOffset()));
+                              header_->AnnotationSetItems().Size(),
+                              header_->AnnotationSetItems().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem,
-                              collection.ClassDatasSize(),
-                              collection.ClassDatasOffset()));
+                              header_->ClassDatas().Size(),
+                              header_->ClassDatas().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem,
-                              collection.CodeItemsSize(),
-                              collection.CodeItemsOffset()));
+                              header_->CodeItems().Size(),
+                              header_->CodeItems().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem,
-                              collection.StringDatasSize(),
-                              collection.StringDatasOffset()));
+                              header_->StringDatas().Size(),
+                              header_->StringDatas().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem,
-                              collection.DebugInfoItemsSize(),
-                              collection.DebugInfoItemsOffset()));
+                              header_->DebugInfoItems().Size(),
+                              header_->DebugInfoItems().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem,
-                              collection.AnnotationItemsSize(),
-                              collection.AnnotationItemsOffset()));
+                              header_->AnnotationItems().Size(),
+                              header_->AnnotationItems().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem,
-                              collection.EncodedArrayItemsSize(),
-                              collection.EncodedArrayItemsOffset()));
+                              header_->EncodedArrayItems().Size(),
+                              header_->EncodedArrayItems().GetOffset()));
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
-                              collection.AnnotationsDirectoryItemsSize(),
-                              collection.AnnotationsDirectoryItemsOffset()));
+                              header_->AnnotationsDirectoryItems().Size(),
+                              header_->AnnotationsDirectoryItems().GetOffset()));
   WriteMapItems(stream, &queue);
 }
 
@@ -761,20 +752,19 @@
   header.endian_tag_ = header_->EndianTag();
   header.link_size_ = header_->LinkSize();
   header.link_off_ = header_->LinkOffset();
-  const dex_ir::Collections& collections = header_->GetCollections();
-  header.map_off_ = collections.MapListOffset();
-  header.string_ids_size_ = collections.StringIdsSize();
-  header.string_ids_off_ = collections.StringIdsOffset();
-  header.type_ids_size_ = collections.TypeIdsSize();
-  header.type_ids_off_ = collections.TypeIdsOffset();
-  header.proto_ids_size_ = collections.ProtoIdsSize();
-  header.proto_ids_off_ = collections.ProtoIdsOffset();
-  header.field_ids_size_ = collections.FieldIdsSize();
-  header.field_ids_off_ = collections.FieldIdsOffset();
-  header.method_ids_size_ = collections.MethodIdsSize();
-  header.method_ids_off_ = collections.MethodIdsOffset();
-  header.class_defs_size_ = collections.ClassDefsSize();
-  header.class_defs_off_ = collections.ClassDefsOffset();
+  header.map_off_ = header_->MapListOffset();
+  header.string_ids_size_ = header_->StringIds().Size();
+  header.string_ids_off_ = header_->StringIds().GetOffset();
+  header.type_ids_size_ = header_->TypeIds().Size();
+  header.type_ids_off_ = header_->TypeIds().GetOffset();
+  header.proto_ids_size_ = header_->ProtoIds().Size();
+  header.proto_ids_off_ = header_->ProtoIds().GetOffset();
+  header.field_ids_size_ = header_->FieldIds().Size();
+  header.field_ids_off_ = header_->FieldIds().GetOffset();
+  header.method_ids_size_ = header_->MethodIds().Size();
+  header.method_ids_off_ = header_->MethodIds().GetOffset();
+  header.class_defs_size_ = header_->ClassDefs().Size();
+  header.class_defs_off_ = header_->ClassDefs().GetOffset();
   header.data_size_ = header_->DataSize();
   header.data_off_ = header_->DataOffset();
 
@@ -797,8 +787,6 @@
   // Starting offset is right after the header.
   stream->Seek(GetHeaderSize());
 
-  dex_ir::Collections& collection = header_->GetCollections();
-
   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
   // Since the offsets may not be calculated already, the writing must be done in the correct order.
   const uint32_t string_ids_offset = stream->Tell();
@@ -863,9 +851,9 @@
   // Write the map list.
   if (compute_offsets_) {
     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
-    collection.SetMapListOffset(stream->Tell());
+    header_->SetMapListOffset(stream->Tell());
   } else {
-    stream->Seek(collection.MapListOffset());
+    stream->Seek(header_->MapListOffset());
   }
   GenerateAndWriteMapItems(stream);
   stream->AlignTo(kDataSectionAlignment);
@@ -882,7 +870,7 @@
   }
 
   // Write link data if it exists.
-  const std::vector<uint8_t>& link_data = collection.LinkData();
+  const std::vector<uint8_t>& link_data = header_->LinkData();
   if (link_data.size() > 0) {
     CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
     if (compute_offsets_) {
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 39d93bf..d6dd9d1 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -417,24 +417,24 @@
       outSize = snprintf(buf.get(), buf_size, "<no-index>");
       break;
     case Instruction::kIndexTypeRef:
-      if (index < header->GetCollections().TypeIdsSize()) {
-        const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
+      if (index < header->TypeIds().Size()) {
+        const char* tp = header->TypeIds()[index]->GetStringId()->Data();
         outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
       } else {
         outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
       }
       break;
     case Instruction::kIndexStringRef:
-      if (index < header->GetCollections().StringIdsSize()) {
-        const char* st = header->GetCollections().GetStringId(index)->Data();
+      if (index < header->StringIds().Size()) {
+        const char* st = header->StringIds()[index]->Data();
         outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
       } else {
         outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
       }
       break;
     case Instruction::kIndexMethodRef:
-      if (index < header->GetCollections().MethodIdsSize()) {
-        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+      if (index < header->MethodIds().Size()) {
+        dex_ir::MethodId* method_id = header->MethodIds()[index];
         const char* name = method_id->Name()->Data();
         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -445,8 +445,8 @@
       }
       break;
     case Instruction::kIndexFieldRef:
-      if (index < header->GetCollections().FieldIdsSize()) {
-        dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
+      if (index < header->FieldIds().Size()) {
+        dex_ir::FieldId* field_id = header->FieldIds()[index];
         const char* name = field_id->Name()->Data();
         const char* type_descriptor = field_id->Type()->GetStringId()->Data();
         const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -466,15 +466,15 @@
     case Instruction::kIndexMethodAndProtoRef: {
       std::string method("<method?>");
       std::string proto("<proto?>");
-      if (index < header->GetCollections().MethodIdsSize()) {
-        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+      if (index < header->MethodIds().Size()) {
+        dex_ir::MethodId* method_id = header->MethodIds()[index];
         const char* name = method_id->Name()->Data();
         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
         method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
       }
-      if (secondary_index < header->GetCollections().ProtoIdsSize()) {
-        dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
+      if (secondary_index < header->ProtoIds().Size()) {
+        dex_ir::ProtoId* proto_id = header->ProtoIds()[secondary_index];
         proto = GetSignatureForProtoId(proto_id);
       }
       outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
@@ -596,7 +596,6 @@
  */
 void DexLayout::DumpFileHeader() {
   char sanitized[8 * 2 + 1];
-  dex_ir::Collections& collections = header_->GetCollections();
   fprintf(out_file_, "DEX file header:\n");
   Asciify(sanitized, header_->Magic(), 8);
   fprintf(out_file_, "magic               : '%s'\n", sanitized);
@@ -610,24 +609,24 @@
   fprintf(out_file_, "link_size           : %d\n", header_->LinkSize());
   fprintf(out_file_, "link_off            : %d (0x%06x)\n",
           header_->LinkOffset(), header_->LinkOffset());
-  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
+  fprintf(out_file_, "string_ids_size     : %d\n", header_->StringIds().Size());
   fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
-          collections.StringIdsOffset(), collections.StringIdsOffset());
-  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
+          header_->StringIds().GetOffset(), header_->StringIds().GetOffset());
+  fprintf(out_file_, "type_ids_size       : %d\n", header_->TypeIds().Size());
   fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
-          collections.TypeIdsOffset(), collections.TypeIdsOffset());
-  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
+          header_->TypeIds().GetOffset(), header_->TypeIds().GetOffset());
+  fprintf(out_file_, "proto_ids_size      : %d\n", header_->ProtoIds().Size());
   fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
-          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
-  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
+          header_->ProtoIds().GetOffset(), header_->ProtoIds().GetOffset());
+  fprintf(out_file_, "field_ids_size      : %d\n", header_->FieldIds().Size());
   fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
-          collections.FieldIdsOffset(), collections.FieldIdsOffset());
-  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
+          header_->FieldIds().GetOffset(), header_->FieldIds().GetOffset());
+  fprintf(out_file_, "method_ids_size     : %d\n", header_->MethodIds().Size());
   fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
-          collections.MethodIdsOffset(), collections.MethodIdsOffset());
-  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
+          header_->MethodIds().GetOffset(), header_->MethodIds().GetOffset());
+  fprintf(out_file_, "class_defs_size     : %d\n", header_->ClassDefs().Size());
   fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
-          collections.ClassDefsOffset(), collections.ClassDefsOffset());
+          header_->ClassDefs().GetOffset(), header_->ClassDefs().GetOffset());
   fprintf(out_file_, "data_size           : %d\n", header_->DataSize());
   fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
           header_->DataOffset(), header_->DataOffset());
@@ -638,7 +637,7 @@
  */
 void DexLayout::DumpClassDef(int idx) {
   // General class information.
-  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+  dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
   fprintf(out_file_, "Class #%d header:\n", idx);
   fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
   fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
@@ -719,7 +718,7 @@
  * Dumps class annotations.
  */
 void DexLayout::DumpClassAnnotations(int idx) {
-  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+  dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
   dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
   if (annotations_directory == nullptr) {
     return;  // none
@@ -1039,7 +1038,7 @@
  * Dumps a bytecode disassembly.
  */
 void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
-  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
+  dex_ir::MethodId* method_id = header_->MethodIds()[idx];
   const char* name = method_id->Name()->Data();
   std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1083,16 +1082,16 @@
 /*
  * Lookup functions.
  */
-static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) {
-  dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx);
+static const char* StringDataByIdx(uint32_t idx, dex_ir::Header* header) {
+  dex_ir::StringId* string_id = header->GetStringIdOrNullPtr(idx);
   if (string_id == nullptr) {
     return nullptr;
   }
   return string_id->Data();
 }
 
-static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) {
-  dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx);
+static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Header* header) {
+  dex_ir::TypeId* type_id = header->GetTypeIdOrNullPtr(idx);
   if (type_id == nullptr) {
     return nullptr;
   }
@@ -1134,7 +1133,7 @@
   if (debug_info != nullptr) {
     DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(),
                                      [this](uint32_t idx) {
-                                       return StringDataByIdx(idx, this->header_->GetCollections());
+                                       return StringDataByIdx(idx, this->header_);
                                      },
                                      DumpPositionsCb,
                                      out_file_);
@@ -1161,12 +1160,12 @@
                                   code->InsSize(),
                                   code->InsnsSize(),
                                   [this](uint32_t idx) {
-                                    return StringDataByIdx(idx, this->header_->GetCollections());
+                                    return StringDataByIdx(idx, this->header_);
                                   },
                                   [this](uint32_t idx) {
                                     return
                                         StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
-                                                            this->header_->GetCollections());
+                                                            this->header_);
                                   },
                                   DumpLocalsCb,
                                   out_file_);
@@ -1182,7 +1181,7 @@
     return;
   }
 
-  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
+  dex_ir::MethodId* method_id = header_->MethodIds()[idx];
   const char* name = method_id->Name()->Data();
   char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1292,7 +1291,7 @@
     return;
   }
 
-  dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
+  dex_ir::FieldId* field_id = header_->FieldIds()[idx];
   const char* name = field_id->Name()->Data();
   const char* type_descriptor = field_id->Type()->GetStringId()->Data();
   const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1346,7 +1345,7 @@
  * the value will be replaced with a newly-allocated string.
  */
 void DexLayout::DumpClass(int idx, char** last_package) {
-  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+  dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
   // Omitting non-public class.
   if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
     return;
@@ -1364,8 +1363,7 @@
   // up the classes, sort them, and dump them alphabetically so the
   // package name wouldn't jump around, but that's not a great plan
   // for something that needs to run on the device.
-  const char* class_descriptor =
-      header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
+  const char* class_descriptor = header_->ClassDefs()[idx]->ClassType()->GetStringId()->Data();
   if (!(class_descriptor[0] == 'L' &&
         class_descriptor[strlen(class_descriptor)-1] == ';')) {
     // Arrays and primitives should not be defined explicitly. Keep going?
@@ -1543,7 +1541,7 @@
 
   // Iterate over all classes.
   char* package = nullptr;
-  const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
+  const uint32_t class_defs_size = header_->ClassDefs().Size();
   for (uint32_t i = 0; i < class_defs_size; i++) {
     DumpClass(i, &package);
   }  // for
@@ -1562,13 +1560,13 @@
 
 void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
   std::vector<dex_ir::ClassDef*> new_class_def_order;
-  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+  for (auto& class_def : header_->ClassDefs()) {
     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
     if (info_->ContainsClass(*dex_file, type_idx)) {
       new_class_def_order.push_back(class_def.get());
     }
   }
-  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+  for (auto& class_def : header_->ClassDefs()) {
     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
     if (!info_->ContainsClass(*dex_file, type_idx)) {
       new_class_def_order.push_back(class_def.get());
@@ -1576,8 +1574,7 @@
   }
   std::unordered_set<dex_ir::ClassData*> visited_class_data;
   size_t class_data_index = 0;
-  dex_ir::CollectionVector<dex_ir::ClassData>::Vector& class_datas =
-      header_->GetCollections().ClassDatas();
+  auto& class_datas = header_->ClassDatas();
   for (dex_ir::ClassDef* class_def : new_class_def_order) {
     dex_ir::ClassData* class_data = class_def->GetClassData();
     if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
@@ -1590,15 +1587,14 @@
       ++class_data_index;
     }
   }
-  CHECK_EQ(class_data_index, class_datas.size());
+  CHECK_EQ(class_data_index, class_datas.Size());
 
   if (DexLayout::kChangeClassDefOrder) {
     // This currently produces dex files that violate the spec since the super class class_def is
     // supposed to occur before any subclasses.
-    dex_ir::CollectionVector<dex_ir::ClassDef>::Vector& class_defs =
-        header_->GetCollections().ClassDefs();
-    CHECK_EQ(new_class_def_order.size(), class_defs.size());
-    for (size_t i = 0; i < class_defs.size(); ++i) {
+    dex_ir::CollectionVector<dex_ir::ClassDef>& class_defs = header_->ClassDefs();
+    CHECK_EQ(new_class_def_order.size(), class_defs.Size());
+    for (size_t i = 0; i < class_defs.Size(); ++i) {
       // Overwrite the existing vector with the new ordering, note that the sets of objects are
       // equivalent, but the order changes. This is why this is not a memory leak.
       // TODO: Consider cleaning this up with a shared_ptr.
@@ -1609,10 +1605,10 @@
 }
 
 void DexLayout::LayoutStringData(const DexFile* dex_file) {
-  const size_t num_strings = header_->GetCollections().StringIds().size();
+  const size_t num_strings = header_->StringIds().Size();
   std::vector<bool> is_shorty(num_strings, false);
   std::vector<bool> from_hot_method(num_strings, false);
-  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+  for (auto& class_def : header_->ClassDefs()) {
     // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
     // as hot. Add its super class and interfaces as well, which can be used during initialization.
     const bool is_profile_class =
@@ -1678,7 +1674,7 @@
   }
   // Sort string data by specified order.
   std::vector<dex_ir::StringId*> string_ids;
-  for (auto& string_id : header_->GetCollections().StringIds()) {
+  for (auto& string_id : header_->StringIds()) {
     string_ids.push_back(string_id.get());
   }
   std::sort(string_ids.begin(),
@@ -1699,8 +1695,7 @@
     // Order by index by default.
     return a->GetIndex() < b->GetIndex();
   });
-  dex_ir::CollectionVector<dex_ir::StringData>::Vector& string_datas =
-      header_->GetCollections().StringDatas();
+  auto& string_datas = header_->StringDatas();
   // Now we know what order we want the string data, reorder them.
   size_t data_index = 0;
   for (dex_ir::StringId* string_id : string_ids) {
@@ -1713,11 +1708,11 @@
     for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) {
       visited.insert(data.get());
     }
-    for (auto& string_id : header_->GetCollections().StringIds()) {
+    for (auto& string_id : header_->StringIds()) {
       CHECK(visited.find(string_id->DataItem()) != visited.end());
     }
   }
-  CHECK_EQ(data_index, string_datas.size());
+  CHECK_EQ(data_index, string_datas.Size());
 }
 
 // Orders code items according to specified class data ordering.
@@ -1732,7 +1727,7 @@
 
   // Assign hotness flags to all code items.
   for (InvokeType invoke_type : invoke_types) {
-    for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+    for (auto& class_def : header_->ClassDefs()) {
       const bool is_profile_class =
           info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
 
@@ -1778,8 +1773,7 @@
     }
   }
 
-  dex_ir::CollectionVector<dex_ir::CodeItem>::Vector& code_items =
-        header_->GetCollections().CodeItems();
+  const auto& code_items = header_->CodeItems();
   if (VLOG_IS_ON(dex)) {
     size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {};
     for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) {
@@ -1871,7 +1865,7 @@
   const bool has_output_container = dex_container != nullptr;
   const bool output = options_.output_dex_directory_ != nullptr || has_output_container;
 
-  // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset
+  // Try to avoid eagerly assigning offsets to find bugs since Offset will abort if the offset
   // is unassigned.
   bool eagerly_assign_offsets = false;
   if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) {
diff --git a/libartbase/base/atomic.h b/libartbase/base/atomic.h
index b68f867..9de84cd 100644
--- a/libartbase/base/atomic.h
+++ b/libartbase/base/atomic.h
@@ -28,6 +28,11 @@
 
 namespace art {
 
+enum class CASMode {
+  kStrong,
+  kWeak,
+};
+
 template<typename T>
 class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
  public:
@@ -100,6 +105,15 @@
     return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release);
   }
 
+  bool CompareAndSet(T expected_value,
+                     T desired_value,
+                     CASMode mode,
+                     std::memory_order memory_order) {
+    return mode == CASMode::kStrong
+        ? this->compare_exchange_strong(expected_value, desired_value, memory_order)
+        : this->compare_exchange_weak(expected_value, desired_value, memory_order);
+  }
+
   // Returns the address of the current atomic variable. This is only used by futex() which is
   // declared to take a volatile address (see base/mutex-inl.h).
   volatile T* Address() {
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index d9bea3d..0ace09d 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -222,4 +222,10 @@
   }
 }  // namespace art
 
+#define TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING() \
+  if (kRunningOnMemoryTool && kPoisonHeapReferences) { \
+    printf("WARNING: TEST DISABLED FOR MEMORY TOOL WITH HEAP POISONING\n"); \
+    return; \
+  }
+
 #endif  // ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index 9ba1d6c..d53480d 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -647,21 +647,11 @@
 }
 
 bool MemMap::Sync() {
-  bool result;
-  if (redzone_size_ != 0) {
-    // To avoid errors when running on a memory tool, temporarily lift the lower-end noaccess
-    // protection before passing it to msync() as it only accepts page-aligned base address,
-    // and exclude the higher-end noaccess protection from the msync range. b/27552451.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether this special case is needed for ASan.
-    uint8_t* base_begin = reinterpret_cast<uint8_t*>(base_begin_);
-    MEMORY_TOOL_MAKE_DEFINED(base_begin, begin_ - base_begin);
-    result = msync(BaseBegin(), End() - base_begin, MS_SYNC) == 0;
-    MEMORY_TOOL_MAKE_NOACCESS(base_begin, begin_ - base_begin);
-  } else {
-    result = msync(BaseBegin(), BaseSize(), MS_SYNC) == 0;
-  }
-  return result;
+  // Historical note: To avoid Valgrind errors, we temporarily lifted the lower-end noaccess
+  // protection before passing it to msync() when `redzone_size_` was non-null, as Valgrind
+  // only accepts page-aligned base address, and excludes the higher-end noaccess protection
+  // from the msync range. b/27552451.
+  return msync(BaseBegin(), BaseSize(), MS_SYNC) == 0;
 }
 
 bool MemMap::Protect(int prot) {
diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc
index 4a78bdc..c575c7a 100644
--- a/libartbase/base/mem_map_test.cc
+++ b/libartbase/base/mem_map_test.cc
@@ -471,9 +471,8 @@
   // cannot allocate in the 2GB-4GB region.
   TEST_DISABLED_FOR_MIPS();
 
-  // This test may not work under Valgrind.
-  // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-  // check whether this test works with ASan.
+  // This test does not work under AddressSanitizer.
+  // Historical note: This test did not work under Valgrind either.
   TEST_DISABLED_FOR_MEMORY_TOOL();
 
   CommonInit();
diff --git a/openjdkjvmti/ti_ddms.cc b/openjdkjvmti/ti_ddms.cc
index 0b4906d..bf063fa 100644
--- a/openjdkjvmti/ti_ddms.cc
+++ b/openjdkjvmti/ti_ddms.cc
@@ -60,7 +60,7 @@
   *data_out = nullptr;
 
   art::Thread* self = art::Thread::Current();
-  art::ScopedThreadStateChange(self, art::ThreadState::kNative);
+  art::ScopedThreadStateChange stcs(self, art::ThreadState::kNative);
 
   art::ArrayRef<const jbyte> data_arr(data_in, length_in);
   std::vector<uint8_t> out_data;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 1168798..b347019 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -37,7 +37,6 @@
         "base/quasi_atomic.cc",
         "base/timing_logger.cc",
         "cha.cc",
-        "check_jni.cc",
         "class_linker.cc",
         "class_loader_context.cc",
         "class_root.cc",
@@ -112,6 +111,7 @@
         "jit/jit_code_cache.cc",
         "jit/profiling_info.cc",
         "jit/profile_saver.cc",
+        "jni/check_jni.cc",
         "jni/java_vm_ext.cc",
         "jni/jni_env_ext.cc",
         "jni/jni_internal.cc",
diff --git a/runtime/exec_utils_test.cc b/runtime/exec_utils_test.cc
index a9c1ea2..c138ce3 100644
--- a/runtime/exec_utils_test.cc
+++ b/runtime/exec_utils_test.cc
@@ -36,12 +36,9 @@
     command.push_back("/usr/bin/id");
   }
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
-    EXPECT_TRUE(Exec(command, &error_msg));
-  }
+  // Historical note: Running on Valgrind failed due to some memory
+  // that leaks in thread alternate signal stacks.
+  EXPECT_TRUE(Exec(command, &error_msg));
   EXPECT_EQ(0U, error_msg.size()) << error_msg;
 }
 
@@ -52,13 +49,10 @@
   std::vector<std::string> command;
   command.push_back("bogus");
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
-    EXPECT_FALSE(Exec(command, &error_msg));
-    EXPECT_FALSE(error_msg.empty());
-  }
+  // Historical note: Running on Valgrind failed due to some memory
+  // that leaks in thread alternate signal stacks.
+  EXPECT_FALSE(Exec(command, &error_msg));
+  EXPECT_FALSE(error_msg.empty());
 }
 
 TEST_F(ExecUtilsTest, EnvSnapshotAdditionsAreNotVisible) {
@@ -76,13 +70,10 @@
   }
   command.push_back(kModifiedVariable);
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
-    EXPECT_FALSE(Exec(command, &error_msg));
-    EXPECT_NE(0U, error_msg.size()) << error_msg;
-  }
+  // Historical note: Running on Valgrind failed due to some memory
+  // that leaks in thread alternate signal stacks.
+  EXPECT_FALSE(Exec(command, &error_msg));
+  EXPECT_NE(0U, error_msg.size()) << error_msg;
 }
 
 TEST_F(ExecUtilsTest, EnvSnapshotDeletionsAreNotVisible) {
@@ -103,13 +94,10 @@
   }
   command.push_back(kDeletedVariable);
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
-    EXPECT_TRUE(Exec(command, &error_msg));
-    EXPECT_EQ(0U, error_msg.size()) << error_msg;
-  }
+  // Historical note: Running on Valgrind failed due to some memory
+  // that leaks in thread alternate signal stacks.
+  EXPECT_TRUE(Exec(command, &error_msg));
+  EXPECT_EQ(0U, error_msg.size()) << error_msg;
   // Restore the variable's value.
   EXPECT_EQ(setenv(kDeletedVariable, save_value, kOverwrite), 0);
 }
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index c4d2fdd..10fa8c5 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1551,7 +1551,7 @@
     // above IsInToSpace() evaluates to true and we change the color from gray to white here in this
     // else block.
     if (kUseBakerReadBarrier) {
-      bool success = to_ref->AtomicSetReadBarrierState</*kCasRelease*/true>(
+      bool success = to_ref->AtomicSetReadBarrierState<std::memory_order_release>(
           ReadBarrier::GrayState(),
           ReadBarrier::WhiteState());
       DCHECK(success) << "Must succeed as we won the race.";
@@ -2490,7 +2490,10 @@
     LockWord new_lock_word = LockWord::FromForwardingAddress(reinterpret_cast<size_t>(to_ref));
 
     // Try to atomically write the fwd ptr.
-    bool success = from_ref->CasLockWordWeakRelaxed(old_lock_word, new_lock_word);
+    bool success = from_ref->CasLockWord(old_lock_word,
+                                         new_lock_word,
+                                         CASMode::kWeak,
+                                         std::memory_order_relaxed);
     if (LIKELY(success)) {
       // The CAS succeeded.
       DCHECK(thread_running_gc_ != nullptr);
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
index 3869533..6caca84 100644
--- a/runtime/gc/heap_verification_test.cc
+++ b/runtime/gc/heap_verification_test.cc
@@ -83,7 +83,7 @@
 }
 
 TEST_F(VerificationTest, IsValidClassInHeap) {
-  TEST_DISABLED_FOR_MEMORY_TOOL();
+  TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
   ScopedObjectAccess soa(Thread::Current());
   VariableSizedHandleScope hs(soa.Self());
   Handle<mirror::String> string(
@@ -106,7 +106,7 @@
 }
 
 TEST_F(VerificationTest, DumpValidObjectInfo) {
-  TEST_DISABLED_FOR_MEMORY_TOOL();
+  TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
   ScopedLogSeverity sls(LogSeverity::INFO);
   ScopedObjectAccess soa(Thread::Current());
   Runtime* const runtime = Runtime::Current();
@@ -126,7 +126,7 @@
 }
 
 TEST_F(VerificationTest, LogHeapCorruption) {
-  TEST_DISABLED_FOR_MEMORY_TOOL();
+  TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
   ScopedLogSeverity sls(LogSeverity::INFO);
   ScopedObjectAccess soa(Thread::Current());
   Runtime* const runtime = Runtime::Current();
@@ -147,7 +147,6 @@
 }
 
 TEST_F(VerificationTest, FindPathFromRootSet) {
-  TEST_DISABLED_FOR_MEMORY_TOOL();
   ScopedLogSeverity sls(LogSeverity::INFO);
   ScopedObjectAccess soa(Thread::Current());
   Runtime* const runtime = Runtime::Current();
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 667bd03..6a4cf56 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1855,11 +1855,17 @@
   jint newValue = args[4];
   bool success;
   if (Runtime::Current()->IsActiveTransaction()) {
-    success = obj->CasFieldStrongSequentiallyConsistent32<true>(MemberOffset(offset),
-                                                                expectedValue, newValue);
+    success = obj->CasField32<true>(MemberOffset(offset),
+                                    expectedValue,
+                                    newValue,
+                                    CASMode::kStrong,
+                                    std::memory_order_seq_cst);
   } else {
-    success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
-                                                                 expectedValue, newValue);
+    success = obj->CasField32<false>(MemberOffset(offset),
+                                     expectedValue,
+                                     newValue,
+                                     CASMode::kStrong,
+                                     std::memory_order_seq_cst);
   }
   result->SetZ(success ? JNI_TRUE : JNI_FALSE);
 }
diff --git a/runtime/check_jni.cc b/runtime/jni/check_jni.cc
similarity index 99%
rename from runtime/check_jni.cc
rename to runtime/jni/check_jni.cc
index 0ff55ae..7919c32 100644
--- a/runtime/check_jni.cc
+++ b/runtime/jni/check_jni.cc
@@ -35,8 +35,8 @@
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "gc/space/space.h"
-#include "jni/java_vm_ext.h"
-#include "jni/jni_internal.h"
+#include "java_vm_ext.h"
+#include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/field.h"
 #include "mirror/method.h"
@@ -2173,7 +2173,7 @@
     return result;
   }
 
-  static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
+  static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, const jvalue* vargs) {
     CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
@@ -2268,16 +2268,16 @@
   FIELD_ACCESSORS(jdouble, Double, Primitive::kPrimDouble, D, D)
 #undef FIELD_ACCESSORS
 
-  static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* vargs) {
+  static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* vargs) {
     CallMethodA(__FUNCTION__, env, obj, nullptr, mid, vargs, Primitive::kPrimVoid, kVirtual);
   }
 
   static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass c, jmethodID mid,
-                                        jvalue* vargs) {
+                                        const jvalue* vargs) {
     CallMethodA(__FUNCTION__, env, obj, c, mid, vargs, Primitive::kPrimVoid, kDirect);
   }
 
-  static void CallStaticVoidMethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
+  static void CallStaticVoidMethodA(JNIEnv* env, jclass c, jmethodID mid, const jvalue* vargs) {
     CallMethodA(__FUNCTION__, env, nullptr, c, mid, vargs, Primitive::kPrimVoid, kStatic);
   }
 
@@ -2316,16 +2316,16 @@
   }
 
 #define CALL(rtype, name, ptype, shorty) \
-  static rtype Call##name##MethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* vargs) { \
+  static rtype Call##name##MethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* vargs) { \
     return CallMethodA(__FUNCTION__, env, obj, nullptr, mid, vargs, ptype, kVirtual).shorty; \
   } \
   \
   static rtype CallNonvirtual##name##MethodA(JNIEnv* env, jobject obj, jclass c, jmethodID mid, \
-                                             jvalue* vargs) { \
+                                             const jvalue* vargs) { \
     return CallMethodA(__FUNCTION__, env, obj, c, mid, vargs, ptype, kDirect).shorty; \
   } \
   \
-  static rtype CallStatic##name##MethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) { \
+  static rtype CallStatic##name##MethodA(JNIEnv* env, jclass c, jmethodID mid, const jvalue* vargs) { \
     return CallMethodA(__FUNCTION__, env, nullptr, c, mid, vargs, ptype, kStatic).shorty; \
   } \
   \
@@ -3070,7 +3070,7 @@
   }
 
   static JniValueType CallMethodA(const char* function_name, JNIEnv* env, jobject obj, jclass c,
-                                  jmethodID mid, jvalue* vargs, Primitive::Type type,
+                                  jmethodID mid, const jvalue* vargs, Primitive::Type type,
                                   InvokeType invoke) {
     CHECK_ATTACHED_THREAD(function_name, JniValueType());
     ScopedObjectAccess soa(env);
diff --git a/runtime/check_jni.h b/runtime/jni/check_jni.h
similarity index 87%
rename from runtime/check_jni.h
rename to runtime/jni/check_jni.h
index f41abf8..10fdfe8 100644
--- a/runtime/check_jni.h
+++ b/runtime/jni/check_jni.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_CHECK_JNI_H_
-#define ART_RUNTIME_CHECK_JNI_H_
+#ifndef ART_RUNTIME_JNI_CHECK_JNI_H_
+#define ART_RUNTIME_JNI_CHECK_JNI_H_
 
 #include <jni.h>
 
@@ -26,4 +26,4 @@
 
 }  // namespace art
 
-#endif  // ART_RUNTIME_CHECK_JNI_H_
+#endif  // ART_RUNTIME_JNI_CHECK_JNI_H_
diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc
index 7290d63..a02e76a 100644
--- a/runtime/jni/jni_internal.cc
+++ b/runtime/jni/jni_internal.cc
@@ -761,7 +761,7 @@
     return local_result;
   }
 
-  static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
+  static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(java_class);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
@@ -824,7 +824,7 @@
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
-  static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(obj);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
@@ -850,7 +850,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
-  static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -875,7 +875,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetB();
   }
 
-  static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -900,7 +900,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetC();
   }
 
-  static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -925,7 +925,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetD();
   }
 
-  static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -950,7 +950,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetF();
   }
 
-  static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -975,7 +975,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetI();
   }
 
-  static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1000,7 +1000,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
-  static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1025,7 +1025,7 @@
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetS();
   }
 
-  static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1049,7 +1049,7 @@
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args);
   }
 
-  static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+  static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
@@ -1078,7 +1078,7 @@
   }
 
   static jobject CallNonvirtualObjectMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                             jvalue* args) {
+                                             const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(obj);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
@@ -1107,7 +1107,7 @@
   }
 
   static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                               jvalue* args) {
+                                               const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1134,7 +1134,7 @@
   }
 
   static jbyte CallNonvirtualByteMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                         jvalue* args) {
+                                         const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1161,7 +1161,7 @@
   }
 
   static jchar CallNonvirtualCharMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                         jvalue* args) {
+                                         const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1188,7 +1188,7 @@
   }
 
   static jshort CallNonvirtualShortMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                           jvalue* args) {
+                                           const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1215,7 +1215,7 @@
   }
 
   static jint CallNonvirtualIntMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                       jvalue* args) {
+                                       const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1242,7 +1242,7 @@
   }
 
   static jlong CallNonvirtualLongMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                         jvalue* args) {
+                                         const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1269,7 +1269,7 @@
   }
 
   static jfloat CallNonvirtualFloatMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                           jvalue* args) {
+                                           const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1296,7 +1296,7 @@
   }
 
   static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                             jvalue* args) {
+                                             const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
@@ -1322,7 +1322,7 @@
   }
 
   static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
-                                        jvalue* args) {
+                                        const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
@@ -1562,7 +1562,7 @@
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
-  static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithJValues(soa, nullptr, mid, args));
@@ -1585,7 +1585,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
   }
 
-  static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
@@ -1607,7 +1607,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
   }
 
-  static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetB();
@@ -1629,7 +1629,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
   }
 
-  static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetC();
@@ -1651,7 +1651,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
   }
 
-  static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetS();
@@ -1673,7 +1673,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
   }
 
-  static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetI();
@@ -1695,7 +1695,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
   }
 
-  static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
@@ -1717,7 +1717,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
   }
 
-  static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetF();
@@ -1739,7 +1739,7 @@
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
   }
 
-  static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetD();
@@ -1760,7 +1760,7 @@
     InvokeWithVarArgs(soa, nullptr, mid, args);
   }
 
-  static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+  static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, nullptr, mid, args);
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index ee4f53b..bb99c0c 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -78,18 +78,6 @@
   }
 }
 
-inline bool Object::CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val) {
-  // Force use of non-transactional mode and do not check.
-  return CasFieldWeakSequentiallyConsistent32<false, false>(
-      OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
-}
-
-inline bool Object::CasLockWordWeakAcquire(LockWord old_val, LockWord new_val) {
-  // Force use of non-transactional mode and do not check.
-  return CasFieldWeakAcquire32<false, false>(
-      OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
-}
-
 inline uint32_t Object::GetLockOwnerThreadId() {
   return Monitor::GetLockOwnerThreadId(this);
 }
@@ -575,84 +563,6 @@
   }
 }
 
-// TODO: Pass memory_order_ and strong/weak as arguments to avoid code duplication?
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
-                                                         int32_t old_value,
-                                                         int32_t new_value) {
-  if (kCheckTransaction) {
-    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
-  }
-  if (kTransactionActive) {
-    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
-  }
-  if (kVerifyFlags & kVerifyThis) {
-    VerifyObject(this);
-  }
-  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
-  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
-  return atomic_addr->CompareAndSetWeakSequentiallyConsistent(old_value, new_value);
-}
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakAcquire32(MemberOffset field_offset,
-                                          int32_t old_value,
-                                          int32_t new_value) {
-  if (kCheckTransaction) {
-    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
-  }
-  if (kTransactionActive) {
-    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
-  }
-  if (kVerifyFlags & kVerifyThis) {
-    VerifyObject(this);
-  }
-  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
-  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
-  return atomic_addr->CompareAndSetWeakAcquire(old_value, new_value);
-}
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakRelease32(MemberOffset field_offset,
-                                          int32_t old_value,
-                                          int32_t new_value) {
-  if (kCheckTransaction) {
-    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
-  }
-  if (kTransactionActive) {
-    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
-  }
-  if (kVerifyFlags & kVerifyThis) {
-    VerifyObject(this);
-  }
-  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
-  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
-  return atomic_addr->CompareAndSetWeakRelease(old_value, new_value);
-}
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset,
-                                                           int32_t old_value,
-                                                           int32_t new_value) {
-  if (kCheckTransaction) {
-    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
-  }
-  if (kTransactionActive) {
-    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
-  }
-  if (kVerifyFlags & kVerifyThis) {
-    VerifyObject(this);
-  }
-  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
-  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
-  return atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_value, new_value);
-}
-
 template<bool kTransactionActive,
          bool kCheckTransaction,
          VerifyObjectFlags kVerifyFlags,
diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h
index aeaa850..597ba67 100644
--- a/runtime/mirror/object-readbarrier-inl.h
+++ b/runtime/mirror/object-readbarrier-inl.h
@@ -32,14 +32,17 @@
 template<VerifyObjectFlags kVerifyFlags>
 inline LockWord Object::GetLockWord(bool as_volatile) {
   if (as_volatile) {
-    return LockWord(GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+    return LockWord(GetField32Volatile<kVerifyFlags>(MonitorOffset()));
   }
-  return LockWord(GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+  return LockWord(GetField32<kVerifyFlags>(MonitorOffset()));
 }
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset,
-                                          int32_t old_value, int32_t new_value) {
+inline bool Object::CasField32(MemberOffset field_offset,
+                               int32_t old_value,
+                               int32_t new_value,
+                               CASMode mode,
+                               std::memory_order memory_order) {
   if (kCheckTransaction) {
     DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
   }
@@ -52,19 +55,19 @@
   uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
 
-  return atomic_addr->CompareAndSetWeakRelaxed(old_value, new_value);
+  return atomic_addr->CompareAndSet(old_value, new_value, mode, memory_order);
 }
 
-inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) {
+inline bool Object::CasLockWord(LockWord old_val,
+                                LockWord new_val,
+                                CASMode mode,
+                                std::memory_order memory_order) {
   // Force use of non-transactional mode and do not check.
-  return CasFieldWeakRelaxed32<false, false>(
-      OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
-}
-
-inline bool Object::CasLockWordWeakRelease(LockWord old_val, LockWord new_val) {
-  // Force use of non-transactional mode and do not check.
-  return CasFieldWeakRelease32<false, false>(
-      OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
+  return CasField32<false, false>(MonitorOffset(),
+                                  old_val.GetValue(),
+                                  new_val.GetValue(),
+                                  mode,
+                                  memory_order);
 }
 
 inline uint32_t Object::GetReadBarrierState(uintptr_t* fake_address_dependency) {
@@ -145,7 +148,7 @@
   return rb_state;
 }
 
-template<bool kCasRelease>
+template<std::memory_order kMemoryOrder>
 inline bool Object::AtomicSetReadBarrierState(uint32_t expected_rb_state, uint32_t rb_state) {
   if (!kUseBakerReadBarrier) {
     LOG(FATAL) << "Unreachable";
@@ -169,9 +172,7 @@
     // If kCasRelease == true, use a CAS release so that when GC updates all the fields of
     // an object and then changes the object from gray to black, the field updates (stores) will be
     // visible (won't be reordered after this CAS.)
-  } while (!(kCasRelease ?
-             CasLockWordWeakRelease(expected_lw, new_lw) :
-             CasLockWordWeakRelaxed(expected_lw, new_lw)));
+  } while (!CasLockWord(expected_lw, new_lw, CASMode::kWeak, kMemoryOrder));
   return true;
 }
 
@@ -188,7 +189,7 @@
     new_lw = lw;
     new_lw.SetMarkBitState(mark_bit);
     // Since this is only set from the mutator, we can use the non-release CAS.
-  } while (!CasLockWordWeakRelaxed(expected_lw, new_lw));
+  } while (!CasLockWord(expected_lw, new_lw, CASMode::kWeak, std::memory_order_relaxed));
   return true;
 }
 
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 4240e70..ce845bf 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -197,7 +197,9 @@
         // loop iteration.
         LockWord hash_word = LockWord::FromHashCode(GenerateIdentityHashCode(), lw.GCState());
         DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode);
-        if (current_this->CasLockWordWeakRelaxed(lw, hash_word)) {
+        // Use a strong CAS to prevent spurious failures since these can make the boot image
+        // non-deterministic.
+        if (current_this->CasLockWord(lw, hash_word, CASMode::kStrong, std::memory_order_relaxed)) {
           return hash_word.GetHashCode();
         }
         break;
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index a89d632..654fe95 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -111,7 +111,7 @@
 #endif
   ALWAYS_INLINE void SetReadBarrierState(uint32_t rb_state) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template<bool kCasRelease = false>
+  template<std::memory_order kMemoryOrder = std::memory_order_relaxed>
   ALWAYS_INLINE bool AtomicSetReadBarrierState(uint32_t expected_rb_state, uint32_t rb_state)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -151,13 +151,7 @@
   LockWord GetLockWord(bool as_volatile) REQUIRES_SHARED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetLockWord(LockWord new_val, bool as_volatile) REQUIRES_SHARED(Locks::mutator_lock_);
-  bool CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool CasLockWordWeakAcquire(LockWord old_val, LockWord new_val)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool CasLockWordWeakRelease(LockWord old_val, LockWord new_val)
+  bool CasLockWord(LockWord old_val, LockWord new_val, CASMode mode, std::memory_order memory_order)
       REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t GetLockOwnerThreadId();
 
@@ -523,41 +517,11 @@
   template<bool kTransactionActive,
            bool kCheckTransaction = true,
            VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE bool CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
-                                                          int32_t old_value,
-                                                          int32_t new_value)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  template<bool kTransactionActive,
-           bool kCheckTransaction = true,
-           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE bool CasFieldWeakRelaxed32(MemberOffset field_offset,
-                                           int32_t old_value,
-                                           int32_t new_value)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  template<bool kTransactionActive,
-           bool kCheckTransaction = true,
-           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE bool CasFieldWeakAcquire32(MemberOffset field_offset,
-                                           int32_t old_value,
-                                           int32_t new_value)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  template<bool kTransactionActive,
-           bool kCheckTransaction = true,
-           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE bool CasFieldWeakRelease32(MemberOffset field_offset,
-                                           int32_t old_value,
-                                           int32_t new_value)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  template<bool kTransactionActive,
-           bool kCheckTransaction = true,
-           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE bool CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset,
-                                                            int32_t old_value,
-                                                            int32_t new_value)
+  ALWAYS_INLINE bool CasField32(MemberOffset field_offset,
+                                int32_t old_value,
+                                int32_t new_value,
+                                CASMode mode,
+                                std::memory_order memory_order)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 2c38de5..d47bc0d 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -134,13 +134,15 @@
 }
 
 int32_t Monitor::GetHashCode() {
-  while (!HasHashCode()) {
-    if (hash_code_.CompareAndSetWeakRelaxed(0, mirror::Object::GenerateIdentityHashCode())) {
-      break;
-    }
+  int32_t hc = hash_code_.load(std::memory_order_relaxed);
+  if (!HasHashCode()) {
+    // Use a strong CAS to prevent spurious failures since these can make the boot image
+    // non-deterministic.
+    hash_code_.CompareAndSetStrongRelaxed(0, mirror::Object::GenerateIdentityHashCode());
+    hc = hash_code_.load(std::memory_order_relaxed);
   }
   DCHECK(HasHashCode());
-  return hash_code_.load(std::memory_order_relaxed);
+  return hc;
 }
 
 bool Monitor::Install(Thread* self) {
@@ -173,7 +175,7 @@
   }
   LockWord fat(this, lw.GCState());
   // Publish the updated lock word, which may race with other threads.
-  bool success = GetObject()->CasLockWordWeakRelease(lw, fat);
+  bool success = GetObject()->CasLockWord(lw, fat, CASMode::kWeak, std::memory_order_release);
   // Lock profiling.
   if (success && owner_ != nullptr && lock_profiling_threshold_ != 0) {
     // Do not abort on dex pc errors. This can easily happen when we want to dump a stack trace on
@@ -1039,7 +1041,7 @@
       case LockWord::kUnlocked: {
         // No ordering required for preceding lockword read, since we retest.
         LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0, lock_word.GCState()));
-        if (h_obj->CasLockWordWeakAcquire(lock_word, thin_locked)) {
+        if (h_obj->CasLockWord(lock_word, thin_locked, CASMode::kWeak, std::memory_order_acquire)) {
           AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */);
           return h_obj.Get();  // Success!
         }
@@ -1063,7 +1065,10 @@
               return h_obj.Get();  // Success!
             } else {
               // Use CAS to preserve the read barrier state.
-              if (h_obj->CasLockWordWeakRelaxed(lock_word, thin_locked)) {
+              if (h_obj->CasLockWord(lock_word,
+                                     thin_locked,
+                                     CASMode::kWeak,
+                                     std::memory_order_relaxed)) {
                 AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */);
                 return h_obj.Get();  // Success!
               }
@@ -1165,7 +1170,7 @@
             return true;
           } else {
             // Use CAS to preserve the read barrier state.
-            if (h_obj->CasLockWordWeakRelease(lock_word, new_lw)) {
+            if (h_obj->CasLockWord(lock_word, new_lw, CASMode::kWeak, std::memory_order_release)) {
               AtraceMonitorUnlock();
               // Success!
               return true;
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index d41a195..0f474d3 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -41,9 +41,11 @@
   ScopedFastNativeObjectAccess soa(env);
   ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
-  bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
-                                                                    expectedValue,
-                                                                    newValue);
+  bool success = obj->CasField32<false>(MemberOffset(offset),
+                                        expectedValue,
+                                        newValue,
+                                        CASMode::kStrong,
+                                        std::memory_order_seq_cst);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index b3a47c3..ce295aa 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -290,11 +290,6 @@
                      void* ucontext_ptr,
                      bool skip_frames) {
   // Historical note: This was disabled when running under Valgrind (b/18119146).
-  // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-  // check whether this test works with ASan.
-  if (kRunningOnMemoryTool) {
-    return;
-  }
 
   BacktraceMap* map = existing_map;
   std::unique_ptr<BacktraceMap> tmp_map;
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 6aeedd4..9e9c33c 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -138,7 +138,7 @@
   }
 
   void BuildArgArrayFromJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                ObjPtr<mirror::Object> receiver, jvalue* args)
+                                ObjPtr<mirror::Object> receiver, const jvalue* args)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     // Set receiver if non-null (method is not static)
     if (receiver != nullptr) {
@@ -492,7 +492,7 @@
 }
 
 JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
-                         jvalue* args) {
+                         const jvalue* args) {
   // We want to make sure that the stack is not within a small distance from the
   // protected region in case we are calling into a leaf function whose stack
   // check has been elided.
@@ -523,7 +523,7 @@
 }
 
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           jobject obj, jmethodID mid, jvalue* args) {
+                                           jobject obj, jmethodID mid, const jvalue* args) {
   // We want to make sure that the stack is not within a small distance from the
   // protected region in case we are calling into a leaf function whose stack
   // check has been elided.
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 4560a39..4391bcd 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -69,13 +69,13 @@
 JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
                          jobject obj,
                          jmethodID mid,
-                         jvalue* args)
+                         const jvalue* args)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
                                            jobject obj,
                                            jmethodID mid,
-                                           jvalue* args)
+                                           const jvalue* args)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index 54769f9..794ac19 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -339,9 +339,6 @@
 };
 
 TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
-  // SigQuit induces a dump. ASan isn't happy with libunwind reading memory.
-  TEST_DISABLED_FOR_MEMORY_TOOL();
-
   // The runtime needs to be started for the signal handler.
   Thread* self = Thread::Current();
 
diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h
index 1fe62e8..aac547e 100644
--- a/runtime/subtype_check.h
+++ b/runtime/subtype_check.h
@@ -542,15 +542,17 @@
                                                    int32_t new_value)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     if (Runtime::Current() != nullptr && Runtime::Current()->IsActiveTransaction()) {
-      return klass->template
-          CasFieldWeakSequentiallyConsistent32</*kTransactionActive*/true>(offset,
-                                                                           old_value,
-                                                                           new_value);
+      return klass->template CasField32</*kTransactionActive*/true>(offset,
+                                                                    old_value,
+                                                                    new_value,
+                                                                    CASMode::kWeak,
+                                                                    std::memory_order_seq_cst);
     } else {
-      return klass->template
-          CasFieldWeakSequentiallyConsistent32</*kTransactionActive*/false>(offset,
-                                                                            old_value,
-                                                                            new_value);
+      return klass->template CasField32</*kTransactionActive*/false>(offset,
+                                                                     old_value,
+                                                                     new_value,
+                                                                     CASMode::kWeak,
+                                                                     std::memory_order_seq_cst);
     }
   }
 
diff --git a/runtime/subtype_check_test.cc b/runtime/subtype_check_test.cc
index e297d0b..979fa42 100644
--- a/runtime/subtype_check_test.cc
+++ b/runtime/subtype_check_test.cc
@@ -86,9 +86,11 @@
   }
 
   template <bool kTransactionActive>
-  bool CasFieldWeakSequentiallyConsistent32(art::MemberOffset offset,
-                                            int32_t old_value,
-                                            int32_t new_value)
+  bool CasField32(art::MemberOffset offset,
+                  int32_t old_value,
+                  int32_t new_value,
+                  CASMode mode ATTRIBUTE_UNUSED,
+                  std::memory_order memory_order ATTRIBUTE_UNUSED)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     UNUSED(offset);
     if (old_value == GetField32Volatile(offset)) {
diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build
index 08987b5..3bb63ca 100644
--- a/test/004-ReferenceMap/build
+++ b/test/004-ReferenceMap/build
@@ -21,6 +21,5 @@
 # (see b/19467889)
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-  --dump-width=1000 ${DX_FLAGS} classes
+${DX} -JXmx256m --debug --dex --output=classes.dex ${DX_FLAGS} classes
 zip $TEST_NAME.jar classes.dex
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
index 08987b5..3bb63ca 100644
--- a/test/004-StackWalk/build
+++ b/test/004-StackWalk/build
@@ -21,6 +21,5 @@
 # (see b/19467889)
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-  --dump-width=1000 ${DX_FLAGS} classes
+${DX} -JXmx256m --debug --dex --output=classes.dex ${DX_FLAGS} classes
 zip $TEST_NAME.jar classes.dex
diff --git a/test/022-interface/build b/test/022-interface/build
index f6aad91..ab1c822 100644
--- a/test/022-interface/build
+++ b/test/022-interface/build
@@ -17,6 +17,6 @@
 # Stop if something fails.
 set -e
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+${DX} --debug --dex --output=classes.dex classes
 
 zip $TEST_NAME.jar classes.dex
diff --git a/test/091-override-package-private-method/build b/test/091-override-package-private-method/build
index ea12b3a..e5fa669 100755
--- a/test/091-override-package-private-method/build
+++ b/test/091-override-package-private-method/build
@@ -24,8 +24,8 @@
 mv classes/OverridePackagePrivateMethodSuper.class classes-ex
 
 if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex
   zip ${TEST_NAME}-ex.jar classes.dex
 fi
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
index 6fe73af..f24c5b2 100644
--- a/test/111-unresolvable-exception/build
+++ b/test/111-unresolvable-exception/build
@@ -22,6 +22,6 @@
 rm classes/TestException.class
 
 if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
   zip $TEST_NAME.jar classes.dex
 fi
diff --git a/test/113-multidex/build b/test/113-multidex/build
index f945563..4ad7cb9 100644
--- a/test/113-multidex/build
+++ b/test/113-multidex/build
@@ -29,9 +29,9 @@
 
 if [ ${NEED_DEX} = "true" ]; then
   # All except Main
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
 
   # Only Main
-  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+  ${DX} -JXmx256m --debug --dex --output=classes2.dex classes2
   zip $TEST_NAME.jar classes.dex classes2.dex
 fi
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
index cf19855..b4bb88d 100644
--- a/test/126-miranda-multidex/build
+++ b/test/126-miranda-multidex/build
@@ -29,9 +29,9 @@
 
 if [ ${NEED_DEX} = "true" ]; then
   # All except Main
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
 
   # Only Main
-  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+  ${DX} -JXmx256m --debug --dex --output=classes2.dex classes2
   zip $TEST_NAME.jar classes.dex classes2.dex
 fi
diff --git a/test/127-checker-secondarydex/build b/test/127-checker-secondarydex/build
index 712774f..c23b761 100755
--- a/test/127-checker-secondarydex/build
+++ b/test/127-checker-secondarydex/build
@@ -24,8 +24,8 @@
 mv classes/Super.class classes-ex
 
 if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex
   zip ${TEST_NAME}-ex.jar classes.dex
 fi
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index a91d348..985d273 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -54,15 +54,38 @@
 #endif
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) {
-  // Keep pausing.
-  struct timespec ts = { .tv_sec = 100, .tv_nsec = 0 };
-  printf("Going to sleep\n");
-  for (;;) {
-    // Use nanosleep since it gets to the system call quickly and doesn't
-    // have any points at which an unwind will fail.
-    nanosleep(&ts, nullptr);
+extern "C" JNIEXPORT jint JNICALL Java_Main_startSecondaryProcess(JNIEnv*, jclass) {
+#if __linux__
+  // Get our command line so that we can use it to start identical process.
+  std::string cmdline;  // null-separated and null-terminated arguments.
+  ReadFileToString("/proc/self/cmdline", &cmdline);
+  cmdline = cmdline + "--secondary" + '\0';  // Let the child know it is a helper.
+
+  // Split the string into individual arguments suitable for execv.
+  std::vector<char*> argv;
+  for (size_t i = 0; i < cmdline.size(); i += strlen(&cmdline[i]) + 1) {
+    argv.push_back(&cmdline[i]);
   }
+  argv.push_back(nullptr);  // Terminate the list.
+
+  pid_t pid = fork();
+  if (pid < 0) {
+    LOG(FATAL) << "Fork failed";
+  } else if (pid == 0) {
+    execv(argv[0], argv.data());
+    exit(1);
+  }
+  return pid;
+#else
+  return 0;
+#endif
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_sigstop(JNIEnv*, jclass) {
+#if __linux__
+  raise(SIGSTOP);
+#endif
+  return true;  // Prevent the compiler from tail-call optimizing this method away.
 }
 
 // Helper to look for a sequence in the stack trace.
@@ -107,12 +130,7 @@
 }
 #endif
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
-    JNIEnv*,
-    jobject,
-    jboolean,
-    jint,
-    jboolean) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jclass) {
 #if __linux__
   std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
   if (!bt->Unwind(0, nullptr)) {
@@ -128,10 +146,10 @@
   // only unique functions are being expected.
   // "mini-debug-info" does not include parameters to save space.
   std::vector<std::string> seq = {
-      "Java_Main_unwindInProcess",                   // This function.
-      "java.util.Arrays.binarySearch0",              // Framework method.
-      "Base.runBase",                                // Method in other dex file.
-      "Main.main"                                    // The Java entry method.
+      "Java_Main_unwindInProcess",       // This function.
+      "java.util.Arrays.binarySearch0",  // Framework method.
+      "Base.runTest",                    // Method in other dex file.
+      "Main.main"                        // The Java entry method.
   };
 
   bool result = CheckStack(bt.get(), seq);
@@ -150,8 +168,8 @@
 }
 
 #if __linux__
-static constexpr int kSleepTimeMicroseconds = 50000;            // 0.05 seconds
-static constexpr int kMaxTotalSleepTimeMicroseconds = 1000000;  // 1 second
+static constexpr int kSleepTimeMicroseconds = 50000;             // 0.05 seconds
+static constexpr int kMaxTotalSleepTimeMicroseconds = 10000000;  // 10 seconds
 
 // 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) {
@@ -183,17 +201,12 @@
 }
 #endif
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(
-    JNIEnv*,
-    jobject,
-    jboolean,
-    jint pid_int) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jclass, jint pid_int) {
 #if __linux__
   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)) {
+  // SEIZE is like ATTACH, but it does not stop the process (we let it stop itself).
+  if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
     // Were not able to attach, bad.
     printf("Failed to attach to other process.\n");
     PLOG(ERROR) << "Failed to attach.";
@@ -201,13 +214,12 @@
     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) {
+  if (signal != SIGSTOP) {
     LOG(WARNING) << "wait_for_sigstop failed.";
+    return JNI_FALSE;
   }
 
   std::unique_ptr<Backtrace> bt(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
@@ -224,10 +236,10 @@
     // See comment in unwindInProcess for non-exact stack matching.
     // "mini-debug-info" does not include parameters to save space.
     std::vector<std::string> seq = {
-        "Java_Main_sleep",                           // The sleep function in the other process.
-        "java.util.Arrays.binarySearch0",            // Framework method.
-        "Base.runBase",                              // Method in other dex file.
-        "Main.main"                                  // The Java entry method.
+        "Java_Main_sigstop",                // The stop function in the other process.
+        "java.util.Arrays.binarySearch0",   // Framework method.
+        "Base.runTest",                     // Method in other dex file.
+        "Main.main"                         // The Java entry method.
     };
 
     result = CheckStack(bt.get(), seq);
diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt
index 8db7853..eedae8f 100644
--- a/test/137-cfi/expected.txt
+++ b/test/137-cfi/expected.txt
@@ -1,2 +1,7 @@
 JNI_OnLoad called
+Unwind in process: PASS
 JNI_OnLoad called
+Unwind other process: PASS
+JNI_OnLoad called
+JNI_OnLoad called
+Unwind other process: PASS
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 9190b1c..4096b89 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -20,7 +20,7 @@
 # there will be JITed frames on the callstack (it synchronously JITs on first use).
 ${RUN} "$@" -Xcompiler-option --generate-debug-info \
   --runtime-option -Xjitthreshold:0 \
-  --args --full-signatures --args --test-local --args --test-remote
+  --args --test-local --args --test-remote
 return_status1=$?
 
 # Test with minimal compressed debugging information.
diff --git a/test/137-cfi/src-multidex/Base.java b/test/137-cfi/src-multidex/Base.java
index d3f8a56..986a3c2 100644
--- a/test/137-cfi/src-multidex/Base.java
+++ b/test/137-cfi/src-multidex/Base.java
@@ -15,8 +15,12 @@
  */
 
 public abstract class Base {
-  abstract public void runImpl();
-  public void runBase() {
-    runImpl();
+  public void runTest() throws Exception {
+    // Conditionally throw exception to prevent the compiler from inlining the code.
+    if (!this.getClass().getName().equals("Main")) {
+      throw new Exception("Who is calling?");
+    }
+    test();
   }
+  abstract public void test();
 }
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 9a2e352..5b32d8e 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -22,181 +22,68 @@
 
 public class Main extends Base implements Comparator<Main> {
   // Whether to test local unwinding.
-  private boolean testLocal;
+  private static boolean testLocal;
 
   // Unwinding another process, modelling debuggerd.
-  private boolean testRemote;
+  private static boolean testRemote;
 
   // We fork ourself to create the secondary process for remote unwinding.
-  private boolean secondary;
-
-  // Expect the symbols to contain full method signatures including parameters.
-  private boolean fullSignatures;
-
-  private boolean passed;
-
-  public Main(String[] args) throws Exception {
-      System.loadLibrary(args[0]);
-      for (String arg : args) {
-          if (arg.equals("--test-local")) {
-              testLocal = true;
-          }
-          if (arg.equals("--test-remote")) {
-              testRemote = true;
-          }
-          if (arg.equals("--secondary")) {
-              secondary = true;
-          }
-          if (arg.equals("--full-signatures")) {
-              fullSignatures = true;
-          }
-      }
-      if (!testLocal && !testRemote) {
-          System.out.println("No test selected.");
-      }
-  }
+  private static boolean secondary;
 
   public static void main(String[] args) throws Exception {
-      new Main(args).runBase();
-  }
-
-  public void runImpl() {
-      if (secondary) {
-          if (!testRemote) {
-              throw new RuntimeException("Should not be running secondary!");
+      System.loadLibrary(args[0]);
+      for (int i = 1; i < args.length; i++) {
+          if (args[i].equals("--test-local")) {
+              testLocal = true;
+          } else if (args[i].equals("--test-remote")) {
+              testRemote = true;
+          } else if (args[i].equals("--secondary")) {
+              secondary = true;
+          } else {
+              System.out.println("Unknown argument: " + args[i]);
+              System.exit(1);
           }
-          runSecondary();
-      } else {
-          runPrimary();
       }
+
+      // Call test() via base class to test unwinding through multidex.
+      new Main().runTest();
   }
 
-  private void runSecondary() {
-      foo();
-      throw new RuntimeException("Didn't expect to get back...");
-  }
-
-  private void runPrimary() {
-      // First do the in-process unwinding.
-      if (testLocal && !foo()) {
-          System.out.println("Unwinding self failed.");
-      }
-
-      if (!testRemote) {
-          // 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 until the forked process had time to run until its sleep phase.
-          BufferedReader lineReader;
-          try {
-              InputStreamReader stdout = new InputStreamReader(p.getInputStream(), "UTF-8");
-              lineReader = new BufferedReader(stdout);
-              while (!lineReader.readLine().contains("Going to sleep")) {
-              }
-          } catch (Exception e) {
-              throw new RuntimeException(e);
-          }
-
-          if (!unwindOtherProcess(fullSignatures, pid)) {
-              System.out.println("Unwinding other process failed.");
-
-              // In this case, log all the output.
-              // Note: this is potentially non-terminating code, if the secondary is totally stuck.
-              //       We rely on the run-test timeout infrastructure to terminate the primary in
-              //       such a case.
-              try {
-                  String tmp;
-                  System.out.println("Output from the secondary:");
-                  while ((tmp = lineReader.readLine()) != null) {
-                      System.out.println("Secondary: " + tmp);
-                  }
-              } catch (Exception e) {
-                  e.printStackTrace(System.out);
-              }
-          }
-
-          try {
-              lineReader.close();
-          } catch (Exception e) {
-              e.printStackTrace(System.out);
-          }
-      } finally {
-          // Kill the forked process if it is not already dead.
-          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.indexOf(",")));
-      } 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() {
-      // Call bar via Arrays.binarySearch.
-      // This tests that we can unwind from framework code.
+  public void test() {
+      // Call unwind() via Arrays.binarySearch to test unwinding through framework.
       Main[] array = { this, this, this };
       Arrays.binarySearch(array, 0, 3, this /* value */, this /* comparator */);
-      return passed;
   }
 
   public int compare(Main lhs, Main rhs) {
-      passed = bar(secondary);
+      unwind();
       // Returning "equal" ensures that we terminate search
-      // after first item and thus call bar() only once.
+      // after first item and thus call unwind() only once.
       return 0;
   }
 
-  public boolean bar(boolean b) {
-      if (b) {
-          return sleep(2, b, 1.0);
-      } else {
-          return unwindInProcess(fullSignatures, 1, b);
+  public void unwind() {
+      if (secondary) {
+          sigstop();  // This is helper child process. Stop and wait for unwinding.
+          return;     // Don't run the tests again in the secondary helper process.
+      }
+
+      if (testLocal) {
+          String result = unwindInProcess() ? "PASS" : "FAIL";
+          System.out.println("Unwind in process: " + result);
+      }
+
+      if (testRemote) {
+          // Start a secondary helper process. It will stop itself when it is ready.
+          int pid = startSecondaryProcess();
+          // Wait for the secondary process to stop and then unwind it remotely.
+          String result = unwindOtherProcess(pid) ? "PASS" : "FAIL";
+          System.out.println("Unwind other process: " + result);
       }
   }
 
-  // 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(boolean fullSignatures, int i, boolean b);
-  public native boolean unwindOtherProcess(boolean fullSignatures, int pid);
+  public static native int startSecondaryProcess();
+  public static native boolean sigstop();
+  public static native boolean unwindInProcess();
+  public static native boolean unwindOtherProcess(int pid);
 }
diff --git a/test/138-duplicate-classes-check2/build b/test/138-duplicate-classes-check2/build
index 76d535a..3ff15aa 100755
--- a/test/138-duplicate-classes-check2/build
+++ b/test/138-duplicate-classes-check2/build
@@ -25,8 +25,8 @@
 rm classes-ex/A.class
 
 if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
   zip ${TEST_NAME}.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex
   zip ${TEST_NAME}-ex.jar classes.dex
 fi
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 44ea0c9..58ffe04 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -36,32 +36,46 @@
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
-    if (m_name.compare("testLiveArgument") == 0) {
+    if (m_name.compare("$noinline$testLiveArgument") == 0) {
       found_method_ = true;
-      uint32_t value = 0;
-      CHECK(GetVReg(m, 0, kIntVReg, &value));
-      CHECK_EQ(value, 42u);
-    } else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) {
+      CHECK_EQ(CodeItemDataAccessor(m->DexInstructionData()).RegistersSize(), 3u);
+      CheckOptimizedOutRegLiveness(m, 1, kIntVReg, true, 42);
+
+      uint32_t value;
+      CHECK(GetVReg(m, 2, kReferenceVReg, &value));
+    } else if (m_name.compare("$noinline$testIntervalHole") == 0) {
+      found_method_ = true;
       uint32_t number_of_dex_registers =
           CodeItemDataAccessor(m->DexInstructionData()).RegistersSize();
       uint32_t dex_register_of_first_parameter = number_of_dex_registers - 2;
+      CheckOptimizedOutRegLiveness(m, dex_register_of_first_parameter, kIntVReg, true, 1);
+    } else if (m_name.compare("$noinline$testCodeSinking") == 0) {
       found_method_ = true;
-      uint32_t value = 0;
-      if (GetCurrentQuickFrame() != nullptr &&
-          GetCurrentOatQuickMethodHeader()->IsOptimized() &&
-          !Runtime::Current()->IsJavaDebuggable()) {
-        CHECK_EQ(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value), false);
-      } else {
-        CHECK(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value));
-        CHECK_EQ(value, 1u);
-      }
+      CheckOptimizedOutRegLiveness(m, 0, kReferenceVReg);
     }
 
     return true;
   }
 
-  // Value returned to Java to ensure the methods testSimpleVReg and testPairVReg
-  // have been found and tested.
+  void CheckOptimizedOutRegLiveness(ArtMethod* m,
+                                    uint32_t dex_reg,
+                                    VRegKind vreg_kind,
+                                    bool check_val = false,
+                                    uint32_t expected = 0) REQUIRES_SHARED(Locks::mutator_lock_) {
+    uint32_t value = 0;
+    if (GetCurrentQuickFrame() != nullptr &&
+        GetCurrentOatQuickMethodHeader()->IsOptimized() &&
+        !Runtime::Current()->IsJavaDebuggable()) {
+      CHECK_EQ(GetVReg(m, dex_reg, vreg_kind, &value), false);
+    } else {
+      CHECK(GetVReg(m, dex_reg, vreg_kind, &value));
+      if (check_val) {
+        CHECK_EQ(value, expected);
+      }
+    }
+  }
+
+  // Value returned to Java to ensure the required methods have been found and tested.
   bool found_method_ = false;
 };
 
diff --git a/test/466-get-live-vreg/src/Main.java b/test/466-get-live-vreg/src/Main.java
index 1903260..29a6901 100644
--- a/test/466-get-live-vreg/src/Main.java
+++ b/test/466-get-live-vreg/src/Main.java
@@ -18,9 +18,9 @@
   public Main() {
   }
 
-  static int testLiveArgument(int arg) {
+  static int $noinline$testLiveArgument(int arg1, Integer arg2) {
     doStaticNativeCallLiveVreg();
-    return arg;
+    return arg1 + arg2.intValue();
   }
 
   static void moveArgToCalleeSave() {
@@ -31,7 +31,7 @@
     }
   }
 
-  static void $opt$noinline$testIntervalHole(int arg, boolean test) {
+  static void $noinline$testIntervalHole(int arg, boolean test) {
     // Move the argument to callee save to ensure it is in
     // a readable register.
     moveArgToCalleeSave();
@@ -53,16 +53,18 @@
 
   public static void main(String[] args) {
     System.loadLibrary(args[0]);
-    if (testLiveArgument(staticField3) != staticField3) {
-      throw new Error("Expected " + staticField3);
+    if ($noinline$testLiveArgument(staticField3, Integer.valueOf(1)) != staticField3 + 1) {
+      throw new Error("Expected " + staticField3 + 1);
     }
 
-    if (testLiveArgument(staticField3) != staticField3) {
-      throw new Error("Expected " + staticField3);
+    if ($noinline$testLiveArgument(staticField3,Integer.valueOf(1)) != staticField3 + 1) {
+      throw new Error("Expected " + staticField3 + 1);
     }
 
     testWrapperIntervalHole(1, true);
     testWrapperIntervalHole(1, false);
+
+    $noinline$testCodeSinking(1);
   }
 
   // Wrapper method to avoid inlining, which affects liveness
@@ -70,12 +72,25 @@
   static void testWrapperIntervalHole(int arg, boolean test) {
     try {
       Thread.sleep(0);
-      $opt$noinline$testIntervalHole(arg, test);
+      $noinline$testIntervalHole(arg, test);
     } catch (Exception e) {
       throw new Error(e);
     }
   }
 
+  // The value of dex register which originally holded "Object[] o = new Object[1];" will not be
+  // live at the call to doStaticNativeCallLiveVreg after code sinking optimizizaion.
+  static void $noinline$testCodeSinking(int x) {
+    Object[] o = new Object[1];
+    o[0] = o;
+    doStaticNativeCallLiveVreg();
+    if (doThrow) {
+      throw new Error(o.toString());
+    }
+  }
+
+  static boolean doThrow;
+
   static int staticField1;
   static int staticField2;
   static int staticField3 = 42;
diff --git a/test/477-checker-bound-type/src/Main.java b/test/477-checker-bound-type/src/Main.java
index 2504ab2..237e4da 100644
--- a/test/477-checker-bound-type/src/Main.java
+++ b/test/477-checker-bound-type/src/Main.java
@@ -57,5 +57,79 @@
     }
   }
 
-  public static void main(String[] args) {  }
+  /// CHECK-START: void Main.boundTypeInLoop(int[]) licm (before)
+  /// CHECK-DAG: <<Param:l\d+>>     ParameterValue                        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>       Phi                                   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<BoundT:l\d+>>    BoundType [<<Param>>]                 loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArrayLength [<<BoundT>>]              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArrayGet                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArraySet                              loop:<<Loop>>      outer_loop:none
+
+  /// CHECK-START: void Main.boundTypeInLoop(int[]) licm (after)
+  /// CHECK-DAG: <<Param:l\d+>>     ParameterValue                        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>       Phi                                   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<BoundT:l\d+>>    BoundType [<<Param>>]                 loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArrayLength [<<BoundT>>]              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArrayGet                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArraySet                              loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                    BoundType
+
+  /// CHECK-START: void Main.boundTypeInLoop(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Param:l\d+>>     ParameterValue                        loop:none
+  /// CHECK-DAG: <<BoundTA:l\d+>>   BoundType [<<Param>>]                 loop:none
+  /// CHECK-DAG:                    ArrayLength [<<BoundTA>>]             loop:none
+  /// CHECK-DAG:                    ArrayGet                              loop:none
+  /// CHECK-DAG:                    ArraySet                              loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>       Phi                                   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<BoundT:l\d+>>    BoundType [<<Param>>]                 loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArrayLength [<<BoundT>>]              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArrayGet                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArraySet                              loop:<<Loop>>      outer_loop:none
+
+  /// CHECK-START: void Main.boundTypeInLoop(int[]) GVN$after_arch (after)
+  /// CHECK-DAG: <<Param:l\d+>>     ParameterValue                        loop:none
+  /// CHECK-DAG: <<BoundTA:l\d+>>   BoundType [<<Param>>]                 loop:none
+  /// CHECK-DAG:                    ArrayLength [<<BoundTA>>]             loop:none
+  /// CHECK-DAG:                    ArrayGet                              loop:none
+  /// CHECK-DAG:                    ArraySet                              loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>       Phi                                   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                    ArrayGet                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                    ArraySet                              loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                    BoundType
+  /// CHECK-NOT:                    ArrayLength
+  private static void boundTypeInLoop(int[] a) {
+    for (int i = 0; a != null && i < a.length; i++) {
+      a[i] += 1;
+    }
+  }
+
+  //  BoundType must not be hoisted by LICM, in this example it leads to ArrayLength being
+  //  hoisted as well which is invalid.
+  //
+  /// CHECK-START: void Main.BoundTypeNoLICM(java.lang.Object) licm (before)
+  /// CHECK-DAG: <<Param:l\d+>>   ParameterValue             loop:none
+  /// CHECK-DAG:                  SuspendCheck               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Bound1:l\d+>>  BoundType [<<Param>>]      loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG: <<Bound2:l\d+>>  BoundType [<<Bound1>>]     loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                  ArrayLength [<<Bound2>>]   loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-START: void Main.BoundTypeNoLICM(java.lang.Object) licm (after)
+  /// CHECK-DAG: <<Param:l\d+>>   ParameterValue             loop:none
+  /// CHECK-DAG:                  SuspendCheck               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Bound1:l\d+>>  BoundType [<<Param>>]      loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG: <<Bound2:l\d+>>  BoundType [<<Bound1>>]     loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                  ArrayLength [<<Bound2>>]   loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-NOT:                  BoundType                  loop:none
+  private static void BoundTypeNoLICM(Object obj) {
+    int i = 0;
+    while (obj instanceof int[]) {
+      int[] a = (int[])obj;
+      a[0] = 1;
+    }
+  }
+
+  public static void main(String[] args) { }
 }
diff --git a/test/530-checker-lse2/build b/test/530-checker-lse2/build
deleted file mode 100644
index d85147f..0000000
--- a/test/530-checker-lse2/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/565-checker-condition-liveness/info.txt b/test/565-checker-condition-liveness/info.txt
index 67b6ceb..e716c04 100644
--- a/test/565-checker-condition-liveness/info.txt
+++ b/test/565-checker-condition-liveness/info.txt
Binary files differ
diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java
index acfcecd..6b6619f 100644
--- a/test/565-checker-condition-liveness/src/Main.java
+++ b/test/565-checker-condition-liveness/src/Main.java
@@ -31,6 +31,82 @@
     return (arg > 5.0f) ? 0 : -1;
   }
 
+  /// CHECK-START: void Main.testThrowIntoCatchBlock(int, java.lang.Object, int[]) liveness (after)
+  /// CHECK-DAG:  <<IntArg:i\d+>>   ParameterValue        env_uses:[21,25]
+  /// CHECK-DAG:  <<RefArg:l\d+>>   ParameterValue        env_uses:[11,21,25]
+  /// CHECK-DAG:  <<Array:l\d+>>    ParameterValue        env_uses:[11,21,25]
+  /// CHECK-DAG:  <<Const1:i\d+>>   IntConstant 1         env_uses:[21,25]
+  /// CHECK-DAG:                    SuspendCheck          env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]]           liveness:10
+  /// CHECK-DAG:                    NullCheck             env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:20
+  /// CHECK-DAG:                    BoundsCheck           env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:24
+  /// CHECK-DAG:                    TryBoundary
+
+  /// CHECK-START-DEBUGGABLE: void Main.testThrowIntoCatchBlock(int, java.lang.Object, int[]) liveness (after)
+  /// CHECK-DAG:  <<IntArg:i\d+>>   ParameterValue        env_uses:[11,21,25]
+  /// CHECK-DAG:  <<RefArg:l\d+>>   ParameterValue        env_uses:[11,21,25]
+  /// CHECK-DAG:  <<Array:l\d+>>    ParameterValue        env_uses:[11,21,25]
+  /// CHECK-DAG:  <<Const1:i\d+>>   IntConstant 1         env_uses:[21,25]
+  /// CHECK-DAG:                    SuspendCheck          env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]]           liveness:10
+  /// CHECK-DAG:                    NullCheck             env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:20
+  /// CHECK-DAG:                    BoundsCheck           env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:24
+  /// CHECK-DAG:                    TryBoundary
+  //
+  // A value live at a throwing instruction in a try block may be copied by
+  // the exception handler to its location at the top of the catch block.
+  public static void testThrowIntoCatchBlock(int x, Object y, int[] a) {
+    try {
+      a[1] = x;
+    } catch (ArrayIndexOutOfBoundsException exception) {
+    }
+  }
+
+  /// CHECK-START: void Main.testBoundsCheck(int, java.lang.Object, int[]) liveness (after)
+  /// CHECK-DAG:  <<IntArg:i\d+>>   ParameterValue        env_uses:[]
+  /// CHECK-DAG:  <<RefArg:l\d+>>   ParameterValue        env_uses:[11,17,21]
+  /// CHECK-DAG:  <<Array:l\d+>>    ParameterValue        env_uses:[11,17,21]
+  /// CHECK-DAG:  <<Const1:i\d+>>   IntConstant 1         env_uses:[]
+  /// CHECK-DAG:                    SuspendCheck          env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]]           liveness:10
+  /// CHECK-DAG:                    NullCheck             env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:16
+  /// CHECK-DAG:                    BoundsCheck           env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:20
+
+  /// CHECK-START-DEBUGGABLE: void Main.testBoundsCheck(int, java.lang.Object, int[]) liveness (after)
+  /// CHECK-DAG:  <<IntArg:i\d+>>   ParameterValue        env_uses:[11,17,21]
+  /// CHECK-DAG:  <<RefArg:l\d+>>   ParameterValue        env_uses:[11,17,21]
+  /// CHECK-DAG:  <<Array:l\d+>>    ParameterValue        env_uses:[11,17,21]
+  /// CHECK-DAG:  <<Const1:i\d+>>   IntConstant 1         env_uses:[17,21]
+  /// CHECK-DAG:                    SuspendCheck          env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]]           liveness:10
+  /// CHECK-DAG:                    NullCheck             env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:16
+  /// CHECK-DAG:                    BoundsCheck           env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:20
+  public static void testBoundsCheck(int x, Object y, int[] a) {
+    a[1] = x;
+  }
+
+  /// CHECK-START: void Main.testDeoptimize(int, java.lang.Object, int[]) liveness (after)
+  /// CHECK-DAG:  <<IntArg:i\d+>>   ParameterValue        env_uses:[25]
+  /// CHECK-DAG:  <<RefArg:l\d+>>   ParameterValue        env_uses:[13,19,25]
+  /// CHECK-DAG:  <<Array:l\d+>>    ParameterValue        env_uses:[13,19,25]
+  /// CHECK-DAG:  <<Const0:i\d+>>   IntConstant 0         env_uses:[25]
+  /// CHECK-DAG:                    SuspendCheck          env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]]           liveness:12
+  /// CHECK-DAG:                    NullCheck             env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:18
+  /// CHECK-DAG:                    Deoptimize            env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:24
+
+  /// CHECK-START-DEBUGGABLE: void Main.testDeoptimize(int, java.lang.Object, int[]) liveness (after)
+  /// CHECK-DAG:  <<IntArg:i\d+>>   ParameterValue        env_uses:[13,19,25]
+  /// CHECK-DAG:  <<RefArg:l\d+>>   ParameterValue        env_uses:[13,19,25]
+  /// CHECK-DAG:  <<Array:l\d+>>    ParameterValue        env_uses:[13,19,25]
+  /// CHECK-DAG:  <<Const0:i\d+>>   IntConstant 0         env_uses:[19,25]
+  /// CHECK-DAG:                    SuspendCheck          env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]]           liveness:12
+  /// CHECK-DAG:                    NullCheck             env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:18
+  /// CHECK-DAG:                    Deoptimize            env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]]  liveness:24
+  //
+  // A value that's not live in compiled code may still be needed in interpreter,
+  // due to code motion, etc.
+  public static void testDeoptimize(int x, Object y, int[] a) {
+    a[0] = x;
+    a[1] = x;
+  }
+
+
   /// CHECK-START: void Main.main(java.lang.String[]) liveness (after)
   /// CHECK:         <<X:i\d+>>    ArrayLength uses:[<<UseInput:\d+>>]
   /// CHECK:         <<Y:i\d+>>    StaticFieldGet uses:[<<UseInput>>]
@@ -44,7 +120,15 @@
     if (x > y) {
       System.nanoTime();
     }
+
+    int val = 14;
+    int[] array = new int[2];
+    Integer intObj = Integer.valueOf(0);
+    testThrowIntoCatchBlock(val, intObj, array);
+    testBoundsCheck(val, intObj, array);
+    testDeoptimize(val, intObj, array);
   }
 
+
   public static int field = 42;
 }
diff --git a/test/565-checker-rotate/build b/test/565-checker-rotate/build
deleted file mode 100644
index 10ffcc5..0000000
--- a/test/565-checker-rotate/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2017 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/565-checker-rotate/smali/Main2.smali b/test/565-checker-rotate/smali/Main2.smali
new file mode 100644
index 0000000..ca5027e
--- /dev/null
+++ b/test/565-checker-rotate/smali/Main2.smali
@@ -0,0 +1,165 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LMain2;
+.super Ljava/lang/Object;
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) intrinsics_recognition (after)
+## CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+## CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+## CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+## CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+## CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+## CHECK-DAG:     <<Result:i\d+>>  Ror [<<Val>>,<<NegDist>>]
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
+## CHECK-NOT:                      InvokeStaticOrDirect
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) select_generator (after)
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+## CHECK-DAG:     <<SelVal:i\d+>>  Select [<<Zero>>,<<One>>,<<ArgVal>>]
+## CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+## CHECK-DAG:     <<Result:i\d+>>  Ror [<<SelVal>>,<<NegDist>>]
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) select_generator (after)
+## CHECK-NOT:                      Phi
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+## CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK-NOT:                      Select
+
+# Original java source
+#
+#     private static int rotateLeftBoolean(boolean value, int distance) {
+#       return Integer.rotateLeft(value ? 1 : 0, distance);
+#     }
+
+.method public static rotateLeftBoolean(ZI)I
+    .registers 3
+    .param p0, "value"    # Z
+    .param p1, "distance"    # I
+
+    .prologue
+    .line 66
+    if-eqz p0, :cond_8
+
+    const/4 v0, 0x1
+
+    :goto_3
+    invoke-static {v0, p1}, Ljava/lang/Integer;->rotateLeft(II)I
+
+    move-result v0
+
+    return v0
+
+    :cond_8
+    const/4 v0, 0x0
+
+    goto :goto_3
+.end method
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) intrinsics_recognition (after)
+## CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+## CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+## CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+## CHECK-DAG:                     Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier (after)
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+## CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+## CHECK-DAG:     <<Result:i\d+>>  Ror [<<Val>>,<<ArgDist>>]
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier (after)
+## CHECK-NOT:                      InvokeStaticOrDirect
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) select_generator (after)
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+## CHECK-DAG:     <<SelVal:i\d+>>  Select [<<Zero>>,<<One>>,<<ArgVal>>]
+## CHECK-DAG:     <<Result:i\d+>>  Ror [<<SelVal>>,<<ArgDist>>]
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) select_generator (after)
+## CHECK-NOT:                     Phi
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK:         <<ArgVal:z\d+>>  ParameterValue
+## CHECK:         <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+## CHECK-DAG:                      Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK-NOT:                     Select
+
+# Original java source:
+#
+#     private static int rotateRightBoolean(boolean value, int distance) {
+#       return Integer.rotateRight(value ? 1 : 0, distance);
+#     }
+
+.method public static rotateRightBoolean(ZI)I
+    .registers 3
+    .param p0, "value"    # Z
+    .param p1, "distance"    # I
+
+    .prologue
+    .line 219
+    if-eqz p0, :cond_8
+
+    const/4 v0, 0x1
+
+    :goto_3
+    invoke-static {v0, p1}, Ljava/lang/Integer;->rotateRight(II)I
+
+    move-result v0
+
+    return v0
+
+    :cond_8
+    const/4 v0, 0x0
+
+    goto :goto_3
+.end method
diff --git a/test/565-checker-rotate/src-art/Main.java b/test/565-checker-rotate/src-art/Main.java
new file mode 100644
index 0000000..b9e1315
--- /dev/null
+++ b/test/565-checker-rotate/src-art/Main.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+
+  private static Class main2;
+
+  /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftByte(byte value, int distance) {
+    return Integer.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftShort(short value, int distance) {
+    return Integer.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftChar(char value, int distance) {
+    return Integer.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftInt(int value, int distance) {
+    return Integer.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:j\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static long rotateLeftLong(long value, int distance) {
+    return Long.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightByte(byte value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightShort(short value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightChar(char value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightInt(int value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static long rotateRightLong(long value, int distance) {
+    return Long.rotateRight(value, distance);
+  }
+
+
+  /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftIntWithByteDistance(int value, byte distance) {
+    return Integer.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightIntWithByteDistance(int value, byte distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+
+  public static void testRotateLeftBoolean() throws Exception {
+    Method rotateLeftBoolean = main2.getMethod("rotateLeftBoolean", boolean.class, int.class);
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0, (int)rotateLeftBoolean.invoke(null, false, i));
+      expectEqualsInt(1 << i, (int)rotateLeftBoolean.invoke(null, true, i));
+    }
+  }
+
+  public static void testRotateLeftByte() {
+    expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 0));
+    expectEqualsInt(0x00000002, rotateLeftByte((byte)0x01, 1));
+    expectEqualsInt(0x80000000, rotateLeftByte((byte)0x01, 31));
+    expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 32));  // overshoot
+    expectEqualsInt(0xFFFFFF03, rotateLeftByte((byte)0x81, 1));
+    expectEqualsInt(0xFFFFFE07, rotateLeftByte((byte)0x81, 2));
+    expectEqualsInt(0x00000120, rotateLeftByte((byte)0x12, 4));
+    expectEqualsInt(0xFFFF9AFF, rotateLeftByte((byte)0x9A, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftByte((byte)0x0000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftByte((byte)0xFFFF, i));
+      expectEqualsInt((1 << j), rotateLeftByte((byte)0x0001, i));
+      expectEqualsInt((0x12 << j) | (0x12 >>> -j), rotateLeftByte((byte)0x12, i));
+    }
+  }
+
+  public static void testRotateLeftShort() {
+    expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 0));
+    expectEqualsInt(0x00000002, rotateLeftShort((short)0x0001, 1));
+    expectEqualsInt(0x80000000, rotateLeftShort((short)0x0001, 31));
+    expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 32));  // overshoot
+    expectEqualsInt(0xFFFF0003, rotateLeftShort((short)0x8001, 1));
+    expectEqualsInt(0xFFFE0007, rotateLeftShort((short)0x8001, 2));
+    expectEqualsInt(0x00012340, rotateLeftShort((short)0x1234, 4));
+    expectEqualsInt(0xFF9ABCFF, rotateLeftShort((short)0x9ABC, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftShort((short)0x0000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftShort((short)0xFFFF, i));
+      expectEqualsInt((1 << j), rotateLeftShort((short)0x0001, i));
+      expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftShort((short)0x1234, i));
+    }
+  }
+
+  public static void testRotateLeftChar() {
+    expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 0));
+    expectEqualsInt(0x00000002, rotateLeftChar((char)0x0001, 1));
+    expectEqualsInt(0x80000000, rotateLeftChar((char)0x0001, 31));
+    expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 32));  // overshoot
+    expectEqualsInt(0x00010002, rotateLeftChar((char)0x8001, 1));
+    expectEqualsInt(0x00020004, rotateLeftChar((char)0x8001, 2));
+    expectEqualsInt(0x00012340, rotateLeftChar((char)0x1234, 4));
+    expectEqualsInt(0x009ABC00, rotateLeftChar((char)0x9ABC, 8));
+    expectEqualsInt(0x00FF0000, rotateLeftChar((char)0xFF00, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftChar((char)0x0000, i));
+      expectEqualsInt((1 << j), rotateLeftChar((char)0x0001, i));
+      expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftChar((char)0x1234, i));
+    }
+  }
+
+  public static void testRotateLeftInt() {
+    expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 0));
+    expectEqualsInt(0x00000002, rotateLeftInt(0x00000001, 1));
+    expectEqualsInt(0x80000000, rotateLeftInt(0x00000001, 31));
+    expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 32));  // overshoot
+    expectEqualsInt(0x00000003, rotateLeftInt(0x80000001, 1));
+    expectEqualsInt(0x00000006, rotateLeftInt(0x80000001, 2));
+    expectEqualsInt(0x23456781, rotateLeftInt(0x12345678, 4));
+    expectEqualsInt(0xBCDEF09A, rotateLeftInt(0x9ABCDEF0, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftInt(0x00000000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftInt(0xFFFFFFFF, i));
+      expectEqualsInt(1 << j, rotateLeftInt(0x00000001, i));
+      expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j), rotateLeftInt(0x12345678, i));
+    }
+  }
+
+  public static void testRotateLeftLong() {
+    expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 0));
+    expectEqualsLong(0x0000000000000002L, rotateLeftLong(0x0000000000000001L, 1));
+    expectEqualsLong(0x8000000000000000L, rotateLeftLong(0x0000000000000001L, 63));
+    expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 64));  // overshoot
+    expectEqualsLong(0x0000000000000003L, rotateLeftLong(0x8000000000000001L, 1));
+    expectEqualsLong(0x0000000000000006L, rotateLeftLong(0x8000000000000001L, 2));
+    expectEqualsLong(0x23456789ABCDEF01L, rotateLeftLong(0x123456789ABCDEF0L, 4));
+    expectEqualsLong(0x3456789ABCDEF012L, rotateLeftLong(0x123456789ABCDEF0L, 8));
+    for (int i = 0; i < 70; i++) {  // overshoot a bit
+      int j = i & 63;
+      expectEqualsLong(0x0000000000000000L, rotateLeftLong(0x0000000000000000L, i));
+      expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateLeftLong(0xFFFFFFFFFFFFFFFFL, i));
+      expectEqualsLong(1L << j, rotateLeftLong(0x0000000000000001, i));
+      expectEqualsLong((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j),
+                       rotateLeftLong(0x123456789ABCDEF0L, i));
+    }
+  }
+
+  public static void testRotateRightBoolean() throws Exception {
+    Method rotateRightBoolean = main2.getMethod("rotateRightBoolean", boolean.class, int.class);
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0, (int)rotateRightBoolean.invoke(null, false, i));
+      expectEqualsInt(1 << (32 - i), (int)rotateRightBoolean.invoke(null, true, i));
+    }
+  }
+
+  public static void testRotateRightByte() {
+    expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 0));
+    expectEqualsInt(0x7FFFFFC0, rotateRightByte((byte)0x80, 1));
+    expectEqualsInt(0xFFFFFF01, rotateRightByte((byte)0x80, 31));
+    expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 32));  // overshoot
+    expectEqualsInt(0xFFFFFFC0, rotateRightByte((byte)0x81, 1));
+    expectEqualsInt(0x7FFFFFE0, rotateRightByte((byte)0x81, 2));
+    expectEqualsInt(0x20000001, rotateRightByte((byte)0x12, 4));
+    expectEqualsInt(0x9AFFFFFF, rotateRightByte((byte)0x9A, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightByte((byte)0x00, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightByte((byte)0xFF, i));
+      expectEqualsInt(1 << (32 - j), rotateRightByte((byte)0x01, i));
+      expectEqualsInt((0x12 >>> j) | (0x12 << -j), rotateRightByte((byte)0x12, i));
+    }
+  }
+
+  public static void testRotateRightShort() {
+    expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 0));
+    expectEqualsInt(0x7FFFC000, rotateRightShort((short)0x8000, 1));
+    expectEqualsInt(0xFFFF0001, rotateRightShort((short)0x8000, 31));
+    expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 32));  // overshoot
+    expectEqualsInt(0xFFFFC000, rotateRightShort((short)0x8001, 1));
+    expectEqualsInt(0x7FFFE000, rotateRightShort((short)0x8001, 2));
+    expectEqualsInt(0x40000123, rotateRightShort((short)0x1234, 4));
+    expectEqualsInt(0xBCFFFF9A, rotateRightShort((short)0x9ABC, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightShort((short)0x0000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightShort((short)0xFFFF, i));
+      expectEqualsInt(1 << (32 - j), rotateRightShort((short)0x0001, i));
+      expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightShort((short)0x1234, i));
+    }
+  }
+
+  public static void testRotateRightChar() {
+    expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 0));
+    expectEqualsInt(0x00004000, rotateRightChar((char)0x8000, 1));
+    expectEqualsInt(0x00010000, rotateRightChar((char)0x8000, 31));
+    expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 32));  // overshoot
+    expectEqualsInt(0x80004000, rotateRightChar((char)0x8001, 1));
+    expectEqualsInt(0x40002000, rotateRightChar((char)0x8001, 2));
+    expectEqualsInt(0x40000123, rotateRightChar((char)0x1234, 4));
+    expectEqualsInt(0xBC00009A, rotateRightChar((char)0x9ABC, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightChar((char)0x0000, i));
+      expectEqualsInt(1 << (32 - j), rotateRightChar((char)0x0001, i));
+      expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightChar((char)0x1234, i));
+    }
+  }
+
+  public static void testRotateRightInt() {
+    expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 0));
+    expectEqualsInt(0x40000000, rotateRightInt(0x80000000, 1));
+    expectEqualsInt(0x00000001, rotateRightInt(0x80000000, 31));
+    expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 32));  // overshoot
+    expectEqualsInt(0xC0000000, rotateRightInt(0x80000001, 1));
+    expectEqualsInt(0x60000000, rotateRightInt(0x80000001, 2));
+    expectEqualsInt(0x81234567, rotateRightInt(0x12345678, 4));
+    expectEqualsInt(0xF09ABCDE, rotateRightInt(0x9ABCDEF0, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightInt(0x00000000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightInt(0xFFFFFFFF, i));
+      expectEqualsInt(0x80000000 >>> j, rotateRightInt(0x80000000, i));
+      expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j), rotateRightInt(0x12345678, i));
+    }
+  }
+
+  public static void testRotateRightLong() {
+    expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 0));
+    expectEqualsLong(0x4000000000000000L, rotateRightLong(0x8000000000000000L, 1));
+    expectEqualsLong(0x0000000000000001L, rotateRightLong(0x8000000000000000L, 63));
+    expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 64));  // overshoot
+    expectEqualsLong(0xC000000000000000L, rotateRightLong(0x8000000000000001L, 1));
+    expectEqualsLong(0x6000000000000000L, rotateRightLong(0x8000000000000001L, 2));
+    expectEqualsLong(0x0123456789ABCDEFL, rotateRightLong(0x123456789ABCDEF0L, 4));
+    expectEqualsLong(0xF0123456789ABCDEL, rotateRightLong(0x123456789ABCDEF0L, 8));
+    for (int i = 0; i < 70; i++) {  // overshoot a bit
+      int j = i & 63;
+      expectEqualsLong(0x0000000000000000L, rotateRightLong(0x0000000000000000L, i));
+      expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateRightLong(0xFFFFFFFFFFFFFFFFL, i));
+      expectEqualsLong(0x8000000000000000L >>> j, rotateRightLong(0x8000000000000000L, i));
+      expectEqualsLong((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j),
+                       rotateRightLong(0x123456789ABCDEF0L, i));
+    }
+  }
+
+
+  public static void testRotateLeftIntWithByteDistance() {
+    expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)0));
+    expectEqualsInt(0x00000002, rotateLeftIntWithByteDistance(0x00000001, (byte)1));
+    expectEqualsInt(0x80000000, rotateLeftIntWithByteDistance(0x00000001, (byte)31));
+    expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)32));  // overshoot
+    expectEqualsInt(0x00000003, rotateLeftIntWithByteDistance(0x80000001, (byte)1));
+    expectEqualsInt(0x00000006, rotateLeftIntWithByteDistance(0x80000001, (byte)2));
+    expectEqualsInt(0x23456781, rotateLeftIntWithByteDistance(0x12345678, (byte)4));
+    expectEqualsInt(0xBCDEF09A, rotateLeftIntWithByteDistance(0x9ABCDEF0, (byte)8));
+    for (byte i = 0; i < 40; i++) {  // overshoot a bit
+      byte j = (byte)(i & 31);
+      expectEqualsInt(0x00000000, rotateLeftIntWithByteDistance(0x00000000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftIntWithByteDistance(0xFFFFFFFF, i));
+      expectEqualsInt(1 << j, rotateLeftIntWithByteDistance(0x00000001, i));
+      expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j),
+                      rotateLeftIntWithByteDistance(0x12345678, i));
+    }
+  }
+
+  public static void testRotateRightIntWithByteDistance() {
+    expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)0));
+    expectEqualsInt(0x40000000, rotateRightIntWithByteDistance(0x80000000, (byte)1));
+    expectEqualsInt(0x00000001, rotateRightIntWithByteDistance(0x80000000, (byte)31));
+    expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)32));  // overshoot
+    expectEqualsInt(0xC0000000, rotateRightIntWithByteDistance(0x80000001, (byte)1));
+    expectEqualsInt(0x60000000, rotateRightIntWithByteDistance(0x80000001, (byte)2));
+    expectEqualsInt(0x81234567, rotateRightIntWithByteDistance(0x12345678, (byte)4));
+    expectEqualsInt(0xF09ABCDE, rotateRightIntWithByteDistance(0x9ABCDEF0, (byte)8));
+    for (byte i = 0; i < 40; i++) {  // overshoot a bit
+      byte j = (byte)(i & 31);
+      expectEqualsInt(0x00000000, rotateRightIntWithByteDistance(0x00000000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightIntWithByteDistance(0xFFFFFFFF, i));
+      expectEqualsInt(0x80000000 >>> j, rotateRightIntWithByteDistance(0x80000000, i));
+      expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j),
+                      rotateRightIntWithByteDistance(0x12345678, i));
+    }
+  }
+
+
+  public static void main(String args[]) throws Exception {
+    main2 = Class.forName("Main2");
+
+    testRotateLeftBoolean();
+    testRotateLeftByte();
+    testRotateLeftShort();
+    testRotateLeftChar();
+    testRotateLeftInt();
+    testRotateLeftLong();
+
+    testRotateRightBoolean();
+    testRotateRightByte();
+    testRotateRightShort();
+    testRotateRightChar();
+    testRotateRightInt();
+    testRotateRightLong();
+
+    // Also exercise distance values with types other than int.
+    testRotateLeftIntWithByteDistance();
+    testRotateRightIntWithByteDistance();
+
+    System.out.println("passed");
+  }
+
+
+  private static void expectEqualsInt(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEqualsLong(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/565-checker-rotate/src/Main.java b/test/565-checker-rotate/src/Main.java
index eb0e868..79b8555 100644
--- a/test/565-checker-rotate/src/Main.java
+++ b/test/565-checker-rotate/src/Main.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,623 +14,9 @@
  * limitations under the License.
  */
 
+// This file is just for running on the RI as the test is ART specific.
 public class Main {
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
-  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
-  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
-  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
-  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<Val>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after)
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
-  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
-  /// CHECK-DAG:     <<SelVal:i\d+>>  Select [<<Zero>>,<<One>>,<<ArgVal>>]
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<SelVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after)
-  /// CHECK-NOT:                      Phi
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
-  /// CHECK-NOT:                      Select
-
-  private static int rotateLeftBoolean(boolean value, int distance) {
-    return Integer.rotateLeft(value ? 1 : 0, distance);
-  }
-
-  /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateLeftByte(byte value, int distance) {
-    return Integer.rotateLeft(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateLeftShort(short value, int distance) {
-    return Integer.rotateLeft(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateLeftChar(char value, int distance) {
-    return Integer.rotateLeft(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateLeftInt(int value, int distance) {
-    return Integer.rotateLeft(value, distance);
-  }
-
-  /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:j\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static long rotateLeftLong(long value, int distance) {
-    return Long.rotateLeft(value, distance);
-  }
-
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
-  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
-  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                     Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
-  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
-  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<Val>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after)
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
-  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
-  /// CHECK-DAG:     <<SelVal:i\d+>>  Select [<<Zero>>,<<One>>,<<ArgVal>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<SelVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after)
-  /// CHECK-NOT:                     Phi
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
-  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
-  /// CHECK-NOT:                     Select
-
-  private static int rotateRightBoolean(boolean value, int distance) {
-    return Integer.rotateRight(value ? 1 : 0, distance);
-  }
-
-  /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateRightByte(byte value, int distance) {
-    return Integer.rotateRight(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateRightShort(short value, int distance) {
-    return Integer.rotateRight(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateRightChar(char value, int distance) {
-    return Integer.rotateRight(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateRightInt(int value, int distance) {
-    return Integer.rotateRight(value, distance);
-  }
-
-  /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:j\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static long rotateRightLong(long value, int distance) {
-    return Long.rotateRight(value, distance);
-  }
-
-
-  /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
-  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateLeftIntWithByteDistance(int value, byte distance) {
-    return Integer.rotateLeft(value, distance);
-  }
-
-  /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
-  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
-  /// CHECK:         <<ArgDist:b\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
-  /// CHECK-DAG:                      Return [<<Result>>]
-
-  /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
-  /// CHECK-NOT:                      InvokeStaticOrDirect
-
-  private static int rotateRightIntWithByteDistance(int value, byte distance) {
-    return Integer.rotateRight(value, distance);
-  }
-
-
-  public static void testRotateLeftBoolean() {
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0, rotateLeftBoolean(false, i));
-      expectEqualsInt(1 << i, rotateLeftBoolean(true, i));
-    }
-  }
-
-  public static void testRotateLeftByte() {
-    expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 0));
-    expectEqualsInt(0x00000002, rotateLeftByte((byte)0x01, 1));
-    expectEqualsInt(0x80000000, rotateLeftByte((byte)0x01, 31));
-    expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 32));  // overshoot
-    expectEqualsInt(0xFFFFFF03, rotateLeftByte((byte)0x81, 1));
-    expectEqualsInt(0xFFFFFE07, rotateLeftByte((byte)0x81, 2));
-    expectEqualsInt(0x00000120, rotateLeftByte((byte)0x12, 4));
-    expectEqualsInt(0xFFFF9AFF, rotateLeftByte((byte)0x9A, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateLeftByte((byte)0x0000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateLeftByte((byte)0xFFFF, i));
-      expectEqualsInt((1 << j), rotateLeftByte((byte)0x0001, i));
-      expectEqualsInt((0x12 << j) | (0x12 >>> -j), rotateLeftByte((byte)0x12, i));
-    }
-  }
-
-  public static void testRotateLeftShort() {
-    expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 0));
-    expectEqualsInt(0x00000002, rotateLeftShort((short)0x0001, 1));
-    expectEqualsInt(0x80000000, rotateLeftShort((short)0x0001, 31));
-    expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 32));  // overshoot
-    expectEqualsInt(0xFFFF0003, rotateLeftShort((short)0x8001, 1));
-    expectEqualsInt(0xFFFE0007, rotateLeftShort((short)0x8001, 2));
-    expectEqualsInt(0x00012340, rotateLeftShort((short)0x1234, 4));
-    expectEqualsInt(0xFF9ABCFF, rotateLeftShort((short)0x9ABC, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateLeftShort((short)0x0000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateLeftShort((short)0xFFFF, i));
-      expectEqualsInt((1 << j), rotateLeftShort((short)0x0001, i));
-      expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftShort((short)0x1234, i));
-    }
-  }
-
-  public static void testRotateLeftChar() {
-    expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 0));
-    expectEqualsInt(0x00000002, rotateLeftChar((char)0x0001, 1));
-    expectEqualsInt(0x80000000, rotateLeftChar((char)0x0001, 31));
-    expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 32));  // overshoot
-    expectEqualsInt(0x00010002, rotateLeftChar((char)0x8001, 1));
-    expectEqualsInt(0x00020004, rotateLeftChar((char)0x8001, 2));
-    expectEqualsInt(0x00012340, rotateLeftChar((char)0x1234, 4));
-    expectEqualsInt(0x009ABC00, rotateLeftChar((char)0x9ABC, 8));
-    expectEqualsInt(0x00FF0000, rotateLeftChar((char)0xFF00, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateLeftChar((char)0x0000, i));
-      expectEqualsInt((1 << j), rotateLeftChar((char)0x0001, i));
-      expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftChar((char)0x1234, i));
-    }
-  }
-
-  public static void testRotateLeftInt() {
-    expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 0));
-    expectEqualsInt(0x00000002, rotateLeftInt(0x00000001, 1));
-    expectEqualsInt(0x80000000, rotateLeftInt(0x00000001, 31));
-    expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 32));  // overshoot
-    expectEqualsInt(0x00000003, rotateLeftInt(0x80000001, 1));
-    expectEqualsInt(0x00000006, rotateLeftInt(0x80000001, 2));
-    expectEqualsInt(0x23456781, rotateLeftInt(0x12345678, 4));
-    expectEqualsInt(0xBCDEF09A, rotateLeftInt(0x9ABCDEF0, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateLeftInt(0x00000000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateLeftInt(0xFFFFFFFF, i));
-      expectEqualsInt(1 << j, rotateLeftInt(0x00000001, i));
-      expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j), rotateLeftInt(0x12345678, i));
-    }
-  }
-
-  public static void testRotateLeftLong() {
-    expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 0));
-    expectEqualsLong(0x0000000000000002L, rotateLeftLong(0x0000000000000001L, 1));
-    expectEqualsLong(0x8000000000000000L, rotateLeftLong(0x0000000000000001L, 63));
-    expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 64));  // overshoot
-    expectEqualsLong(0x0000000000000003L, rotateLeftLong(0x8000000000000001L, 1));
-    expectEqualsLong(0x0000000000000006L, rotateLeftLong(0x8000000000000001L, 2));
-    expectEqualsLong(0x23456789ABCDEF01L, rotateLeftLong(0x123456789ABCDEF0L, 4));
-    expectEqualsLong(0x3456789ABCDEF012L, rotateLeftLong(0x123456789ABCDEF0L, 8));
-    for (int i = 0; i < 70; i++) {  // overshoot a bit
-      int j = i & 63;
-      expectEqualsLong(0x0000000000000000L, rotateLeftLong(0x0000000000000000L, i));
-      expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateLeftLong(0xFFFFFFFFFFFFFFFFL, i));
-      expectEqualsLong(1L << j, rotateLeftLong(0x0000000000000001, i));
-      expectEqualsLong((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j),
-                       rotateLeftLong(0x123456789ABCDEF0L, i));
-    }
-  }
-
-  public static void testRotateRightBoolean() {
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0, rotateRightBoolean(false, i));
-      expectEqualsInt(1 << (32 - i), rotateRightBoolean(true, i));
-    }
-  }
-
-  public static void testRotateRightByte() {
-    expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 0));
-    expectEqualsInt(0x7FFFFFC0, rotateRightByte((byte)0x80, 1));
-    expectEqualsInt(0xFFFFFF01, rotateRightByte((byte)0x80, 31));
-    expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 32));  // overshoot
-    expectEqualsInt(0xFFFFFFC0, rotateRightByte((byte)0x81, 1));
-    expectEqualsInt(0x7FFFFFE0, rotateRightByte((byte)0x81, 2));
-    expectEqualsInt(0x20000001, rotateRightByte((byte)0x12, 4));
-    expectEqualsInt(0x9AFFFFFF, rotateRightByte((byte)0x9A, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateRightByte((byte)0x00, i));
-      expectEqualsInt(0xFFFFFFFF, rotateRightByte((byte)0xFF, i));
-      expectEqualsInt(1 << (32 - j), rotateRightByte((byte)0x01, i));
-      expectEqualsInt((0x12 >>> j) | (0x12 << -j), rotateRightByte((byte)0x12, i));
-    }
-  }
-
-  public static void testRotateRightShort() {
-    expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 0));
-    expectEqualsInt(0x7FFFC000, rotateRightShort((short)0x8000, 1));
-    expectEqualsInt(0xFFFF0001, rotateRightShort((short)0x8000, 31));
-    expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 32));  // overshoot
-    expectEqualsInt(0xFFFFC000, rotateRightShort((short)0x8001, 1));
-    expectEqualsInt(0x7FFFE000, rotateRightShort((short)0x8001, 2));
-    expectEqualsInt(0x40000123, rotateRightShort((short)0x1234, 4));
-    expectEqualsInt(0xBCFFFF9A, rotateRightShort((short)0x9ABC, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateRightShort((short)0x0000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateRightShort((short)0xFFFF, i));
-      expectEqualsInt(1 << (32 - j), rotateRightShort((short)0x0001, i));
-      expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightShort((short)0x1234, i));
-    }
-  }
-
-  public static void testRotateRightChar() {
-    expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 0));
-    expectEqualsInt(0x00004000, rotateRightChar((char)0x8000, 1));
-    expectEqualsInt(0x00010000, rotateRightChar((char)0x8000, 31));
-    expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 32));  // overshoot
-    expectEqualsInt(0x80004000, rotateRightChar((char)0x8001, 1));
-    expectEqualsInt(0x40002000, rotateRightChar((char)0x8001, 2));
-    expectEqualsInt(0x40000123, rotateRightChar((char)0x1234, 4));
-    expectEqualsInt(0xBC00009A, rotateRightChar((char)0x9ABC, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateRightChar((char)0x0000, i));
-      expectEqualsInt(1 << (32 - j), rotateRightChar((char)0x0001, i));
-      expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightChar((char)0x1234, i));
-    }
-  }
-
-  public static void testRotateRightInt() {
-    expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 0));
-    expectEqualsInt(0x40000000, rotateRightInt(0x80000000, 1));
-    expectEqualsInt(0x00000001, rotateRightInt(0x80000000, 31));
-    expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 32));  // overshoot
-    expectEqualsInt(0xC0000000, rotateRightInt(0x80000001, 1));
-    expectEqualsInt(0x60000000, rotateRightInt(0x80000001, 2));
-    expectEqualsInt(0x81234567, rotateRightInt(0x12345678, 4));
-    expectEqualsInt(0xF09ABCDE, rotateRightInt(0x9ABCDEF0, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEqualsInt(0x00000000, rotateRightInt(0x00000000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateRightInt(0xFFFFFFFF, i));
-      expectEqualsInt(0x80000000 >>> j, rotateRightInt(0x80000000, i));
-      expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j), rotateRightInt(0x12345678, i));
-    }
-  }
-
-  public static void testRotateRightLong() {
-    expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 0));
-    expectEqualsLong(0x4000000000000000L, rotateRightLong(0x8000000000000000L, 1));
-    expectEqualsLong(0x0000000000000001L, rotateRightLong(0x8000000000000000L, 63));
-    expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 64));  // overshoot
-    expectEqualsLong(0xC000000000000000L, rotateRightLong(0x8000000000000001L, 1));
-    expectEqualsLong(0x6000000000000000L, rotateRightLong(0x8000000000000001L, 2));
-    expectEqualsLong(0x0123456789ABCDEFL, rotateRightLong(0x123456789ABCDEF0L, 4));
-    expectEqualsLong(0xF0123456789ABCDEL, rotateRightLong(0x123456789ABCDEF0L, 8));
-    for (int i = 0; i < 70; i++) {  // overshoot a bit
-      int j = i & 63;
-      expectEqualsLong(0x0000000000000000L, rotateRightLong(0x0000000000000000L, i));
-      expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateRightLong(0xFFFFFFFFFFFFFFFFL, i));
-      expectEqualsLong(0x8000000000000000L >>> j, rotateRightLong(0x8000000000000000L, i));
-      expectEqualsLong((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j),
-                       rotateRightLong(0x123456789ABCDEF0L, i));
-    }
-  }
-
-
-  public static void testRotateLeftIntWithByteDistance() {
-    expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)0));
-    expectEqualsInt(0x00000002, rotateLeftIntWithByteDistance(0x00000001, (byte)1));
-    expectEqualsInt(0x80000000, rotateLeftIntWithByteDistance(0x00000001, (byte)31));
-    expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)32));  // overshoot
-    expectEqualsInt(0x00000003, rotateLeftIntWithByteDistance(0x80000001, (byte)1));
-    expectEqualsInt(0x00000006, rotateLeftIntWithByteDistance(0x80000001, (byte)2));
-    expectEqualsInt(0x23456781, rotateLeftIntWithByteDistance(0x12345678, (byte)4));
-    expectEqualsInt(0xBCDEF09A, rotateLeftIntWithByteDistance(0x9ABCDEF0, (byte)8));
-    for (byte i = 0; i < 40; i++) {  // overshoot a bit
-      byte j = (byte)(i & 31);
-      expectEqualsInt(0x00000000, rotateLeftIntWithByteDistance(0x00000000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateLeftIntWithByteDistance(0xFFFFFFFF, i));
-      expectEqualsInt(1 << j, rotateLeftIntWithByteDistance(0x00000001, i));
-      expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j),
-                      rotateLeftIntWithByteDistance(0x12345678, i));
-    }
-  }
-
-  public static void testRotateRightIntWithByteDistance() {
-    expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)0));
-    expectEqualsInt(0x40000000, rotateRightIntWithByteDistance(0x80000000, (byte)1));
-    expectEqualsInt(0x00000001, rotateRightIntWithByteDistance(0x80000000, (byte)31));
-    expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)32));  // overshoot
-    expectEqualsInt(0xC0000000, rotateRightIntWithByteDistance(0x80000001, (byte)1));
-    expectEqualsInt(0x60000000, rotateRightIntWithByteDistance(0x80000001, (byte)2));
-    expectEqualsInt(0x81234567, rotateRightIntWithByteDistance(0x12345678, (byte)4));
-    expectEqualsInt(0xF09ABCDE, rotateRightIntWithByteDistance(0x9ABCDEF0, (byte)8));
-    for (byte i = 0; i < 40; i++) {  // overshoot a bit
-      byte j = (byte)(i & 31);
-      expectEqualsInt(0x00000000, rotateRightIntWithByteDistance(0x00000000, i));
-      expectEqualsInt(0xFFFFFFFF, rotateRightIntWithByteDistance(0xFFFFFFFF, i));
-      expectEqualsInt(0x80000000 >>> j, rotateRightIntWithByteDistance(0x80000000, i));
-      expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j),
-                      rotateRightIntWithByteDistance(0x12345678, i));
-    }
-  }
-
-
   public static void main(String args[]) {
-    testRotateLeftBoolean();
-    testRotateLeftByte();
-    testRotateLeftShort();
-    testRotateLeftChar();
-    testRotateLeftInt();
-    testRotateLeftLong();
-
-    testRotateRightBoolean();
-    testRotateRightByte();
-    testRotateRightShort();
-    testRotateRightChar();
-    testRotateRightInt();
-    testRotateRightLong();
-
-    // Also exercise distance values with types other than int.
-    testRotateLeftIntWithByteDistance();
-    testRotateRightIntWithByteDistance();
-
     System.out.println("passed");
   }
-
-
-  private static void expectEqualsInt(int expected, int result) {
-    if (expected != result) {
-      throw new Error("Expected: " + expected + ", found: " + result);
-    }
-  }
-
-  private static void expectEqualsLong(long expected, long result) {
-    if (expected != result) {
-      throw new Error("Expected: " + expected + ", found: " + result);
-    }
-  }
-}
+}
\ No newline at end of file
diff --git a/test/569-checker-pattern-replacement/build b/test/569-checker-pattern-replacement/build
deleted file mode 100644
index d85147f..0000000
--- a/test/569-checker-pattern-replacement/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/583-checker-zero/build b/test/583-checker-zero/build
deleted file mode 100644
index d85147f..0000000
--- a/test/583-checker-zero/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/639-checker-code-sinking/src/Main.java b/test/639-checker-code-sinking/src/Main.java
index a1c30f7..8efac92 100644
--- a/test/639-checker-code-sinking/src/Main.java
+++ b/test/639-checker-code-sinking/src/Main.java
@@ -343,6 +343,37 @@
     }
   }
 
+  static native void doStaticNativeCallLiveVreg();
+
+  //  Test ensures that 'o' has been moved into the if despite the InvokeStaticOrDirect.
+  //
+  /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (before)
+  /// CHECK: <<Int1:i\d+>>        IntConstant 1
+  /// CHECK: <<Int0:i\d+>>        IntConstant 0
+  /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:java.lang.Object[]
+  /// CHECK-NOT:                  begin_block
+  /// CHECK:                      NewArray [<<LoadClass>>,<<Int1>>]
+  /// CHECK:                      If
+  /// CHECK:                      begin_block
+  /// CHECK:                      Throw
+
+  /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (after)
+  /// CHECK: <<Int1:i\d+>>        IntConstant 1
+  /// CHECK: <<Int0:i\d+>>        IntConstant 0
+  /// CHECK:                      If
+  /// CHECK:                      begin_block
+  /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:java.lang.Object[]
+  /// CHECK:                      NewArray [<<LoadClass>>,<<Int1>>]
+  /// CHECK:                      Throw
+  static void testSinkingOverInvoke() {
+    Object[] o = new Object[1];
+    o[0] = o;
+    doStaticNativeCallLiveVreg();
+    if (doThrow) {
+      throw new Error(o.toString());
+    }
+  }
+
   public String $opt$noinline$toString() {
     return "" + intField;
   }
diff --git a/test/646-checker-hadd-alt-char/build b/test/646-checker-hadd-alt-char/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-alt-char/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-alt-char/src/Main.java b/test/646-checker-hadd-alt-char/src/Main.java
index 2a1382d..79904ce 100644
--- a/test/646-checker-hadd-alt-char/src/Main.java
+++ b/test/646-checker-hadd-alt-char/src/Main.java
@@ -58,7 +58,7 @@
   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>  Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
@@ -120,7 +120,7 @@
   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>]              loop:<<Loop>>      outer_loop:none
diff --git a/test/646-checker-hadd-alt-short/build b/test/646-checker-hadd-alt-short/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-alt-short/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-alt-short/src/Main.java b/test/646-checker-hadd-alt-short/src/Main.java
index 4035b97..1ecb1d82 100644
--- a/test/646-checker-hadd-alt-short/src/Main.java
+++ b/test/646-checker-hadd-alt-short/src/Main.java
@@ -58,7 +58,7 @@
   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>  Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
@@ -82,7 +82,9 @@
   private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
     for (int i = 0; i < min_length; i++) {
-      bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >>> 1);
+      int v1 = b1[i] & 0xffff;
+      int v2 = b2[i] & 0xffff;
+      bo[i] = (short) ((v1 + v2) >>> 1);
     }
   }
 
@@ -116,7 +118,7 @@
   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>]              loop:<<Loop>>      outer_loop:none
@@ -142,7 +144,9 @@
   private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
     for (int i = 0; i < min_length; i++) {
-      bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >>> 1);
+      int v1 = b1[i] & 0xffff;
+      int v2 = b2[i] & 0xffff;
+      bo[i] = (short) ((v1 + v2 + 1) >>> 1);
     }
   }
 
diff --git a/test/646-checker-hadd-char/build b/test/646-checker-hadd-char/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-char/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-char/src/Main.java b/test/646-checker-hadd-char/src/Main.java
index 6549dab..cbe6297 100644
--- a/test/646-checker-hadd-char/src/Main.java
+++ b/test/646-checker-hadd-char/src/Main.java
@@ -67,7 +67,7 @@
   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>  Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
@@ -152,7 +152,7 @@
   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
diff --git a/test/646-checker-hadd-short/build b/test/646-checker-hadd-short/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-short/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-short/src/Main.java b/test/646-checker-hadd-short/src/Main.java
index c09da81..d78a678 100644
--- a/test/646-checker-hadd-short/src/Main.java
+++ b/test/646-checker-hadd-short/src/Main.java
@@ -86,7 +86,7 @@
   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>  Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
@@ -110,7 +110,9 @@
   private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
     for (int i = 0; i < min_length; i++) {
-      bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >> 1);
+      int v1 = b1[i] & 0xffff;
+      int v2 = b2[i] & 0xffff;
+      bo[i] = (short) ((v1 + v2) >> 1);
     }
   }
 
@@ -224,7 +226,7 @@
   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
@@ -250,7 +252,9 @@
   private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
     for (int i = 0; i < min_length; i++) {
-      bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >> 1);
+      int v1 = b1[i] & 0xffff;
+      int v2 = b2[i] & 0xffff;
+      bo[i] = (short) ((v1 + v2 + 1) >> 1);
     }
   }
 
@@ -261,9 +265,9 @@
   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<Add2:i\d+>> Add [<<And1>>,<<Add1>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<And1>>]             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<Cnv>>] loop:<<Loop>>      outer_loop:none
@@ -288,7 +292,9 @@
     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
     for (int i = 0; i < min_length; i++) {
       // Slightly different order in idiom does not confuse recognition.
-      bo[i] = (short) ((b1[i] & 0xffff) + ((b2[i] & 0xffff) + 1) >> 1);
+      int v1 = b1[i] & 0xffff;
+      int v2 = b2[i] & 0xffff;
+      bo[i] = (short) (v1 + (v2 + 1) >> 1);
     }
   }
 
diff --git a/test/660-checker-simd-sad-byte/build b/test/660-checker-simd-sad-byte/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-byte/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-byte/src/Main.java b/test/660-checker-simd-sad-byte/src/Main.java
index 778d55c..38003d1 100644
--- a/test/660-checker-simd-sad-byte/src/Main.java
+++ b/test/660-checker-simd-sad-byte/src/Main.java
@@ -90,8 +90,8 @@
   /// CHECK-START: int Main.sadByte2Int(byte[], byte[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
@@ -121,8 +121,8 @@
   /// CHECK-START: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
@@ -154,8 +154,8 @@
   /// CHECK-START: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
diff --git a/test/660-checker-simd-sad-char/build b/test/660-checker-simd-sad-char/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-char/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-char/src/Main.java b/test/660-checker-simd-sad-char/src/Main.java
index 91c92f1..18ae024 100644
--- a/test/660-checker-simd-sad-char/src/Main.java
+++ b/test/660-checker-simd-sad-char/src/Main.java
@@ -59,8 +59,8 @@
   /// CHECK-START: int Main.sadChar2Int(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
@@ -82,8 +82,8 @@
   /// CHECK-START: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
@@ -107,8 +107,8 @@
   /// CHECK-START: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
diff --git a/test/660-checker-simd-sad-int/build b/test/660-checker-simd-sad-int/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-int/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
index 29415fd..5952c41 100644
--- a/test/660-checker-simd-sad-int/src/Main.java
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -22,8 +22,8 @@
   /// CHECK-START: int Main.sadInt2Int(int[], int[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
@@ -51,8 +51,8 @@
   /// CHECK-START: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                       loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                       loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub1:i\d+>>   Sub [<<Get2>>,<<Get1>>]             loop:<<Loop>>      outer_loop:none
@@ -79,8 +79,8 @@
   /// CHECK-START: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
diff --git a/test/660-checker-simd-sad-short/build b/test/660-checker-simd-sad-short/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-short/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-short/src/Main.java b/test/660-checker-simd-sad-short/src/Main.java
index 77c9e53..ff74559 100644
--- a/test/660-checker-simd-sad-short/src/Main.java
+++ b/test/660-checker-simd-sad-short/src/Main.java
@@ -61,8 +61,8 @@
   /// CHECK-START: int Main.sadShort2Int(short[], short[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
@@ -92,8 +92,8 @@
   /// CHECK-START: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
@@ -125,8 +125,8 @@
   /// CHECK-START: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
@@ -161,8 +161,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Cons:i\d+>>   IntConstant -7                 loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>    Add [<<Get1>>,<<Cons>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Add>>]                  loop:<<Loop>>      outer_loop:none
@@ -193,8 +193,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Cons:i\d+>>   IntConstant 7                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Cons>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
@@ -225,8 +225,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Cons:i\d+>>   IntConstant 7                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>    Add [<<Get1>>,<<Cons>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Add>>]                  loop:<<Loop>>      outer_loop:none
diff --git a/test/660-checker-simd-sad-short2/build b/test/660-checker-simd-sad-short2/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-short2/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-short2/src/Main.java b/test/660-checker-simd-sad-short2/src/Main.java
index a1f9829..1ce0e2a 100644
--- a/test/660-checker-simd-sad-short2/src/Main.java
+++ b/test/660-checker-simd-sad-short2/src/Main.java
@@ -59,8 +59,8 @@
   /// CHECK-START: int Main.sadCastedChar2Int(char[], char[]) instruction_simplifier (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
@@ -75,8 +75,8 @@
   /// CHECK-START: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
@@ -106,8 +106,8 @@
   /// CHECK-START: int Main.sadCastedChar2IntAlt(char[], char[]) instruction_simplifier (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
@@ -123,13 +123,11 @@
   /// CHECK-START: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
-  // Note: Get1+Cnv1 not simplified yet due to env use of Get1 in NullCheck for s2[i].
-  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Cnv1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
@@ -158,8 +156,8 @@
   /// CHECK-START: int Main.sadCastedChar2IntAlt2(char[], char[]) instruction_simplifier (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<BC1:\i\d+>>   BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<BC2:\i\d+>>   BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
@@ -175,13 +173,11 @@
   /// CHECK-START: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
-  // Note: Get1+Cnv1 not simplified yet due to env use of Get1 in NullCheck for s2[i].
-  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
-  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Cnv1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
diff --git a/test/660-checker-simd-sad-short3/build b/test/660-checker-simd-sad-short3/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-short3/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-short3/src/Main.java b/test/660-checker-simd-sad-short3/src/Main.java
index 877a536..d0892c3 100644
--- a/test/660-checker-simd-sad-short3/src/Main.java
+++ b/test/660-checker-simd-sad-short3/src/Main.java
@@ -25,8 +25,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Param:s\d+>>  ParameterValue                 loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get>>,<<Param>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
@@ -56,8 +56,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Param:s\d+>>  ParameterValue                 loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Param>>,<<Get>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
@@ -87,8 +87,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant -32767             loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>    Add [<<Get>>,<<ConsI>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Add>>]                  loop:<<Loop>>      outer_loop:none
@@ -118,8 +118,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 32767              loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<ConsI>>,<<Get>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
@@ -149,8 +149,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Conv:s\d+>>   TypeConversion [{{i\d+}}]      loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get>>,<<Conv>>]         loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
@@ -181,8 +181,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Conv:s\d+>>   TypeConversion [{{i\d+}}]      loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Conv>>,<<Get>>]         loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
@@ -213,8 +213,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 110                loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>    [<<Get>>,<<ConsI>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Conv:s\d+>>   TypeConversion [<<Add>>]       loop:<<Loop>>      outer_loop:none
@@ -248,8 +248,8 @@
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 110                loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:s\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:i\d+>>    [<<Get>>,<<ConsI>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Conv:s\d+>>   TypeConversion [<<Add>>]       loop:<<Loop>>      outer_loop:none
diff --git a/test/661-checker-simd-reduc/build b/test/661-checker-simd-reduc/build
deleted file mode 100644
index d85147f..0000000
--- a/test/661-checker-simd-reduc/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/661-checker-simd-reduc/src/Main.java b/test/661-checker-simd-reduc/src/Main.java
index eff2018..7b6f957 100644
--- a/test/661-checker-simd-reduc/src/Main.java
+++ b/test/661-checker-simd-reduc/src/Main.java
@@ -55,8 +55,8 @@
   /// CHECK-START: int Main.reductionInt(int[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]  loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Get>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
@@ -130,8 +130,8 @@
   /// CHECK-START: int Main.reductionIntToLoop(int[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1>>      outer_loop:none
   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]  loop:<<Loop1>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Get>>]        loop:<<Loop1>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop1>>      outer_loop:none
@@ -295,8 +295,8 @@
   /// CHECK-START: int Main.reductionMinusInt(int[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
-  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
-  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]  loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Sub [<<Phi2>>,<<Get>>]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
diff --git a/test/672-checker-throw-method/build b/test/672-checker-throw-method/build
deleted file mode 100644
index d85147f..0000000
--- a/test/672-checker-throw-method/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/672-checker-throw-method/src/Main.java b/test/672-checker-throw-method/src/Main.java
index a507133..360b52c 100644
--- a/test/672-checker-throw-method/src/Main.java
+++ b/test/672-checker-throw-method/src/Main.java
@@ -51,7 +51,7 @@
   /// CHECK-START: void Main.doit1(int[]) code_sinking (before)
   /// CHECK: begin_block
   /// CHECK:   <<Str:l\d+>> LoadString
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
@@ -61,7 +61,7 @@
   //
   /// CHECK-START: void Main.doit1(int[]) code_sinking (after)
   /// CHECK: begin_block
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
@@ -109,7 +109,7 @@
   /// CHECK-START: void Main.doit3(int[]) code_sinking (before)
   /// CHECK: begin_block
   /// CHECK:   <<Str:l\d+>> LoadString
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
@@ -119,7 +119,7 @@
   //
   /// CHECK-START: void Main.doit3(int[]) code_sinking (after)
   /// CHECK: begin_block
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
diff --git a/test/673-checker-throw-vmethod/build b/test/673-checker-throw-vmethod/build
deleted file mode 100644
index d85147f..0000000
--- a/test/673-checker-throw-vmethod/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/673-checker-throw-vmethod/src/Main.java b/test/673-checker-throw-vmethod/src/Main.java
index d0e1591..206dfaf 100644
--- a/test/673-checker-throw-vmethod/src/Main.java
+++ b/test/673-checker-throw-vmethod/src/Main.java
@@ -45,7 +45,7 @@
   /// CHECK-START: void Main.doit1(int[]) code_sinking (before)
   /// CHECK: begin_block
   /// CHECK:   <<Str:l\d+>> LoadString
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
@@ -55,7 +55,7 @@
   //
   /// CHECK-START: void Main.doit1(int[]) code_sinking (after)
   /// CHECK: begin_block
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
@@ -103,7 +103,7 @@
   /// CHECK-START: void Main.doit3(int[]) code_sinking (before)
   /// CHECK: begin_block
   /// CHECK:   <<Str:l\d+>> LoadString
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
@@ -113,7 +113,7 @@
   //
   /// CHECK-START: void Main.doit3(int[]) code_sinking (after)
   /// CHECK: begin_block
-  /// CHECK:   <<Tst:z\d+>> NotEqual
+  /// CHECK:   <<Tst:z\d+>> Equal
   /// CHECK:                If [<<Tst>>]
   /// CHECK: end_block
   /// CHECK: begin_block
diff --git a/test/952-invoke-custom/build b/test/952-invoke-custom/build
index 2caca94..53d8228 100755
--- a/test/952-invoke-custom/build
+++ b/test/952-invoke-custom/build
@@ -21,11 +21,6 @@
 INTERMEDIATE_CLASSES=classes-intermediate
 CLASSES=classes
 
-DEXER="${DX:-dx}"
-if [ "${USE_D8=false}" = "true" ]; then
-  DEXER="${ANDROID_HOST_OUT}/bin/d8-compat-dx"
-fi
-
 # Create directory for intermediate classes
 rm -rf "${INTERMEDIATE_CLASSES}"
 mkdir "${INTERMEDIATE_CLASSES}"
@@ -46,7 +41,7 @@
 
 # Create DEX
 DX_FLAGS="${DX_FLAGS} --min-sdk-version=26 --debug --dump-width=1000"
-${DEXER} -JXmx256m --dex ${DX_FLAGS} --dump-to=${CLASSES}.lst --output=classes.dex ${CLASSES}
+${DX} -JXmx256m --dex ${DX_FLAGS} --output=classes.dex ${CLASSES}
 
 # Zip DEX to file name expected by test runner
 zip ${TEST_NAME:-classes-dex}.jar classes.dex
diff --git a/test/979-const-method-handle/build b/test/979-const-method-handle/build
index ce931a9..67fc2a6 100755
--- a/test/979-const-method-handle/build
+++ b/test/979-const-method-handle/build
@@ -22,11 +22,6 @@
 TRANSFORMER_CLASSES=classes-transformer
 CLASSES=classes
 
-DEXER="${DX:-dx}"
-if [ "${USE_D8=false}" = "true" ]; then
-  DEXER="${ANDROID_HOST_OUT}/bin/d8-compat-dx"
-fi
-
 # Create directories for classes
 for class_dir in "${INTERMEDIATE_CLASSES}" "${TRANSFORMER_CLASSES}" "${CLASSES}"; do
   rm -rf "${class_dir}"
@@ -49,7 +44,7 @@
 
 # Create DEX
 DX_FLAGS="${DX_FLAGS} --min-sdk-version=28 --debug --dump-width=1000"
-${DEXER} -JXmx256m --dex ${DX_FLAGS} --dump-to=${CLASSES}.lst --output=classes.dex ${CLASSES} ${TRANSFORMER_CLASSES}
+${DX} -JXmx256m --dex ${DX_FLAGS} --output=classes.dex ${CLASSES} ${TRANSFORMER_CLASSES}
 
 # Zip DEX to file name expected by test runner
 zip ${TEST_NAME:-classes-dex}.jar classes.dex
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index f8bebdd..ad292fd 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -140,8 +140,11 @@
         $(call core-image-dependencies,$(target),$(image),$(compiler),$(address_size)))))))
 
 test-art-host-run-test-dependencies : $(host_prereq_rules)
+.PHONY: test-art-host-run-test-dependencies
 test-art-target-run-test-dependencies : $(target_prereq_rules)
+.PHONY: test-art-target-run-test-dependencies
 test-art-run-test-dependencies : test-art-host-run-test-dependencies test-art-target-run-test-dependencies
+.PHONY: test-art-run-test-dependencies
 
 # Create a rule to build and run a test group of the following form:
 # test-art-{1: host target}-run-test
diff --git a/test/etc/default-build b/test/etc/default-build
index 9dbc73c..39f1a25 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -119,12 +119,13 @@
 # The key for default arguments if no experimental things are enabled.
 DEFAULT_EXPERIMENT="no-experiment"
 
-# Setup experimental flag mappings in a bash associative array.
-declare -A SMALI_EXPERIMENTAL_ARGS
-SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api 24"
-SMALI_EXPERIMENTAL_ARGS["method-handles"]="--api 26"
-SMALI_EXPERIMENTAL_ARGS["var-handles"]="--api 26"
-SMALI_EXPERIMENTAL_ARGS["agents"]="--api 26"
+# Setup experimental API level mappings in a bash associative array.
+declare -A EXPERIMENTAL_API_LEVEL
+EXPERIMENTAL_API_LEVEL["default-methods"]="24"
+EXPERIMENTAL_API_LEVEL["parameter-annotations"]="25"
+EXPERIMENTAL_API_LEVEL["agents"]="26"
+EXPERIMENTAL_API_LEVEL["method-handles"]="26"
+EXPERIMENTAL_API_LEVEL["var-handles"]="28"
 
 declare -A JAVAC_EXPERIMENTAL_ARGS
 JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8"
@@ -135,11 +136,6 @@
 JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8"
 JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8"
 
-declare -A DX_EXPERIMENTAL_ARGS
-DX_EXPERIMENTAL_ARGS["method-handles"]="--min-sdk-version=26"
-DX_EXPERIMENTAL_ARGS["parameter-annotations"]="--min-sdk-version=25"
-DX_EXPERIMENTAL_ARGS["var-handles"]="--min-sdk-version=28"
-
 while true; do
   if [ "x$1" = "x--dx-option" ]; then
     shift
@@ -216,14 +212,15 @@
   HAS_SRC_ART=false
 fi
 
-# Be sure to get any default arguments if not doing any experiments.
-EXPERIMENTAL="${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}"
-
 # Add args from the experimental mappings.
-for experiment in ${EXPERIMENTAL}; do
-  SMALI_ARGS="${SMALI_ARGS} ${SMALI_EXPERIMENTAL_ARGS[${experiment}]}"
+for experiment in ${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}; do
   JAVAC_ARGS="${JAVAC_ARGS} ${JAVAC_EXPERIMENTAL_ARGS[${experiment}]}"
-  DX_FLAGS="${DX_FLAGS} ${DX_EXPERIMENTAL_ARGS[${experiment}]}"
+done
+
+for experiment in ${EXPERIMENTAL}; do
+  SMALI_ARGS="${SMALI_ARGS} --api ${EXPERIMENTAL_API_LEVEL[${experiment}]}"
+  DX_FLAGS="${DX_FLAGS} --min-sdk-version=${EXPERIMENTAL_API_LEVEL[${experiment}]}"
+  D8_FLAGS="--min-api ${EXPERIMENTAL_API_LEVEL[${experiment}]}"
 done
 
 #########################################
@@ -289,25 +286,33 @@
   local name="$1"
 
   local dx_input
-  if [[ "$USE_DESUGAR" == "true" ]]; then
-    # Make a jar first so desugar doesn't need every .class file individually.
-    jar cf "$name.before-desugar.jar" -C "$name" .
-
-    dx_input="${name}.desugar.jar"
-
-    # Make desugared JAR.
-    desugar --input "$name.before-desugar.jar" --output "$dx_input"
-  else
-    dx_input="${name}"
+  if [[ "$USE_DESUGAR" != "true" ]]; then
+    # Use d8 with --no-desugaring for the 3 tests that opt out of desugaring (b/110150973).
+    local d8_inputs=$(find classes -name '*.class' -type f)
+    ${D8} ${D8_FLAGS} --debug --no-desugaring --output ${name}.jar $d8_inputs && \
+      jar -xf ${name}.jar ${name}.dex && \
+      rm ${name}.jar
+    return $?
   fi
 
+  # Make a jar first so desugar doesn't need every .class file individually.
+  jar cf "$name.before-desugar.jar" -C "$name" .
+
+  # Make desugared JAR.
+  dx_input="${name}.desugar.jar"
+  desugar --input "$name.before-desugar.jar" --output "$dx_input"
+
   local dexer="${DX}"
   if [[ "${USE_D8}" != "false" ]]; then
     dexer="${ANDROID_HOST_OUT}/bin/d8-compat-dx"
   fi
 
   # Make dex file from desugared JAR.
-  ${dexer} -JXmx256m ${DX_VM_FLAGS} --debug --dex --dump-to=${name}.lst --output=${name}.dex --dump-width=1000 ${DX_FLAGS} "${dx_input}"
+  local dexer_flags="${DX_FLAGS} --debug --dex"
+  if [ $DEV_MODE = "yes" ]; then
+    echo ${dexer} -JXmx256m ${DX_VM_FLAGS} $dexer_flags --output=${name}.dex "${dx_input}"
+  fi
+  ${dexer} -JXmx256m ${DX_VM_FLAGS} $dexer_flags --output=${name}.dex "${dx_input}"
 }
 
 # Merge all the dex files in $1..$N into $1. Skip non-existing files, but at least 1 file must exist.
@@ -432,8 +437,7 @@
   # Compile Jasmin classes as if they were part of the classes.dex file.
   make_jasmin jasmin_classes $(find 'jasmin' -name '*.j')
   if [[ "${NEED_DEX}" == "true" ]]; then
-    # Disable desugar because it won't handle intentional linkage errors.
-    USE_DESUGAR=false make_dex jasmin_classes
+    make_dex jasmin_classes
     make_dexmerge classes.dex jasmin_classes.dex
   else
     # Move jasmin classes into classes directory so that they are picked up with -cp classes.
@@ -458,10 +462,7 @@
   make_jasmin jasmin_classes2 $(find 'jasmin-multidex' -name '*.j')
 
   if [[ "${NEED_DEX}" == "true" ]]; then
-    # Disable desugar because it won't handle intentional linkage errors.
-    USE_DESUGAR=false make_dex jasmin_classes2
-
-    # Merge jasmin_classes2.dex into classes2.dex
+    make_dex jasmin_classes2
     make_dexmerge classes2.dex jasmin_classes2.dex
   else
     # Move jasmin classes into classes2 directory so that they are picked up with -cp classes2.
diff --git a/test/run-test b/test/run-test
index 5bd8b3b..b5b4285 100755
--- a/test/run-test
+++ b/test/run-test
@@ -529,12 +529,27 @@
 # Most interesting target architecture variables are Makefile variables, not environment variables.
 # Try to map the suffix64 flag and what we find in ${ANDROID_PRODUCT_OUT}/data/art-test to an architecture name.
 function guess_target_arch_name() {
-    grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
-    grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'`
-    if [ "x${suffix64}" = "x64" ]; then
-        target_arch_name=${grep64bit}
+    # Check whether this is a device with native bridge. Currently this is hardcoded
+    # to x86 + arm.
+    x86_arm=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | sort | grep -E '^(arm|x86)$'`
+    # Collapse line-breaks into spaces
+    x86_arm=$(echo $x86_arm)
+    if [ "x$x86_arm" = "xarm x86" ] ; then
+        err_echo "Native-bridge configuration detected."
+        # We only support the main arch for tests.
+        if [ "x${suffix64}" = "x64" ]; then
+            target_arch_name=""
+        else
+            target_arch_name=x86
+        fi
     else
-        target_arch_name=${grep32bit}
+        grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
+        grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'`
+        if [ "x${suffix64}" = "x64" ]; then
+            target_arch_name=${grep64bit}
+        else
+            target_arch_name=${grep32bit}
+        fi
     fi
 }
 
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index 68efcaf..1924cee 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -265,14 +265,8 @@
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
-    'art-gtest-valgrind32': {
-      # Disabled: Valgrind is no longer supported.
-      # Historical note: This was already disabled, as x86 valgrind did not understand SSE4.x
-      # 'make' : 'valgrind-test-art-host32',
-        'env': {
-            'ART_USE_READ_BARRIER' : 'false'
-        }
-    },
+    # TODO: Remove this configuration, when the ART Buildbot is no
+    # longer using it for 'host-x86_64-valgrind'.
     'art-gtest-valgrind64': {
       # Disabled: Valgrind is no longer supported.
       # 'make' : 'valgrind-test-art-host64',
@@ -293,10 +287,12 @@
             'ASAN_OPTIONS' : 'detect_leaks=0'
         }
     },
+    # TODO: Also exercise '--interp-ac' in 'art-asan', when b/109813469 is addressed.
     'art-asan': {
         'run-test' : ['--interpreter',
                       '--optimizing',
-                      '--jit'],
+                      '--jit',
+                      '--speed-profile'],
         'env': {
             'SANITIZE_HOST' : 'address',
             'ASAN_OPTIONS' : 'detect_leaks=0'
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 9f423ba..2741a92 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -28,9 +28,6 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := ahat
 
-# Let users with Java 7 run ahat (b/28303627)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-
 # Make this available on the classpath of the general-tests tradefed suite.
 # It is used by libcore tests that run there.
 LOCAL_COMPATIBILITY_SUITE := general-tests
diff --git a/tools/ahat/AndroidTest.xml b/tools/ahat/AndroidTest.xml
index 867658c..b07905a 100644
--- a/tools/ahat/AndroidTest.xml
+++ b/tools/ahat/AndroidTest.xml
@@ -14,6 +14,8 @@
      limitations under the License.
 -->
 <configuration description="Runs the ahat unit tests">
+    <option name="test-suite-tag" value="ahat" />
+    <option name="test-suite-tag" value="art-tools" />
     <option name="null-device" value="true" />
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="com.android.ahat.AhatTestSuite" />
diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt
index 93fe46b..6fc62e7 100644
--- a/tools/ahat/etc/ahat_api.txt
+++ b/tools/ahat/etc/ahat_api.txt
@@ -10,6 +10,7 @@
 
   public class DominatorsComputation {
     method public static void computeDominators(com.android.ahat.dominators.DominatorsComputation.Node);
+    method public static void computeDominators(com.android.ahat.dominators.DominatorsComputation.Node, com.android.ahat.progress.Progress, long);
   }
 
   public static abstract interface DominatorsComputation.Node {
@@ -27,12 +28,10 @@
     method public int getLength();
     method public com.android.ahat.heapdump.Value getValue(int);
     method public java.util.List<com.android.ahat.heapdump.Value> getValues();
-    method public java.lang.String toString();
   }
 
   public class AhatClassInstance extends com.android.ahat.heapdump.AhatInstance {
     method public java.lang.Iterable<com.android.ahat.heapdump.FieldValue> getInstanceFields();
-    method public java.lang.String toString();
   }
 
   public class AhatClassObj extends com.android.ahat.heapdump.AhatInstance {
@@ -42,7 +41,6 @@
     method public java.lang.String getName();
     method public java.util.List<com.android.ahat.heapdump.FieldValue> getStaticFieldValues();
     method public com.android.ahat.heapdump.AhatClassObj getSuperClassObj();
-    method public java.lang.String toString();
   }
 
   public class AhatHeap implements com.android.ahat.heapdump.Diffable {
@@ -157,8 +155,13 @@
   }
 
   public class Parser {
+    ctor public Parser(java.nio.ByteBuffer);
+    ctor public Parser(java.io.File) throws java.io.IOException;
+    method public com.android.ahat.heapdump.Parser map(com.android.ahat.proguard.ProguardMap);
+    method public com.android.ahat.heapdump.AhatSnapshot parse() throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
     method public static com.android.ahat.heapdump.AhatSnapshot parseHeapDump(java.io.File, com.android.ahat.proguard.ProguardMap) throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
     method public static com.android.ahat.heapdump.AhatSnapshot parseHeapDump(java.nio.ByteBuffer, com.android.ahat.proguard.ProguardMap) throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
+    method public com.android.ahat.heapdump.Parser progress(com.android.ahat.progress.Progress);
   }
 
   public class PathElement implements com.android.ahat.heapdump.Diffable {
@@ -284,6 +287,26 @@
 
 }
 
+package com.android.ahat.progress {
+
+  public class NullProgress implements com.android.ahat.progress.Progress {
+    ctor public NullProgress();
+    method public void advance(long);
+    method public void done();
+    method public void start(java.lang.String, long);
+    method public void update(long);
+  }
+
+  public abstract interface Progress {
+    method public default void advance();
+    method public abstract void advance(long);
+    method public abstract void done();
+    method public abstract void start(java.lang.String, long);
+    method public abstract void update(long);
+  }
+
+}
+
 package com.android.ahat.proguard {
 
   public class ProguardMap {
diff --git a/tools/ahat/src/main/com/android/ahat/AsciiProgress.java b/tools/ahat/src/main/com/android/ahat/AsciiProgress.java
new file mode 100644
index 0000000..3ac98a4
--- /dev/null
+++ b/tools/ahat/src/main/com/android/ahat/AsciiProgress.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.progress.Progress;
+
+/**
+ * A progress bar that prints ascii to System.out.
+ * <p>
+ * For best results, have System.out positioned at a new line before using
+ * this progress indicator.
+ */
+class AsciiProgress implements Progress {
+  private String description;
+  private long duration;
+  private long progress;
+
+  private static void display(String description, long percent) {
+    System.out.print(String.format("\r[ %3d%% ] %s ...", percent, description));
+    System.out.flush();
+  }
+
+  @Override
+  public void start(String description, long duration) {
+    assert this.description == null;
+    this.description = description;
+    this.duration = duration;
+    this.progress = 0;
+    display(description, 0);
+  }
+
+  @Override
+  public void advance(long n) {
+    update(progress + n);
+  }
+
+  @Override
+  public void update(long current) {
+    assert description != null;
+    long oldPercent = progress * 100 / duration;
+    long newPercent = current * 100 / duration;
+    progress = current;
+
+    if (newPercent > oldPercent) {
+      display(description, newPercent);
+    }
+  }
+
+  @Override
+  public void done() {
+    update(duration);
+    System.out.println();
+    this.description = null;
+  }
+}
diff --git a/tools/ahat/src/main/com/android/ahat/Main.java b/tools/ahat/src/main/com/android/ahat/Main.java
index af197d4..d3cfcf9 100644
--- a/tools/ahat/src/main/com/android/ahat/Main.java
+++ b/tools/ahat/src/main/com/android/ahat/Main.java
@@ -20,6 +20,7 @@
 import com.android.ahat.heapdump.Diff;
 import com.android.ahat.heapdump.HprofFormatException;
 import com.android.ahat.heapdump.Parser;
+import com.android.ahat.progress.Progress;
 import com.android.ahat.proguard.ProguardMap;
 import com.sun.net.httpserver.HttpServer;
 import java.io.File;
@@ -58,10 +59,10 @@
    * Prints an error message and exits the application on failure to load the
    * heap dump.
    */
-  private static AhatSnapshot loadHeapDump(File hprof, ProguardMap map) {
+  private static AhatSnapshot loadHeapDump(File hprof, ProguardMap map, Progress progress) {
     System.out.println("Processing '" + hprof + "' ...");
     try {
-      return Parser.parseHeapDump(hprof, map);
+      return new Parser(hprof).map(map).progress(progress).parse();
     } catch (IOException e) {
       System.err.println("Unable to load '" + hprof + "':");
       e.printStackTrace();
@@ -152,9 +153,9 @@
       System.exit(1);
     }
 
-    AhatSnapshot ahat = loadHeapDump(hprof, map);
+    AhatSnapshot ahat = loadHeapDump(hprof, map, new AsciiProgress());
     if (hprofbase != null) {
-      AhatSnapshot base = loadHeapDump(hprofbase, mapbase);
+      AhatSnapshot base = loadHeapDump(hprofbase, mapbase, new AsciiProgress());
 
       System.out.println("Diffing heap dumps ...");
       Diff.snapshots(ahat, base);
diff --git a/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
index 6185dee..903211e 100644
--- a/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
+++ b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
@@ -16,6 +16,8 @@
 
 package com.android.ahat.dominators;
 
+import com.android.ahat.progress.NullProgress;
+import com.android.ahat.progress.Progress;
 import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Deque;
@@ -146,6 +148,10 @@
     //   If revisit != null, this node is on the global list of nodes to be
     //   revisited.
     public NodeSet revisit = null;
+
+    // Distance from the root to this node. Used for purposes of tracking
+    // progress only.
+    public long depth;
   }
 
   // A collection of node ids.
@@ -245,6 +251,23 @@
    * @see Node
    */
   public static void computeDominators(Node root) {
+    computeDominators(root, new NullProgress(), 0);
+  }
+
+  /**
+   * Computes the immediate dominators of all nodes reachable from the <code>root</code> node.
+   * There must not be any incoming references to the <code>root</code> node.
+   * <p>
+   * The result of this function is to call the {@link Node#setDominator}
+   * function on every node reachable from the root node.
+   *
+   * @param root the root node of the dominators computation
+   * @param progress progress tracker.
+   * @param numNodes upper bound on the number of reachable nodes in the
+   *                 graph, for progress tracking purposes only.
+   * @see Node
+   */
+  public static void computeDominators(Node root, Progress progress, long numNodes) {
     long id = 0;
 
     // The set of nodes xS such that xS.revisit != null.
@@ -257,6 +280,7 @@
     NodeS rootS = new NodeS();
     rootS.node = root;
     rootS.id = id++;
+    rootS.depth = 0;
     root.setDominatorsComputationState(rootS);
 
     Deque<Link> dfs = new ArrayDeque<Link>();
@@ -265,8 +289,14 @@
       dfs.push(new Link(rootS, child));
     }
 
+    // workBound is an upper bound on the amount of work required in the
+    // second phase of dominators computation, used solely for the purposes of
+    // tracking progress.
+    long workBound = 0;
+
     // 1. Do a depth first search of the nodes, label them with ids and come
     // up with initial candidate dominators for them.
+    progress.start("Initializing dominators", numNodes);
     while (!dfs.isEmpty()) {
       Link link = dfs.pop();
 
@@ -274,6 +304,7 @@
         // This is the marker link indicating we have now visited all
         // nodes reachable from link.srcS.
         link.srcS.maxReachableId = id - 1;
+        progress.advance();
       } else {
         NodeS dstS = (NodeS)link.dst.getDominatorsComputationState();
         if (dstS == null) {
@@ -288,6 +319,7 @@
           dstS.domS = link.srcS;
           dstS.domS.dominated.add(dstS);
           dstS.oldDomS = link.srcS;
+          dstS.depth = link.srcS.depth + 1;
 
           dfs.push(new Link(dstS));
           for (Node child : link.dst.getReferencesForDominators()) {
@@ -296,6 +328,10 @@
         } else {
           // We have seen the destination node before. Update the state based
           // on the new potential dominator.
+          if (dstS.inRefIds.size == 1) {
+            workBound += dstS.oldDomS.depth;
+          }
+
           long seenid = dstS.inRefIds.last();
           dstS.inRefIds.add(link.srcS.id);
 
@@ -330,9 +366,11 @@
         }
       }
     }
+    progress.done();
 
     // 2. Continue revisiting nodes until every node satisfies the requirement
     // that domS.id == oldDomS.id.
+    progress.start("Resolving dominators", workBound);
     while (!revisit.isEmpty()) {
       NodeS oldDomS = revisit.poll();
       assert oldDomS.revisit != null;
@@ -388,7 +426,10 @@
           nodeS.oldDomS.revisit.add(nodeS);
         }
       }
+      progress.advance((oldDomS.depth - oldDomS.oldDomS.depth) * nodes.size);
     }
+    progress.done();
+
 
     // 3. We have figured out the correct dominator for each node. Notify the
     // user of the results by doing one last traversal of the nodes.
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
index 67253bf..95553a2 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
@@ -17,6 +17,7 @@
 package com.android.ahat.heapdump;
 
 import com.android.ahat.dominators.DominatorsComputation;
+import com.android.ahat.progress.Progress;
 import java.awt.image.BufferedImage;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -603,10 +604,16 @@
    *   mNextInstanceToGcRootField
    *   mHardReverseReferences
    *   mSoftReverseReferences
+   *
+   * @param progress used to track progress of the traversal.
+   * @param numInsts upper bound on the total number of instances reachable
+   *                 from the root, solely used for the purposes of tracking
+   *                 progress.
    */
-  static void computeReverseReferences(SuperRoot root) {
+  static void computeReverseReferences(SuperRoot root, Progress progress, long numInsts) {
     // Start by doing a breadth first search through strong references.
     // Then continue the breadth first search through weak references.
+    progress.start("Reversing references", numInsts);
     Queue<Reference> strong = new ArrayDeque<Reference>();
     Queue<Reference> weak = new ArrayDeque<Reference>();
 
@@ -620,6 +627,7 @@
 
       if (ref.ref.mNextInstanceToGcRoot == null) {
         // This is the first time we have seen ref.ref.
+        progress.advance();
         ref.ref.mNextInstanceToGcRoot = ref.src;
         ref.ref.mNextInstanceToGcRootField = ref.field;
         ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>();
@@ -646,6 +654,7 @@
 
       if (ref.ref.mNextInstanceToGcRoot == null) {
         // This is the first time we have seen ref.ref.
+        progress.advance();
         ref.ref.mNextInstanceToGcRoot = ref.src;
         ref.ref.mNextInstanceToGcRootField = ref.field;
         ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>();
@@ -664,6 +673,8 @@
         ref.ref.mSoftReverseReferences.add(ref.src);
       }
     }
+
+    progress.done();
   }
 
   /**
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
index 535db08..bc94047 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
@@ -17,6 +17,7 @@
 package com.android.ahat.heapdump;
 
 import com.android.ahat.dominators.DominatorsComputation;
+import com.android.ahat.progress.Progress;
 import java.util.List;
 
 /**
@@ -39,7 +40,8 @@
   AhatSnapshot(SuperRoot root,
                Instances<AhatInstance> instances,
                List<AhatHeap> heaps,
-               Site rootSite) {
+               Site rootSite,
+               Progress progress) {
     mSuperRoot = root;
     mInstances = instances;
     mHeaps = heaps;
@@ -53,8 +55,8 @@
       }
     }
 
-    AhatInstance.computeReverseReferences(mSuperRoot);
-    DominatorsComputation.computeDominators(mSuperRoot);
+    AhatInstance.computeReverseReferences(mSuperRoot, progress, mInstances.size());
+    DominatorsComputation.computeDominators(mSuperRoot, progress, mInstances.size());
     AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size());
 
     for (AhatHeap heap : mHeaps) {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java b/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
index 0851446..7bb19a2 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
@@ -67,6 +67,10 @@
     return null;
   }
 
+  public int size() {
+    return mInstances.size();
+  }
+
   @Override
   public Iterator<T> iterator() {
     return mInstances.iterator();
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
index 13be57d..597a260 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
@@ -16,6 +16,8 @@
 
 package com.android.ahat.heapdump;
 
+import com.android.ahat.progress.NullProgress;
+import com.android.ahat.progress.Progress;
 import com.android.ahat.proguard.ProguardMap;
 import java.io.File;
 import java.io.IOException;
@@ -33,35 +35,95 @@
 
 /**
  * Provides methods for parsing heap dumps.
+ * <p>
+ * The heap dump should be a heap dump in the J2SE HPROF format optionally
+ * with Android extensions and satisfying the following additional
+ * constraints:
+ * <ul>
+ * <li>
+ * Class serial numbers, stack frames, and stack traces individually satisfy
+ * the following:
+ * <ul>
+ *   <li> All elements are defined before they are referenced.
+ *   <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
+ *   <li> There are not more than 2^31 elements defined.
+ * </ul>
+ * <li> All classes are defined via a LOAD CLASS record before the first
+ * heap dump segment.
+ * <li> The ID size used in the heap dump is 4 bytes.
+ * </ul>
  */
 public class Parser {
   private static final int ID_SIZE = 4;
 
-  private Parser() {
+  private HprofBuffer hprof = null;
+  private ProguardMap map = new ProguardMap();
+  private Progress progress = new NullProgress();
+
+  /**
+   * Creates an hprof Parser that parses a heap dump from a byte buffer.
+   *
+   * @param hprof byte buffer to parse the heap dump from.
+   */
+  public Parser(ByteBuffer hprof) {
+    this.hprof = new HprofBuffer(hprof);
   }
 
   /**
-   * Parses a heap dump from a File.
-   * <p>
-   * The heap dump should be a heap dump in the J2SE HPROF format optionally
-   * with Android extensions and satisfying the following additional
-   * constraints:
-   * <ul>
-   * <li>
-   * Class serial numbers, stack frames, and stack traces individually satisfy
-   * the following:
-   * <ul>
-   *   <li> All elements are defined before they are referenced.
-   *   <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
-   *   <li> There are not more than 2^31 elements defined.
-   * </ul>
-   * <li> All classes are defined via a LOAD CLASS record before the first
-   * heap dump segment.
-   * <li> The ID size used in the heap dump is 4 bytes.
-   * </ul>
-   * <p>
-   * The given proguard map will be used to deobfuscate class names, field
-   * names, and stack traces in the heap dump.
+   * Creates an hprof Parser that parses a heap dump from a file.
+   *
+   * @param hprof file to parse the heap dump from.
+   * @throws IOException if the file cannot be accessed.
+   */
+  public Parser(File hprof) throws IOException {
+    this.hprof = new HprofBuffer(hprof);
+  }
+
+  /**
+   * Sets the proguard map to use for deobfuscating the heap.
+   *
+   * @param map proguard map to use to deobfuscate the heap.
+   * @return this Parser instance.
+   */
+  public Parser map(ProguardMap map) {
+    if (map == null) {
+      throw new NullPointerException("map == null");
+    }
+    this.map = map;
+    return this;
+  }
+
+  /**
+   * Sets the progress indicator to use when parsing the heap.
+   *
+   * @param progress progress indicator to use when parsing the heap.
+   * @return this Parser instance.
+   */
+  public Parser progress(Progress progress) {
+    if (progress == null) {
+      throw new NullPointerException("progress == null");
+    }
+    this.progress = progress;
+    return this;
+  }
+
+  /**
+   * Parse the heap dump.
+   *
+   * @throws IOException if the heap dump could not be read
+   * @throws HprofFormatException if the heap dump is not properly formatted
+   * @return the parsed heap dump
+   */
+  public AhatSnapshot parse() throws IOException, HprofFormatException {
+    try {
+      return parseInternal();
+    } catch (BufferUnderflowException e) {
+      throw new HprofFormatException("Unexpected end of file", e);
+    }
+  }
+
+  /**
+   * Parses a heap dump from a File with given proguard map.
    *
    * @param hprof the hprof file to parse
    * @param map the proguard map for deobfuscation
@@ -71,35 +133,11 @@
    */
   public static AhatSnapshot parseHeapDump(File hprof, ProguardMap map)
     throws IOException, HprofFormatException {
-    try {
-      return parseHeapDump(new HprofBuffer(hprof), map);
-    } catch (BufferUnderflowException e) {
-      throw new HprofFormatException("Unexpected end of file", e);
-    }
+    return new Parser(hprof).map(map).parse();
   }
 
   /**
-   * Parses a heap dump from a byte buffer.
-   * <p>
-   * The heap dump should be a heap dump in the J2SE HPROF format optionally
-   * with Android extensions and satisfying the following additional
-   * constraints:
-   * <ul>
-   * <li>
-   * Class serial numbers, stack frames, and stack traces individually satisfy
-   * the following:
-   * <ul>
-   *   <li> All elements are defined before they are referenced.
-   *   <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
-   *   <li> There are not more than 2^31 elements defined.
-   * </ul>
-   * <li> All classes are defined via a LOAD CLASS record before the first
-   * heap dump segment.
-   * <li> The ID size used in the heap dump is 4 bytes.
-   * </ul>
-   * <p>
-   * The given proguard map will be used to deobfuscate class names, field
-   * names, and stack traces in the heap dump.
+   * Parses a heap dump from a byte buffer with given proguard map.
    *
    * @param hprof the bytes of the hprof file to parse
    * @param map the proguard map for deobfuscation
@@ -109,15 +147,10 @@
    */
   public static AhatSnapshot parseHeapDump(ByteBuffer hprof, ProguardMap map)
     throws IOException, HprofFormatException {
-    try {
-      return parseHeapDump(new HprofBuffer(hprof), map);
-    } catch (BufferUnderflowException e) {
-      throw new HprofFormatException("Unexpected end of file", e);
-    }
+    return new Parser(hprof).map(map).parse();
   }
 
-  private static AhatSnapshot parseHeapDump(HprofBuffer hprof, ProguardMap map)
-    throws IOException, HprofFormatException, BufferUnderflowException {
+  private AhatSnapshot parseInternal() throws IOException, HprofFormatException {
     // Read, and mostly ignore, the hprof header info.
     {
       StringBuilder format = new StringBuilder();
@@ -154,7 +187,9 @@
       ArrayList<AhatClassObj> classes = new ArrayList<AhatClassObj>();
       Instances<AhatClassObj> classById = null;
 
+      progress.start("Reading hprof", hprof.size());
       while (hprof.hasRemaining()) {
+        progress.update(hprof.tell());
         int tag = hprof.getU1();
         int time = hprof.getU4();
         int recordLength = hprof.getU4();
@@ -230,6 +265,7 @@
             }
             int subtag;
             while (!isEndOfHeapDumpSegment(subtag = hprof.getU1())) {
+              progress.update(hprof.tell());
               switch (subtag) {
                 case 0x01: { // ROOT JNI GLOBAL
                   long objectId = hprof.getId();
@@ -524,6 +560,7 @@
             break;
         }
       }
+      progress.done();
 
       instances.addAll(classes);
     }
@@ -542,9 +579,11 @@
     // that we couldn't previously resolve.
     SuperRoot superRoot = new SuperRoot();
     {
+      progress.start("Resolving references", mInstances.size());
       Iterator<RootData> ri = roots.iterator();
       RootData root = ri.next();
       for (AhatInstance inst : mInstances) {
+        progress.advance();
         long id = inst.getId();
 
         // Skip past any roots that don't have associated instances.
@@ -613,11 +652,12 @@
           ((AhatArrayInstance)inst).initialize(array);
         }
       }
+      progress.done();
     }
 
     hprof = null;
     roots = null;
-    return new AhatSnapshot(superRoot, mInstances, heaps.heaps, rootSite);
+    return new AhatSnapshot(superRoot, mInstances, heaps.heaps, rootSite, progress);
   }
 
   private static boolean isEndOfHeapDumpSegment(int subtag) {
@@ -867,6 +907,13 @@
     }
 
     /**
+     * Returns the size of the file in bytes.
+     */
+    public int size() {
+      return mBuffer.capacity();
+    }
+
+    /**
      * Return the current absolution position in the file.
      */
     public int tell() {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Value.java b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
index b219bf1..d78f95b 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
@@ -209,7 +209,7 @@
   @Override
   public abstract String toString();
 
-  private Value getBaseline() {
+  Value getBaseline() {
     return this;
   }
 
@@ -396,7 +396,8 @@
       return mInstance.toString();
     }
 
-    public Value getBaseline() {
+    @Override
+    Value getBaseline() {
       return InstanceValue.pack(mInstance.getBaseline());
     }
 
diff --git a/tools/ahat/src/main/com/android/ahat/progress/NullProgress.java b/tools/ahat/src/main/com/android/ahat/progress/NullProgress.java
new file mode 100644
index 0000000..a0ca084
--- /dev/null
+++ b/tools/ahat/src/main/com/android/ahat/progress/NullProgress.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.ahat.progress;
+
+/**
+ * Null progress tracker that ignores all updates.
+ */
+public class NullProgress implements Progress {
+  @Override public void start(String description, long duration) { }
+  @Override public void advance() { }
+  @Override public void advance(long n) { }
+  @Override public void update(long current) { }
+  @Override public void done() { }
+}
diff --git a/tools/ahat/src/main/com/android/ahat/progress/Progress.java b/tools/ahat/src/main/com/android/ahat/progress/Progress.java
new file mode 100644
index 0000000..a10379d
--- /dev/null
+++ b/tools/ahat/src/main/com/android/ahat/progress/Progress.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.ahat.progress;
+
+/**
+ * Interface for notifying users of progress during long operations.
+ */
+public interface Progress {
+  /**
+   * Called to indicate the start of a new phase of work with the given
+   * duration. Behavior is undefined if there is a current phase in progress.
+   *
+   * @param description human readable description of the work to be done.
+   * @param duration the maximum duration of the phase, in arbitrary units
+   *                 appropriate for the work in question.
+   */
+  void start(String description, long duration);
+
+  /**
+   * Called to indicate the current phase has advanced a single unit of its
+   * overall duration towards completion. Behavior is undefined if there is no
+   * current phase in progress.
+   */
+  default void advance() {
+    advance(1);
+  }
+
+  /**
+   * Called to indicate the current phase has advanced <code>n</code> units of
+   * its overall duration towards completion. Behavior is undefined if there
+   * is no current phase in progress.
+   *
+   * @param n number of units of progress that have advanced.
+   */
+  void advance(long n);
+
+  /**
+   * Called to indicate the current phase has completed <code>current</code>
+   * absolute units of its overall duration. Behavior is undefined if there is
+   * no current phase in progress.
+   *
+   * @param current progress towards duration
+   */
+  void update(long current);
+
+  /**
+   * Called to indicates that the current phase has been completed. Behavior
+   * is undefined if there is no current phase in progress.
+   */
+  void done();
+}
diff --git a/tools/ahat/src/test/com/android/ahat/DiffTest.java b/tools/ahat/src/test/com/android/ahat/DiffTest.java
index 585f29a..b1952b2 100644
--- a/tools/ahat/src/test/com/android/ahat/DiffTest.java
+++ b/tools/ahat/src/test/com/android/ahat/DiffTest.java
@@ -18,6 +18,7 @@
 
 import com.android.ahat.heapdump.AhatHeap;
 import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.Value;
 import java.io.IOException;
 import org.junit.Test;
 
@@ -51,6 +52,9 @@
     assertEquals(b, a.getBaseline());
     assertEquals(a.getSite(), b.getSite().getBaseline());
     assertEquals(b.getSite(), a.getSite().getBaseline());
+
+    Value va = Value.pack(a);
+    assertEquals(b, Value.getBaseline(va).asAhatInstance());
   }
 
   @Test
diff --git a/tools/teardown-buildbot-device.sh b/tools/teardown-buildbot-device.sh
index d25dd2b..be68b9f 100755
--- a/tools/teardown-buildbot-device.sh
+++ b/tools/teardown-buildbot-device.sh
@@ -34,17 +34,36 @@
     echo -e "${green}List open files under chroot dir $ART_TEST_CHROOT${nc}"
     adb shell lsof | grep "$ART_TEST_CHROOT"
 
-    echo -e "${green}List processes running from binaries under chroot dir $ART_TEST_CHROOT${nc}"
-    for link in $(adb shell ls -d "/proc/*/root"); do
-      root=$(adb shell readlink "$link")
-      if [[ "x$root" = "x$ART_TEST_CHROOT" ]]; then
-        dir=$(dirname "$link")
-        pid=$(basename "$dir")
-        cmdline=$(adb shell cat "$dir"/cmdline | tr -d '\000')
-        echo "$cmdline (PID: $pid)"
-      fi
-    done
+    # for_all_chroot_process ACTION
+    # -----------------------------
+    # Execute ACTION on all processes running from binaries located
+    # under the chroot directory. ACTION is passed two arguments: the
+    # PID of the process, and a string containing the command line
+    # that started this process.
+    for_all_chroot_process() {
+      local action=$1
+      for link in $(adb shell ls -d "/proc/*/root"); do
+        local root=$(adb shell readlink "$link")
+        if [[ "x$root" = "x$ART_TEST_CHROOT" ]]; then
+          local dir=$(dirname "$link")
+          local pid=$(basename "$dir")
+          local cmdline=$(adb shell cat "$dir"/cmdline | tr '\000' ' ')
+          $action "$pid" "$cmdline"
+        fi
+      done
+    }
 
+    # display_process PID CMDLINE
+    # ---------------------------
+    # Display information about process with given PID, that was started with CMDLINE.
+    display_process() {
+      local pid=$1
+      local cmdline=$2
+      echo "$cmdline (PID: $pid)"
+    }
+
+    echo -e "${green}List processes running from binaries under chroot dir $ART_TEST_CHROOT${nc}"
+    for_all_chroot_process display_process
 
     # Tear down the chroot dir.
 
@@ -102,5 +121,22 @@
     for f in $property_context_files; do
       adb shell rm -f "$ART_TEST_CHROOT$f"
     done
+
+
+    # Kill processes still running in the chroot.
+
+    # kill_process PID CMDLINE
+    # ------------------------
+    # Kill process with given PID, that was started with CMDLINE.
+    kill_process() {
+      local pid=$1
+      local cmdline=$2
+      echo "Killing $cmdline (PID: $pid)"
+      adb shell kill -9 "$pid"
+    }
+
+    echo -e "${green}Kill processes still running from binaries under" \
+      "chroot dir $ART_TEST_CHROOT (if any)${nc} "
+    for_all_chroot_process kill_process
   fi
 fi