Refactor ownership in dex_ir

Remove some unnecessary generality, consolidating and simplifying the
interface to Header and moving all the construction code out of dex_ir.
This makes item ownership exclusively controlled by the collections
themselves, preparing for in-place construction.

Bug: 33017139
Test: make -j 40 test-art-host-gtest
Change-Id: Ice461ae89ef9f8bed3350780e8dd6283bc6eca1b
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_) {