1c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko/*
2c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * Copyright (C) 2015 The Android Open Source Project
3c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko *
4c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * Licensed under the Apache License, Version 2.0 (the "License");
5c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * you may not use this file except in compliance with the License.
6c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * You may obtain a copy of the License at
7c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko *
8c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko *      http://www.apache.org/licenses/LICENSE-2.0
9c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko *
10c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * Unless required by applicable law or agreed to in writing, software
11c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * distributed under the License is distributed on an "AS IS" BASIS,
12c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * See the License for the specific language governing permissions and
14c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko * limitations under the License.
15c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko */
16c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
17c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#ifndef ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_
18c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#define ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_
19c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
20c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#include <cstring>
21c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#include <set>
22c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#include <map>
23c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#include <vector>
24c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
2541b175aba41c9365a1c53b8a1afbd17129c87c14Vladimir Marko#include "base/bit_utils.h"
2641b175aba41c9365a1c53b8a1afbd17129c87c14Vladimir Marko#include "base/logging.h"
27c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#include "dex_file.h"
28c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
29c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Markonamespace art {
30c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
31c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Markoclass TestDexFileBuilder {
32c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko public:
33c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  TestDexFileBuilder()
34c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      : strings_(), types_(), fields_(), protos_(), dex_file_data_() {
35c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
36c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
37c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  void AddString(const std::string& str) {
38c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(dex_file_data_.empty());
39c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    auto it = strings_.emplace(str, IdxAndDataOffset()).first;
40c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_LT(it->first.length(), 128u);  // Don't allow multi-byte length in uleb128.
41c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
42c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
43c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  void AddType(const std::string& descriptor) {
44c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(dex_file_data_.empty());
45c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddString(descriptor);
46c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    types_.emplace(descriptor, 0u);
47c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
48c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
49c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  void AddField(const std::string& class_descriptor, const std::string& type,
50c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko                const std::string& name) {
51c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(dex_file_data_.empty());
52c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddType(class_descriptor);
53c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddType(type);
54c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddString(name);
55c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    FieldKey key = { class_descriptor, type, name };
56c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    fields_.emplace(key, 0u);
57c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
58c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
59c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  void AddMethod(const std::string& class_descriptor, const std::string& signature,
60c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko                 const std::string& name) {
61c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(dex_file_data_.empty());
62c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddType(class_descriptor);
63c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddString(name);
64c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
65c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    ProtoKey proto_key = CreateProtoKey(signature);
66c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddString(proto_key.shorty);
67c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    AddType(proto_key.return_type);
68c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (const auto& arg_type : proto_key.args) {
69c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      AddType(arg_type);
70c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
71c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    auto it = protos_.emplace(proto_key, IdxAndDataOffset()).first;
72c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const ProtoKey* proto = &it->first;  // Valid as long as the element remains in protos_.
73c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
74c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    MethodKey method_key = {
75c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        class_descriptor, name, proto
76c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    };
77c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    methods_.emplace(method_key, 0u);
78c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
79c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
80c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  // NOTE: The builder holds the actual data, so it must live as long as the dex file.
81c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::unique_ptr<const DexFile> Build(const std::string& dex_location) {
82c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(dex_file_data_.empty());
83c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    union {
84c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint8_t data[sizeof(DexFile::Header)];
85c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint64_t force_alignment;
86c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    } header_data;
87c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::memset(header_data.data, 0, sizeof(header_data.data));
88c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    DexFile::Header* header = reinterpret_cast<DexFile::Header*>(&header_data.data);
89c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::copy_n(DexFile::kDexMagic, 4u, header->magic_);
90c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::copy_n(DexFile::kDexMagicVersion, 4u, header->magic_ + 4u);
91c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->header_size_ = sizeof(header);
92c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->endian_tag_ = DexFile::kDexEndianConstant;
93c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->link_size_ = 0u;  // Unused.
94c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->link_off_ = 0u;  // Unused.
95c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->map_off_ = 0u;  // Unused.
96c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
97c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t data_section_size = 0u;
98c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
99c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t string_ids_offset = sizeof(DexFile::Header);
100c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t string_idx = 0u;
101c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (auto& entry : strings_) {
102c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      entry.second.idx = string_idx;
103c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      string_idx += 1u;
104c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      entry.second.data_offset = data_section_size;
105c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      data_section_size += entry.first.length() + 1u /* length */ + 1u /* null-terminator */;
106c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
107c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->string_ids_size_ = strings_.size();
108c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->string_ids_off_ = strings_.empty() ? 0u : string_ids_offset;
109c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
110c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t type_ids_offset = string_ids_offset + strings_.size() * sizeof(DexFile::StringId);
111c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t type_idx = 0u;
112c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (auto& entry : types_) {
113c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      entry.second = type_idx;
114c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      type_idx += 1u;
115c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
116c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->type_ids_size_ = types_.size();
117c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->type_ids_off_ = types_.empty() ? 0u : type_ids_offset;
118c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
119c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t proto_ids_offset = type_ids_offset + types_.size() * sizeof(DexFile::TypeId);
120c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t proto_idx = 0u;
121c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (auto& entry : protos_) {
122c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      entry.second.idx = proto_idx;
123c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      proto_idx += 1u;
124c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      size_t num_args = entry.first.args.size();
125c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (num_args != 0u) {
126c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        entry.second.data_offset = RoundUp(data_section_size, 4u);
127c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        data_section_size = entry.second.data_offset + 4u + num_args * sizeof(DexFile::TypeItem);
128c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      } else {
129c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        entry.second.data_offset = 0u;
130c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
131c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
132c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->proto_ids_size_ = protos_.size();
133c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->proto_ids_off_ = protos_.empty() ? 0u : proto_ids_offset;
134c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
135c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t field_ids_offset = proto_ids_offset + protos_.size() * sizeof(DexFile::ProtoId);
136c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t field_idx = 0u;
137c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (auto& entry : fields_) {
138c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      entry.second = field_idx;
139c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      field_idx += 1u;
140c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
141c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->field_ids_size_ = fields_.size();
142c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->field_ids_off_ = fields_.empty() ? 0u : field_ids_offset;
143c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
144c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t method_ids_offset = field_ids_offset + fields_.size() * sizeof(DexFile::FieldId);
145c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t method_idx = 0u;
146c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (auto& entry : methods_) {
147c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      entry.second = method_idx;
148c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      method_idx += 1u;
149c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
150c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->method_ids_size_ = methods_.size();
151c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->method_ids_off_ = methods_.empty() ? 0u : method_ids_offset;
152c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
153c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    // No class defs.
154c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->class_defs_size_ = 0u;
155c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->class_defs_off_ = 0u;
156c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
157c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t data_section_offset = method_ids_offset + methods_.size() * sizeof(DexFile::MethodId);
158c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->data_size_ = data_section_size;
159c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    header->data_off_ = (data_section_size != 0u) ? data_section_offset : 0u;
160c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
161c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t total_size = data_section_offset + data_section_size;
162c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
163c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_.resize(total_size);
164c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::memcpy(&dex_file_data_[0], header_data.data, sizeof(DexFile::Header));
165c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
166c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (const auto& entry : strings_) {
167c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      CHECK_LT(entry.first.size(), 128u);
168c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint32_t raw_offset = data_section_offset + entry.second.data_offset;
169c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      dex_file_data_[raw_offset] = static_cast<uint8_t>(entry.first.size());
170c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      std::memcpy(&dex_file_data_[raw_offset + 1], entry.first.c_str(), entry.first.size() + 1);
171c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write32(string_ids_offset + entry.second.idx * sizeof(DexFile::StringId), raw_offset);
172c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
173c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
174c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (const auto& entry : types_) {
175c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write32(type_ids_offset + entry.second * sizeof(DexFile::TypeId), GetStringIdx(entry.first));
176c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      ++type_idx;
177c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
178c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
179c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (const auto& entry : protos_) {
180c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      size_t num_args = entry.first.args.size();
181c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint32_t type_list_offset =
182c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko          (num_args != 0u) ? data_section_offset + entry.second.data_offset : 0u;
183c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint32_t raw_offset = proto_ids_offset + entry.second.idx * sizeof(DexFile::ProtoId);
184c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write32(raw_offset + 0u, GetStringIdx(entry.first.shorty));
185c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write16(raw_offset + 4u, GetTypeIdx(entry.first.return_type));
186c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write32(raw_offset + 8u, type_list_offset);
187c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (num_args != 0u) {
188c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        CHECK_NE(entry.second.data_offset, 0u);
189c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        Write32(type_list_offset, num_args);
190c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        for (size_t i = 0; i != num_args; ++i) {
191c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko          Write16(type_list_offset + 4u + i * sizeof(DexFile::TypeItem),
192c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko                  GetTypeIdx(entry.first.args[i]));
193c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        }
194c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
195c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
196c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
197c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (const auto& entry : fields_) {
198c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint32_t raw_offset = field_ids_offset + entry.second * sizeof(DexFile::FieldId);
199c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
200c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write16(raw_offset + 2u, GetTypeIdx(entry.first.type));
201c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write32(raw_offset + 4u, GetStringIdx(entry.first.name));
202c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
203c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
204c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    for (const auto& entry : methods_) {
205c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      uint32_t raw_offset = method_ids_offset + entry.second * sizeof(DexFile::MethodId);
206c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
207c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      auto it = protos_.find(*entry.first.proto);
208c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      CHECK(it != protos_.end());
209c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write16(raw_offset + 2u, it->second.idx);
210c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      Write32(raw_offset + 4u, GetStringIdx(entry.first.name));
211c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
212c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
213c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    // Leave checksum and signature as zeros.
214c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
215c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::string error_msg;
216c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::unique_ptr<const DexFile> dex_file(DexFile::Open(
217c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        &dex_file_data_[0], dex_file_data_.size(), dex_location, 0u, nullptr, &error_msg));
218c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(dex_file != nullptr) << error_msg;
219c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    return std::move(dex_file);
220c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
221c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
222c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  uint32_t GetStringIdx(const std::string& type) {
223c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    auto it = strings_.find(type);
224c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(it != strings_.end());
225c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    return it->second.idx;
226c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
227c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
228c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  uint32_t GetTypeIdx(const std::string& type) {
229c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    auto it = types_.find(type);
230c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(it != types_.end());
231c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    return it->second;
232c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
233c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
234c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  uint32_t GetFieldIdx(const std::string& class_descriptor, const std::string& type,
235c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko                       const std::string& name) {
236c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    FieldKey key = { class_descriptor, type, name };
237c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    auto it = fields_.find(key);
238c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(it != fields_.end());
239c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    return it->second;
240c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
241c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
242c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  uint32_t GetMethodIdx(const std::string& class_descriptor, const std::string& signature,
243c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko                        const std::string& name) {
244c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    ProtoKey proto_key = CreateProtoKey(signature);
245c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    MethodKey method_key = { class_descriptor, name, &proto_key };
246c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    auto it = methods_.find(method_key);
247c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(it != methods_.end());
248c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    return it->second;
249c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
250c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
251c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko private:
252c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct IdxAndDataOffset {
253c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t idx;
254c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    uint32_t data_offset;
255c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
256c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
257c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct FieldKey {
258c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const std::string class_descriptor;
259c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const std::string type;
260c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const std::string name;
261c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
262c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct FieldKeyComparator {
263c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    bool operator()(const FieldKey& lhs, const FieldKey& rhs) const {
264c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (lhs.class_descriptor != rhs.class_descriptor) {
265c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        return lhs.class_descriptor < rhs.class_descriptor;
266c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
267c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (lhs.name != rhs.name) {
268c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        return lhs.name < rhs.name;
269c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
270c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      return lhs.type < rhs.type;
271c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
272c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
273c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
274c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct ProtoKey {
275c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::string shorty;
276c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::string return_type;
277c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::vector<std::string> args;
278c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
279c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct ProtoKeyComparator {
280c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    bool operator()(const ProtoKey& lhs, const ProtoKey& rhs) const {
281c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (lhs.return_type != rhs.return_type) {
282c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        return lhs.return_type < rhs.return_type;
283c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
284c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      size_t min_args = std::min(lhs.args.size(), rhs.args.size());
285c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      for (size_t i = 0; i != min_args; ++i) {
286c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        if (lhs.args[i] != rhs.args[i]) {
287c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko          return lhs.args[i] < rhs.args[i];
288c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        }
289c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
290c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      return lhs.args.size() < rhs.args.size();
291c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
292c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
293c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
294c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct MethodKey {
295c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::string class_descriptor;
296c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    std::string name;
297c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const ProtoKey* proto;
298c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
299c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  struct MethodKeyComparator {
300c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    bool operator()(const MethodKey& lhs, const MethodKey& rhs) const {
301c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (lhs.class_descriptor != rhs.class_descriptor) {
302c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        return lhs.class_descriptor < rhs.class_descriptor;
303c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
304c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (lhs.name != rhs.name) {
305c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        return lhs.name < rhs.name;
306c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
307c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      return ProtoKeyComparator()(*lhs.proto, *rhs.proto);
308c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
309c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  };
310c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
311c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  ProtoKey CreateProtoKey(const std::string& signature) {
312c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(signature[0], '(');
313c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const char* args = signature.c_str() + 1;
314c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const char* args_end = std::strchr(args, ')');
315c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK(args_end != nullptr);
316c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    const char* return_type = args_end + 1;
317c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
318c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    ProtoKey key = {
319c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        std::string() + ((*return_type == '[') ? 'L' : *return_type),
320c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        return_type,
321c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        std::vector<std::string>()
322c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    };
323c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    while (args != args_end) {
324c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      key.shorty += (*args == '[') ? 'L' : *args;
325c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      const char* arg_start = args;
326c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      while (*args == '[') {
327c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        ++args;
328c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
329c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      if (*args == 'L') {
330c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        do {
331c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko          ++args;
332c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko          CHECK_NE(args, args_end);
333c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko        } while (*args != ';');
334c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      }
335c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      ++args;
336c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko      key.args.emplace_back(arg_start, args);
337c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    }
338c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    return key;
339c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
340c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
341c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  void Write32(size_t offset, uint32_t value) {
342c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_LE(offset + 4u, dex_file_data_.size());
343c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(dex_file_data_[offset + 0], 0u);
344c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(dex_file_data_[offset + 1], 0u);
345c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(dex_file_data_[offset + 2], 0u);
346c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(dex_file_data_[offset + 3], 0u);
347c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0);
348c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8);
349c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_[offset + 2] = static_cast<uint8_t>(value >> 16);
350c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_[offset + 3] = static_cast<uint8_t>(value >> 24);
351c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
352c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
353c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  void Write16(size_t offset, uint32_t value) {
354c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_LE(value, 0xffffu);
355c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_LE(offset + 2u, dex_file_data_.size());
356c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(dex_file_data_[offset + 0], 0u);
357c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    CHECK_EQ(dex_file_data_[offset + 1], 0u);
358c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0);
359c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko    dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8);
360c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  }
361c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
362c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::map<std::string, IdxAndDataOffset> strings_;
363c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::map<std::string, uint32_t> types_;
364c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::map<FieldKey, uint32_t, FieldKeyComparator> fields_;
365c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::map<ProtoKey, IdxAndDataOffset, ProtoKeyComparator> protos_;
366c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::map<MethodKey, uint32_t, MethodKeyComparator> methods_;
367c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
368c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko  std::vector<uint8_t> dex_file_data_;
369c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko};
370c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
371c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko}  // namespace art
372c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko
373c91df2d6339dd4adf2da582372451df19ce2ff44Vladimir Marko#endif  // ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_
374