/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Header file of an in-memory representation of DEX files.
 */

#include <stdint.h>
#include <memory>
#include <vector>

#include "dex_ir_builder.h"

#include "dex/class_accessor-inl.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file_exception_helpers.h"
#include "dexlayout.h"

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;
      }
    }
  }
}

template<class T> class CollectionMap : public CollectionBase {
 public:
  CollectionMap() = default;
  ~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;
  }

  uint32_t Size() const override { return size(); }

  // 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 dex::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 dex::AnnotationItem* annotation);
  AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
      const dex::AnnotationSetItem* disk_annotations_item, uint32_t offset);
  AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
      const dex::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
  CodeItem* DedupeOrCreateCodeItem(const DexFile& dex_file,
                                   const dex::CodeItem* disk_code_item,
                                   uint32_t offset,
                                   uint32_t dex_method_index);
  ClassData* CreateClassData(const DexFile& dex_file, const dex::ClassDef& class_def);

  void AddAnnotationsFromMapListSection(const DexFile& dex_file,
                                        uint32_t start_offset,
                                        uint32_t count);
  void AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file, uint32_t offset);

  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, const ClassAccessor::Method& method);

  ParameterAnnotation* GenerateParameterAnnotation(
      const DexFile& dex_file,
      MethodId* method_id,
      const dex::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,
                     const Options& options) {
  const DexFile::Header& disk_header = dex_file.GetHeader();
  Header* header = new Header(disk_header.magic_,
                              disk_header.checksum_,
                              disk_header.signature_,
                              disk_header.endian_tag_,
                              disk_header.file_size_,
                              disk_header.header_size_,
                              disk_header.link_size_,
                              disk_header.link_off_,
                              disk_header.data_size_,
                              disk_header.data_off_,
                              dex_file.SupportsDefaultMethods(),
                              dex_file.NumStringIds(),
                              dex_file.NumTypeIds(),
                              dex_file.NumProtoIds(),
                              dex_file.NumFieldIds(),
                              dex_file.NumMethodIds(),
                              dex_file.NumClassDefs());
  BuilderMaps builder_maps(header, eagerly_assign_offsets);
  // Walk the rest of the header fields.
  // StringId table.
  header->StringIds().SetOffset(disk_header.string_ids_off_);
  for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) {
    builder_maps.CreateStringId(dex_file, i);
  }
  // TypeId table.
  header->TypeIds().SetOffset(disk_header.type_ids_off_);
  for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
    builder_maps.CreateTypeId(dex_file, i);
  }
  // ProtoId table.
  header->ProtoIds().SetOffset(disk_header.proto_ids_off_);
  for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) {
    builder_maps.CreateProtoId(dex_file, i);
  }
  // FieldId table.
  header->FieldIds().SetOffset(disk_header.field_ids_off_);
  for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) {
    builder_maps.CreateFieldId(dex_file, i);
  }
  // MethodId table.
  header->MethodIds().SetOffset(disk_header.method_ids_off_);
  for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) {
    builder_maps.CreateMethodId(dex_file, i);
  }
  // ClassDef table.
  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
      // descriptor.
      const dex::ClassDef& class_def = dex_file.GetClassDef(i);
      const char* descriptor = dex_file.GetClassDescriptor(class_def);
      if (options.class_filter_.find(descriptor) == options.class_filter_.end()) {
        continue;
      }
    }
    builder_maps.CreateClassDef(dex_file, i);
  }
  // MapItem.
  header->SetMapListOffset(disk_header.map_off_);
  // CallSiteIds and MethodHandleItems.
  builder_maps.CreateCallSitesAndMethodHandles(dex_file);
  builder_maps.CheckAndSetRemainingOffsets(dex_file, options);

  // Sort the vectors by the map order (same order as the file).
  builder_maps.SortVectorsByMapOrder();

  // Load the link data if it exists.
  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;
}

/*
 * 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 dex::MapList* map = dex_file.GetMapList();
  const uint32_t count = map->size_;
  for (uint32_t i = 0; i < count; ++i) {
    const dex::MapItem* item = map->list_ + i;
    switch (item->type_) {
      case DexFile::kDexTypeHeaderItem:
        CHECK_EQ(item->size_, 1u);
        CHECK_EQ(item->offset_, 0u);
        break;
      case DexFile::kDexTypeStringIdItem:
        CHECK_EQ(item->size_, header_->StringIds().Size());
        CHECK_EQ(item->offset_, header_->StringIds().GetOffset());
        break;
      case DexFile::kDexTypeTypeIdItem:
        CHECK_EQ(item->size_, header_->TypeIds().Size());
        CHECK_EQ(item->offset_, header_->TypeIds().GetOffset());
        break;
      case DexFile::kDexTypeProtoIdItem:
        CHECK_EQ(item->size_, header_->ProtoIds().Size());
        CHECK_EQ(item->offset_, header_->ProtoIds().GetOffset());
        break;
      case DexFile::kDexTypeFieldIdItem:
        CHECK_EQ(item->size_, header_->FieldIds().Size());
        CHECK_EQ(item->offset_, header_->FieldIds().GetOffset());
        break;
      case DexFile::kDexTypeMethodIdItem:
        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_, header_->ClassDefs().Size());
        }
        CHECK_EQ(item->offset_, header_->ClassDefs().GetOffset());
        break;
      case DexFile::kDexTypeCallSiteIdItem:
        CHECK_EQ(item->size_, header_->CallSiteIds().Size());
        CHECK_EQ(item->offset_, header_->CallSiteIds().GetOffset());
        break;
      case DexFile::kDexTypeMethodHandleItem:
        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:
        header_->TypeLists().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeAnnotationSetRefList:
        header_->AnnotationSetRefLists().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeAnnotationSetItem:
        header_->AnnotationSetItems().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeClassDataItem:
        header_->ClassDatas().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeCodeItem:
        header_->CodeItems().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeStringDataItem:
        header_->StringDatas().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeDebugInfoItem:
        header_->DebugInfoItems().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeAnnotationItem:
        header_->AnnotationItems().SetOffset(item->offset_);
        AddAnnotationsFromMapListSection(dex_file, item->offset_, item->size_);
        break;
      case DexFile::kDexTypeEncodedArrayItem:
        header_->EncodedArrayItems().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeAnnotationsDirectoryItem:
        header_->AnnotationsDirectoryItems().SetOffset(item->offset_);
        break;
      case DexFile::kDexTypeHiddenapiClassData:
        header_->HiddenapiClassDatas().SetOffset(item->offset_);
        AddHiddenapiClassDataFromMapListSection(dex_file, item->offset_);
        break;
      default:
        LOG(ERROR) << "Unknown map list item type.";
    }
  }
}

void BuilderMaps::CreateStringId(const DexFile& dex_file, uint32_t i) {
  const dex::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 dex::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 dex::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i));
  const dex::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 dex::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 dex::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 dex::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 dex::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 dex::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, disk_class_def);
  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 dex::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 dex::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 dex::MapList* map = dex_file.GetMapList();
  for (uint32_t i = 0; i < map->size_; ++i) {
    const dex::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 dex::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 dex::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset);
    AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
    DCHECK(annotation_item != nullptr);
    current_offset += annotation_item->GetSize();
  }
}

void BuilderMaps::AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file,
                                                          uint32_t offset) {
  const dex::HiddenapiClassData* hiddenapi_class_data =
      dex_file.GetHiddenapiClassDataAtOffset(offset);
  DCHECK(hiddenapi_class_data == dex_file.GetHiddenapiClassData());

  for (auto& class_def : header_->ClassDefs()) {
    uint32_t index = class_def->GetIndex();
    ClassData* class_data = class_def->GetClassData();
    const uint8_t* ptr = hiddenapi_class_data->GetFlagsPointer(index);

    std::unique_ptr<HiddenapiFlagsMap> flags = nullptr;
    if (ptr != nullptr) {
      DCHECK(class_data != nullptr);
      flags = std::make_unique<HiddenapiFlagsMap>();
      for (const dex_ir::FieldItem& field : *class_data->StaticFields()) {
        flags->emplace(&field, DecodeUnsignedLeb128(&ptr));
      }
      for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) {
        flags->emplace(&field, DecodeUnsignedLeb128(&ptr));
      }
      for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) {
        flags->emplace(&method, DecodeUnsignedLeb128(&ptr));
      }
      for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) {
        flags->emplace(&method, DecodeUnsignedLeb128(&ptr));
      }
    }

    CreateAndAddIndexedItem(header_->HiddenapiClassDatas(),
                            header_->HiddenapiClassDatas().GetOffset() +
                                hiddenapi_class_data->flags_offset_[index],
                            index,
                            class_def.get(),
                            std::move(flags));
  }
}

AnnotationItem* BuilderMaps::CreateAnnotationItem(const DexFile& dex_file,
                                                  const dex::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 dex::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 dex::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 dex::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 dex::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 dex::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 dex::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::make_unique<FieldAnnotation>(
          field_id, annotation_set_item));
    }
  }
  const dex::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 dex::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::make_unique<MethodAnnotation>(
          method_id, annotation_set_item));
    }
  }
  const dex::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 dex::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 dex::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 dex::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 dex::ClassDef& class_def) {
  // Read the fields and methods defined by the class, resolving the circular reference from those
  // to classes by setting class at the same time.
  const uint32_t offset = class_def.class_data_off_;
  ClassData* class_data = class_datas_map_.GetExistingObject(offset);
  if (class_data == nullptr && offset != 0u) {
    ClassAccessor accessor(dex_file, class_def);
    // Static fields.
    FieldItemVector* static_fields = new FieldItemVector();
    for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
      FieldId* field_item = header_->FieldIds()[field.GetIndex()];
      uint32_t access_flags = field.GetAccessFlags();
      static_fields->emplace_back(access_flags, field_item);
    }
    FieldItemVector* instance_fields = new FieldItemVector();
    for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
      FieldId* field_item = header_->FieldIds()[field.GetIndex()];
      uint32_t access_flags = field.GetAccessFlags();
      instance_fields->emplace_back(access_flags, field_item);
    }
    // Direct methods.
    MethodItemVector* direct_methods = new MethodItemVector();
    auto direct_methods_it = accessor.GetDirectMethods();
    for (auto it = direct_methods_it.begin(); it != direct_methods_it.end(); ++it) {
      direct_methods->push_back(GenerateMethodItem(dex_file, *it));
    }
    // Virtual methods.
    MethodItemVector* virtual_methods = new MethodItemVector();
    auto virtual_methods_it = accessor.GetVirtualMethods();
    const uint8_t* last_data_ptr;
    for (auto it = virtual_methods_it.begin(); ; ++it) {
      if (it == virtual_methods_it.end()) {
        last_data_ptr = it->GetDataPointer();
        break;
      }
      virtual_methods->push_back(GenerateMethodItem(dex_file, *it));
    }
    class_data = class_datas_map_.CreateAndAddItem(header_->ClassDatas(),
                                                   eagerly_assign_offsets_,
                                                   offset,
                                                   static_fields,
                                                   instance_fields,
                                                   direct_methods,
                                                   virtual_methods);
    class_data->SetSize(last_data_ptr - dex_file.GetClassData(class_def));
  }
  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::make_unique<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,
                                           const ClassAccessor::Method& method) {
  MethodId* method_id = header_->MethodIds()[method.GetIndex()];
  uint32_t access_flags = method.GetAccessFlags();
  const dex::CodeItem* disk_code_item = method.GetCodeItem();
  // 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,
                                               method.GetCodeItemOffset(),
                                               method.GetIndex());
  return MethodItem(access_flags, method_id, code_item);
}

ParameterAnnotation* BuilderMaps::GenerateParameterAnnotation(
    const DexFile& dex_file,
    MethodId* method_id,
    const dex::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 dex::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
