1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#include "file_item_container.h"
17b1994897Sopenharmony_ci#include "macros.h"
18b1994897Sopenharmony_ci#include "file_format_version.h"
19b1994897Sopenharmony_ci#include "pgo.h"
20b1994897Sopenharmony_ci
21b1994897Sopenharmony_cinamespace panda::panda_file {
22b1994897Sopenharmony_ci
23b1994897Sopenharmony_ciclass ItemDeduper {
24b1994897Sopenharmony_cipublic:
25b1994897Sopenharmony_ci    template <class T>
26b1994897Sopenharmony_ci    T *Deduplicate(T *item)
27b1994897Sopenharmony_ci    {
28b1994897Sopenharmony_ci        static_assert(std::is_base_of_v<BaseItem, T>);
29b1994897Sopenharmony_ci
30b1994897Sopenharmony_ci        ItemData item_data(item);
31b1994897Sopenharmony_ci        auto it = items_.find(item_data);
32b1994897Sopenharmony_ci        if (it == items_.cend()) {
33b1994897Sopenharmony_ci            items_.insert(item_data);
34b1994897Sopenharmony_ci            return item;
35b1994897Sopenharmony_ci        }
36b1994897Sopenharmony_ci
37b1994897Sopenharmony_ci        auto result = static_cast<T *>(it->GetItem());
38b1994897Sopenharmony_ci        if (item != result) {
39b1994897Sopenharmony_ci            item->SetNeedsEmit(false);
40b1994897Sopenharmony_ci        }
41b1994897Sopenharmony_ci
42b1994897Sopenharmony_ci        return result;
43b1994897Sopenharmony_ci    }
44b1994897Sopenharmony_ci
45b1994897Sopenharmony_ci    size_t GetUniqueCount() const
46b1994897Sopenharmony_ci    {
47b1994897Sopenharmony_ci        return items_.size();
48b1994897Sopenharmony_ci    }
49b1994897Sopenharmony_ci
50b1994897Sopenharmony_ciprivate:
51b1994897Sopenharmony_ci    class ItemWriter : public Writer {
52b1994897Sopenharmony_ci    public:
53b1994897Sopenharmony_ci        ItemWriter(std::vector<uint8_t> *buf, size_t offset) : buf_(buf), offset_(offset) {}
54b1994897Sopenharmony_ci        ~ItemWriter() override = default;
55b1994897Sopenharmony_ci
56b1994897Sopenharmony_ci        NO_COPY_SEMANTIC(ItemWriter);
57b1994897Sopenharmony_ci        NO_MOVE_SEMANTIC(ItemWriter);
58b1994897Sopenharmony_ci
59b1994897Sopenharmony_ci        bool WriteByte(uint8_t byte) override
60b1994897Sopenharmony_ci        {
61b1994897Sopenharmony_ci            buf_->push_back(byte);
62b1994897Sopenharmony_ci            ++offset_;
63b1994897Sopenharmony_ci            return true;
64b1994897Sopenharmony_ci        }
65b1994897Sopenharmony_ci
66b1994897Sopenharmony_ci        bool WriteBytes(const std::vector<uint8_t> &bytes) override
67b1994897Sopenharmony_ci        {
68b1994897Sopenharmony_ci            buf_->insert(buf_->end(), bytes.cbegin(), bytes.cend());
69b1994897Sopenharmony_ci            offset_ += bytes.size();
70b1994897Sopenharmony_ci            return true;
71b1994897Sopenharmony_ci        }
72b1994897Sopenharmony_ci
73b1994897Sopenharmony_ci        size_t GetOffset() const override
74b1994897Sopenharmony_ci        {
75b1994897Sopenharmony_ci            return offset_;
76b1994897Sopenharmony_ci        }
77b1994897Sopenharmony_ci
78b1994897Sopenharmony_ci    private:
79b1994897Sopenharmony_ci        std::vector<uint8_t> *buf_;
80b1994897Sopenharmony_ci        size_t offset_;
81b1994897Sopenharmony_ci    };
82b1994897Sopenharmony_ci
83b1994897Sopenharmony_ci    class ItemData {
84b1994897Sopenharmony_ci    public:
85b1994897Sopenharmony_ci        explicit ItemData(BaseItem *item) : item_(item)
86b1994897Sopenharmony_ci        {
87b1994897Sopenharmony_ci            Initialize();
88b1994897Sopenharmony_ci        }
89b1994897Sopenharmony_ci
90b1994897Sopenharmony_ci        ~ItemData() = default;
91b1994897Sopenharmony_ci
92b1994897Sopenharmony_ci        DEFAULT_COPY_SEMANTIC(ItemData);
93b1994897Sopenharmony_ci        NO_MOVE_SEMANTIC(ItemData);
94b1994897Sopenharmony_ci
95b1994897Sopenharmony_ci        BaseItem *GetItem() const
96b1994897Sopenharmony_ci        {
97b1994897Sopenharmony_ci            return item_;
98b1994897Sopenharmony_ci        }
99b1994897Sopenharmony_ci
100b1994897Sopenharmony_ci        uint32_t GetHash() const
101b1994897Sopenharmony_ci        {
102b1994897Sopenharmony_ci            ASSERT(IsInitialized());
103b1994897Sopenharmony_ci            return hash_;
104b1994897Sopenharmony_ci        }
105b1994897Sopenharmony_ci
106b1994897Sopenharmony_ci        bool operator==(const ItemData &item_data) const noexcept
107b1994897Sopenharmony_ci        {
108b1994897Sopenharmony_ci            ASSERT(IsInitialized());
109b1994897Sopenharmony_ci            return data_ == item_data.data_;
110b1994897Sopenharmony_ci        }
111b1994897Sopenharmony_ci
112b1994897Sopenharmony_ci    private:
113b1994897Sopenharmony_ci        bool IsInitialized() const
114b1994897Sopenharmony_ci        {
115b1994897Sopenharmony_ci            return !data_.empty();
116b1994897Sopenharmony_ci        }
117b1994897Sopenharmony_ci
118b1994897Sopenharmony_ci        void Initialize()
119b1994897Sopenharmony_ci        {
120b1994897Sopenharmony_ci            ASSERT(item_->NeedsEmit());
121b1994897Sopenharmony_ci
122b1994897Sopenharmony_ci            ItemWriter writer(&data_, item_->GetOffset());
123b1994897Sopenharmony_ci            [[maybe_unused]] auto res = item_->Write(&writer);
124b1994897Sopenharmony_ci            ASSERT(res);
125b1994897Sopenharmony_ci            ASSERT(data_.size() == item_->GetSize());
126b1994897Sopenharmony_ci
127b1994897Sopenharmony_ci            hash_ = GetHash32(data_.data(), data_.size());
128b1994897Sopenharmony_ci        }
129b1994897Sopenharmony_ci
130b1994897Sopenharmony_ci        BaseItem *item_;
131b1994897Sopenharmony_ci        uint32_t hash_ {0};
132b1994897Sopenharmony_ci        std::vector<uint8_t> data_;
133b1994897Sopenharmony_ci    };
134b1994897Sopenharmony_ci
135b1994897Sopenharmony_ci    struct ItemHash {
136b1994897Sopenharmony_ci        size_t operator()(const ItemData &item_data) const noexcept
137b1994897Sopenharmony_ci        {
138b1994897Sopenharmony_ci            return item_data.GetHash();
139b1994897Sopenharmony_ci        }
140b1994897Sopenharmony_ci    };
141b1994897Sopenharmony_ci
142b1994897Sopenharmony_ci    std::unordered_set<ItemData, ItemHash> items_;
143b1994897Sopenharmony_ci};
144b1994897Sopenharmony_ci
145b1994897Sopenharmony_citemplate <class T, class C, class I, class P, class E, class... Args>
146b1994897Sopenharmony_cistatic T *GetOrInsert(C &map, I &items, const P &pos, const E &key, bool is_foreign, Args &&... args)
147b1994897Sopenharmony_ci{
148b1994897Sopenharmony_ci    auto it = map.find(key);
149b1994897Sopenharmony_ci    if (it != map.cend()) {
150b1994897Sopenharmony_ci        auto *item = it->second;
151b1994897Sopenharmony_ci        if (item->IsForeign() == is_foreign) {
152b1994897Sopenharmony_ci            return static_cast<T *>(item);
153b1994897Sopenharmony_ci        }
154b1994897Sopenharmony_ci
155b1994897Sopenharmony_ci        UNREACHABLE();
156b1994897Sopenharmony_ci        return nullptr;
157b1994897Sopenharmony_ci    }
158b1994897Sopenharmony_ci
159b1994897Sopenharmony_ci    auto ii = items.insert(pos, std::make_unique<T>(std::forward<Args>(args)...));
160b1994897Sopenharmony_ci    auto *item = static_cast<T *>(ii->get());
161b1994897Sopenharmony_ci
162b1994897Sopenharmony_ci    [[maybe_unused]] auto res = map.insert({key, item});
163b1994897Sopenharmony_ci    ASSERT(res.second);
164b1994897Sopenharmony_ci    return item;
165b1994897Sopenharmony_ci}
166b1994897Sopenharmony_ci
167b1994897Sopenharmony_ci/*static*/
168b1994897Sopenharmony_ciuint8_t ItemContainer::apiVersion = 0;
169b1994897Sopenharmony_cistd::string ItemContainer::subApiVersion = DEFAULT_SUB_API_VERSION;
170b1994897Sopenharmony_ci
171b1994897Sopenharmony_ciItemContainer::ItemContainer()
172b1994897Sopenharmony_ci{
173b1994897Sopenharmony_ci    items_end_ = items_.insert(items_.end(), std::make_unique<EndItem>());
174b1994897Sopenharmony_ci    code_items_end_ = items_.insert(items_.end(), std::make_unique<EndItem>());
175b1994897Sopenharmony_ci    debug_items_end_ = items_.insert(items_.end(), std::make_unique<EndItem>());
176b1994897Sopenharmony_ci    end_ = debug_items_end_->get();
177b1994897Sopenharmony_ci}
178b1994897Sopenharmony_ci
179b1994897Sopenharmony_ciClassItem *ItemContainer::GetOrCreateClassItem(const std::string &str)
180b1994897Sopenharmony_ci{
181b1994897Sopenharmony_ci    return GetOrInsert<ClassItem>(class_map_, items_, items_end_, str, false, str, this);
182b1994897Sopenharmony_ci}
183b1994897Sopenharmony_ci
184b1994897Sopenharmony_ciForeignClassItem *ItemContainer::GetOrCreateForeignClassItem(const std::string &str)
185b1994897Sopenharmony_ci{
186b1994897Sopenharmony_ci    return GetOrInsert<ForeignClassItem>(class_map_, foreign_items_, foreign_items_.end(), str, true, str, this);
187b1994897Sopenharmony_ci}
188b1994897Sopenharmony_ci
189b1994897Sopenharmony_ciStringItem *ItemContainer::GetOrCreateStringItem(const std::string &str)
190b1994897Sopenharmony_ci{
191b1994897Sopenharmony_ci    auto it = class_map_.find(str);
192b1994897Sopenharmony_ci    if (it != class_map_.cend()) {
193b1994897Sopenharmony_ci        return it->second->GetNameItem();
194b1994897Sopenharmony_ci    }
195b1994897Sopenharmony_ci
196b1994897Sopenharmony_ci    return GetOrInsert<StringItem>(string_map_, items_, items_end_, str, false, str, this);
197b1994897Sopenharmony_ci}
198b1994897Sopenharmony_ci
199b1994897Sopenharmony_ciLiteralArrayItem *ItemContainer::GetOrCreateLiteralArrayItem(const std::string &id)
200b1994897Sopenharmony_ci{
201b1994897Sopenharmony_ci    return GetOrInsert<LiteralArrayItem>(literalarray_map_, items_, items_end_, id, false, this);
202b1994897Sopenharmony_ci}
203b1994897Sopenharmony_ci
204b1994897Sopenharmony_ciScalarValueItem *ItemContainer::GetOrCreateIntegerValueItem(uint32_t v)
205b1994897Sopenharmony_ci{
206b1994897Sopenharmony_ci    return GetOrInsert<ScalarValueItem>(int_value_map_, items_, items_end_, v, false, v, this);
207b1994897Sopenharmony_ci}
208b1994897Sopenharmony_ci
209b1994897Sopenharmony_ciScalarValueItem *ItemContainer::GetOrCreateLongValueItem(uint64_t v)
210b1994897Sopenharmony_ci{
211b1994897Sopenharmony_ci    return GetOrInsert<ScalarValueItem>(long_value_map_, items_, items_end_, v, false, v, this);
212b1994897Sopenharmony_ci}
213b1994897Sopenharmony_ci
214b1994897Sopenharmony_ciScalarValueItem *ItemContainer::GetOrCreateFloatValueItem(float v)
215b1994897Sopenharmony_ci{
216b1994897Sopenharmony_ci    return GetOrInsert<ScalarValueItem>(float_value_map_, items_, items_end_, bit_cast<uint32_t>(v), false, v, this);
217b1994897Sopenharmony_ci}
218b1994897Sopenharmony_ci
219b1994897Sopenharmony_ciScalarValueItem *ItemContainer::GetOrCreateDoubleValueItem(double v)
220b1994897Sopenharmony_ci{
221b1994897Sopenharmony_ci    return GetOrInsert<ScalarValueItem>(double_value_map_, items_, items_end_, bit_cast<uint64_t>(v), false, v, this);
222b1994897Sopenharmony_ci}
223b1994897Sopenharmony_ci
224b1994897Sopenharmony_ciScalarValueItem *ItemContainer::GetOrCreateIdValueItem(BaseItem *v)
225b1994897Sopenharmony_ci{
226b1994897Sopenharmony_ci    return GetOrInsert<ScalarValueItem>(id_value_map_, items_, items_end_, v, false, v, this);
227b1994897Sopenharmony_ci}
228b1994897Sopenharmony_ci
229b1994897Sopenharmony_ciProtoItem *ItemContainer::GetOrCreateProtoItem(TypeItem *ret_type, const std::vector<MethodParamItem> &params)
230b1994897Sopenharmony_ci{
231b1994897Sopenharmony_ci    ProtoKey key(ret_type, params);
232b1994897Sopenharmony_ci    return GetOrInsert<ProtoItem>(proto_map_, items_, items_end_, key, false, ret_type, params, this);
233b1994897Sopenharmony_ci}
234b1994897Sopenharmony_ci
235b1994897Sopenharmony_ciPrimitiveTypeItem *ItemContainer::GetOrCreatePrimitiveTypeItem(Type type)
236b1994897Sopenharmony_ci{
237b1994897Sopenharmony_ci    return GetOrCreatePrimitiveTypeItem(type.GetId());
238b1994897Sopenharmony_ci}
239b1994897Sopenharmony_ci
240b1994897Sopenharmony_ciPrimitiveTypeItem *ItemContainer::GetOrCreatePrimitiveTypeItem(Type::TypeId type)
241b1994897Sopenharmony_ci{
242b1994897Sopenharmony_ci    return GetOrInsert<PrimitiveTypeItem>(primitive_type_map_, items_, items_end_, type, false, type, this);
243b1994897Sopenharmony_ci}
244b1994897Sopenharmony_ci
245b1994897Sopenharmony_ciLineNumberProgramItem *ItemContainer::CreateLineNumberProgramItem()
246b1994897Sopenharmony_ci{
247b1994897Sopenharmony_ci    auto it = items_.insert(debug_items_end_, std::make_unique<LineNumberProgramItem>(this));
248b1994897Sopenharmony_ci    auto *item = static_cast<LineNumberProgramItem *>(it->get());
249b1994897Sopenharmony_ci    [[maybe_unused]] auto res = line_number_program_index_item_.Add(item);
250b1994897Sopenharmony_ci    ASSERT(res);
251b1994897Sopenharmony_ci    return item;
252b1994897Sopenharmony_ci}
253b1994897Sopenharmony_ci
254b1994897Sopenharmony_civoid ItemContainer::DeduplicateLineNumberProgram(DebugInfoItem *item, ItemDeduper *deduper)
255b1994897Sopenharmony_ci{
256b1994897Sopenharmony_ci    auto *line_number_program = item->GetLineNumberProgram();
257b1994897Sopenharmony_ci    auto *deduplicated = deduper->Deduplicate(line_number_program);
258b1994897Sopenharmony_ci    if (deduplicated != line_number_program) {
259b1994897Sopenharmony_ci        item->SetLineNumberProgram(deduplicated);
260b1994897Sopenharmony_ci        line_number_program_index_item_.Remove(line_number_program);
261b1994897Sopenharmony_ci        line_number_program_index_item_.IncRefCount(deduplicated);
262b1994897Sopenharmony_ci    }
263b1994897Sopenharmony_ci}
264b1994897Sopenharmony_ci
265b1994897Sopenharmony_civoid ItemContainer::DeduplicateDebugInfo(MethodItem *method, ItemDeduper *debug_info_deduper,
266b1994897Sopenharmony_ci                                         ItemDeduper *line_number_program_deduper)
267b1994897Sopenharmony_ci{
268b1994897Sopenharmony_ci    auto *debug_item = method->GetDebugInfo();
269b1994897Sopenharmony_ci    if (debug_item == nullptr) {
270b1994897Sopenharmony_ci        return;
271b1994897Sopenharmony_ci    }
272b1994897Sopenharmony_ci
273b1994897Sopenharmony_ci    DeduplicateLineNumberProgram(debug_item, line_number_program_deduper);
274b1994897Sopenharmony_ci
275b1994897Sopenharmony_ci    auto *deduplicated = debug_info_deduper->Deduplicate(debug_item);
276b1994897Sopenharmony_ci    if (deduplicated != debug_item) {
277b1994897Sopenharmony_ci        method->SetDebugInfo(deduplicated);
278b1994897Sopenharmony_ci        line_number_program_index_item_.DecRefCount(debug_item->GetLineNumberProgram());
279b1994897Sopenharmony_ci    }
280b1994897Sopenharmony_ci}
281b1994897Sopenharmony_ci
282b1994897Sopenharmony_civoid ItemContainer::DeduplicateCodeAndDebugInfo()
283b1994897Sopenharmony_ci{
284b1994897Sopenharmony_ci    ItemDeduper line_number_program_deduper;
285b1994897Sopenharmony_ci    ItemDeduper debug_deduper;
286b1994897Sopenharmony_ci
287b1994897Sopenharmony_ci    for (auto &p : class_map_) {
288b1994897Sopenharmony_ci        auto *item = p.second;
289b1994897Sopenharmony_ci        if (item->IsForeign()) {
290b1994897Sopenharmony_ci            continue;
291b1994897Sopenharmony_ci        }
292b1994897Sopenharmony_ci
293b1994897Sopenharmony_ci        auto *class_item = static_cast<ClassItem *>(item);
294b1994897Sopenharmony_ci
295b1994897Sopenharmony_ci        class_item->VisitMethods(
296b1994897Sopenharmony_ci            [this, &debug_deduper, &line_number_program_deduper](BaseItem *param_item) {
297b1994897Sopenharmony_ci                auto *method_item = static_cast<MethodItem *>(param_item);
298b1994897Sopenharmony_ci                DeduplicateDebugInfo(method_item, &debug_deduper, &line_number_program_deduper);
299b1994897Sopenharmony_ci                return true;
300b1994897Sopenharmony_ci            });
301b1994897Sopenharmony_ci    }
302b1994897Sopenharmony_ci}
303b1994897Sopenharmony_ci
304b1994897Sopenharmony_cistatic void DeduplicateAnnotationValue(AnnotationItem *annotation_item, ItemDeduper *deduper)
305b1994897Sopenharmony_ci{
306b1994897Sopenharmony_ci    auto *elems = annotation_item->GetElements();
307b1994897Sopenharmony_ci    const auto &tags = annotation_item->GetTags();
308b1994897Sopenharmony_ci
309b1994897Sopenharmony_ci    for (size_t i = 0; i < elems->size(); i++) {
310b1994897Sopenharmony_ci        auto tag = tags[i];
311b1994897Sopenharmony_ci
312b1994897Sopenharmony_ci        // try to dedupe only ArrayValueItems
313b1994897Sopenharmony_ci        switch (tag.GetItem()) {
314b1994897Sopenharmony_ci            case 'K':
315b1994897Sopenharmony_ci            case 'L':
316b1994897Sopenharmony_ci            case 'M':
317b1994897Sopenharmony_ci            case 'N':
318b1994897Sopenharmony_ci            case 'O':
319b1994897Sopenharmony_ci            case 'P':
320b1994897Sopenharmony_ci            case 'Q':
321b1994897Sopenharmony_ci            case 'R':
322b1994897Sopenharmony_ci            case 'S':
323b1994897Sopenharmony_ci            case 'T':
324b1994897Sopenharmony_ci            case 'U':
325b1994897Sopenharmony_ci            case 'V':
326b1994897Sopenharmony_ci            case 'W':
327b1994897Sopenharmony_ci            case 'X':
328b1994897Sopenharmony_ci            case 'Y':
329b1994897Sopenharmony_ci            case 'Z':
330b1994897Sopenharmony_ci            case '@':
331b1994897Sopenharmony_ci                break;
332b1994897Sopenharmony_ci            default:
333b1994897Sopenharmony_ci                continue;
334b1994897Sopenharmony_ci        }
335b1994897Sopenharmony_ci
336b1994897Sopenharmony_ci        auto &elem = (*elems)[i];
337b1994897Sopenharmony_ci        auto *value = elem.GetValue();
338b1994897Sopenharmony_ci        auto *deduplicated = deduper->Deduplicate(value);
339b1994897Sopenharmony_ci        if (deduplicated != value) {
340b1994897Sopenharmony_ci            elem.SetValue(deduplicated);
341b1994897Sopenharmony_ci        }
342b1994897Sopenharmony_ci    }
343b1994897Sopenharmony_ci}
344b1994897Sopenharmony_ci
345b1994897Sopenharmony_cistatic void DeduplicateAnnotations(std::vector<AnnotationItem *> *items, ItemDeduper *annotation_deduper,
346b1994897Sopenharmony_ci                                   ItemDeduper *value_deduper)
347b1994897Sopenharmony_ci{
348b1994897Sopenharmony_ci    for (auto &item : *items) {
349b1994897Sopenharmony_ci        DeduplicateAnnotationValue(item, value_deduper);
350b1994897Sopenharmony_ci        auto *deduplicated = annotation_deduper->Deduplicate(item);
351b1994897Sopenharmony_ci        if (deduplicated != item) {
352b1994897Sopenharmony_ci            item = deduplicated;
353b1994897Sopenharmony_ci        }
354b1994897Sopenharmony_ci    }
355b1994897Sopenharmony_ci}
356b1994897Sopenharmony_ci
357b1994897Sopenharmony_civoid ItemContainer::DeduplicateAnnotations()
358b1994897Sopenharmony_ci{
359b1994897Sopenharmony_ci    ItemDeduper value_deduper;
360b1994897Sopenharmony_ci    ItemDeduper annotation_deduper;
361b1994897Sopenharmony_ci
362b1994897Sopenharmony_ci    for (auto &p : class_map_) {
363b1994897Sopenharmony_ci        auto *item = p.second;
364b1994897Sopenharmony_ci        if (item->IsForeign()) {
365b1994897Sopenharmony_ci            continue;
366b1994897Sopenharmony_ci        }
367b1994897Sopenharmony_ci
368b1994897Sopenharmony_ci        auto *class_item = static_cast<ClassItem *>(item);
369b1994897Sopenharmony_ci
370b1994897Sopenharmony_ci        panda_file::DeduplicateAnnotations(class_item->GetRuntimeAnnotations(), &annotation_deduper, &value_deduper);
371b1994897Sopenharmony_ci        panda_file::DeduplicateAnnotations(class_item->GetAnnotations(), &annotation_deduper, &value_deduper);
372b1994897Sopenharmony_ci        panda_file::DeduplicateAnnotations(class_item->GetRuntimeTypeAnnotations(), &annotation_deduper,
373b1994897Sopenharmony_ci                                           &value_deduper);
374b1994897Sopenharmony_ci        panda_file::DeduplicateAnnotations(class_item->GetTypeAnnotations(), &annotation_deduper, &value_deduper);
375b1994897Sopenharmony_ci
376b1994897Sopenharmony_ci        class_item->VisitMethods([&annotation_deduper, &value_deduper](BaseItem *param_item) {
377b1994897Sopenharmony_ci            auto *method_item = static_cast<MethodItem *>(param_item);
378b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(method_item->GetRuntimeAnnotations(), &annotation_deduper,
379b1994897Sopenharmony_ci                                               &value_deduper);
380b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(method_item->GetAnnotations(), &annotation_deduper, &value_deduper);
381b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(method_item->GetRuntimeTypeAnnotations(), &annotation_deduper,
382b1994897Sopenharmony_ci                                               &value_deduper);
383b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(method_item->GetTypeAnnotations(), &annotation_deduper, &value_deduper);
384b1994897Sopenharmony_ci            return true;
385b1994897Sopenharmony_ci        });
386b1994897Sopenharmony_ci
387b1994897Sopenharmony_ci        class_item->VisitFields([&annotation_deduper, &value_deduper](BaseItem *param_item) {
388b1994897Sopenharmony_ci            auto *field_item = static_cast<FieldItem *>(param_item);
389b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(field_item->GetRuntimeAnnotations(), &annotation_deduper,
390b1994897Sopenharmony_ci                                               &value_deduper);
391b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(field_item->GetAnnotations(), &annotation_deduper, &value_deduper);
392b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(field_item->GetRuntimeTypeAnnotations(), &annotation_deduper,
393b1994897Sopenharmony_ci                                               &value_deduper);
394b1994897Sopenharmony_ci            panda_file::DeduplicateAnnotations(field_item->GetTypeAnnotations(), &annotation_deduper, &value_deduper);
395b1994897Sopenharmony_ci            return true;
396b1994897Sopenharmony_ci        });
397b1994897Sopenharmony_ci    }
398b1994897Sopenharmony_ci}
399b1994897Sopenharmony_ci
400b1994897Sopenharmony_civoid ItemContainer::DeduplicateItems(bool computeLayout)
401b1994897Sopenharmony_ci{
402b1994897Sopenharmony_ci    if (computeLayout) {
403b1994897Sopenharmony_ci        ComputeLayout();
404b1994897Sopenharmony_ci    }
405b1994897Sopenharmony_ci    DeduplicateCodeAndDebugInfo();
406b1994897Sopenharmony_ci    DeduplicateAnnotations();
407b1994897Sopenharmony_ci}
408b1994897Sopenharmony_ci
409b1994897Sopenharmony_cistatic bool Compare(const std::unique_ptr<BaseItem> &item1, const std::unique_ptr<BaseItem> &item2)
410b1994897Sopenharmony_ci{
411b1994897Sopenharmony_ci    return item1->GetReLayoutRank() > item2->GetReLayoutRank();
412b1994897Sopenharmony_ci}
413b1994897Sopenharmony_ci
414b1994897Sopenharmony_civoid ItemContainer::ReLayout()
415b1994897Sopenharmony_ci{
416b1994897Sopenharmony_ci    for (auto &item : items_) {
417b1994897Sopenharmony_ci        if (!item->NeedsEmit()) {
418b1994897Sopenharmony_ci            continue;
419b1994897Sopenharmony_ci        }
420b1994897Sopenharmony_ci
421b1994897Sopenharmony_ci        /* Because only class items and func_main_0 will be accessed in runtime's initialization,
422b1994897Sopenharmony_ci         * the items in abc will be arranged in following order to increase cache hit rate:
423b1994897Sopenharmony_ci         *     class items -> string items(for field name) -> other items
424b1994897Sopenharmony_ci         */
425b1994897Sopenharmony_ci        switch (item->GetItemType()) {
426b1994897Sopenharmony_ci            case ItemTypes::CLASS_ITEM: {
427b1994897Sopenharmony_ci                item->SetReLayoutRank(ItemRank::CLASS_ITEM_RANK);
428b1994897Sopenharmony_ci                break;
429b1994897Sopenharmony_ci            }
430b1994897Sopenharmony_ci            case ItemTypes::STRING_ITEM: {
431b1994897Sopenharmony_ci                item->SetReLayoutRank(ItemRank::STRING_ITEM_RANK);
432b1994897Sopenharmony_ci                break;
433b1994897Sopenharmony_ci            }
434b1994897Sopenharmony_ci            default: {
435b1994897Sopenharmony_ci                break;
436b1994897Sopenharmony_ci            }
437b1994897Sopenharmony_ci        }
438b1994897Sopenharmony_ci    }
439b1994897Sopenharmony_ci
440b1994897Sopenharmony_ci    items_.sort(Compare);
441b1994897Sopenharmony_ci}
442b1994897Sopenharmony_ci
443b1994897Sopenharmony_ciuint32_t ItemContainer::ComputeLayout()
444b1994897Sopenharmony_ci{
445b1994897Sopenharmony_ci    const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
446b1994897Sopenharmony_ci    uint32_t original_offset = 0;
447b1994897Sopenharmony_ci    uint32_t num_classes = class_map_.size();
448b1994897Sopenharmony_ci    uint32_t num_literalarrays = literalarray_map_.size();
449b1994897Sopenharmony_ci    uint32_t class_idx_offset = sizeof(File::Header);
450b1994897Sopenharmony_ci    uint32_t cur_offset = 0;
451b1994897Sopenharmony_ci    if (ContainsLiteralArrayInHeader(bc_version.value())) {
452b1994897Sopenharmony_ci        cur_offset = class_idx_offset + (num_classes + num_literalarrays) * ID_SIZE;
453b1994897Sopenharmony_ci    } else {
454b1994897Sopenharmony_ci        cur_offset = class_idx_offset + (num_classes * ID_SIZE);
455b1994897Sopenharmony_ci    }
456b1994897Sopenharmony_ci    items_round_up_size_.clear();
457b1994897Sopenharmony_ci    foreign_item_roundup_size_ = 0;
458b1994897Sopenharmony_ci
459b1994897Sopenharmony_ci    UpdateOrderIndexes();
460b1994897Sopenharmony_ci
461b1994897Sopenharmony_ci    RebuildIndexSection();
462b1994897Sopenharmony_ci    RebuildLineNumberProgramIndex();
463b1994897Sopenharmony_ci
464b1994897Sopenharmony_ci    index_section_item_.SetOffset(cur_offset);
465b1994897Sopenharmony_ci    index_section_item_.ComputeLayout();
466b1994897Sopenharmony_ci    cur_offset += index_section_item_.GetSize();
467b1994897Sopenharmony_ci
468b1994897Sopenharmony_ci    for (auto &item : foreign_items_) {
469b1994897Sopenharmony_ci        original_offset = cur_offset;
470b1994897Sopenharmony_ci        cur_offset = RoundUp(cur_offset, item->Alignment());
471b1994897Sopenharmony_ci        foreign_item_roundup_size_ += CalculateRoundUpSize(original_offset, cur_offset);
472b1994897Sopenharmony_ci        item->SetOffset(cur_offset);
473b1994897Sopenharmony_ci        item->ComputeLayout();
474b1994897Sopenharmony_ci        cur_offset += item->GetSize();
475b1994897Sopenharmony_ci    }
476b1994897Sopenharmony_ci
477b1994897Sopenharmony_ci    for (auto &item : items_) {
478b1994897Sopenharmony_ci        const auto &name = item->GetName();
479b1994897Sopenharmony_ci
480b1994897Sopenharmony_ci        if (!item->NeedsEmit()) {
481b1994897Sopenharmony_ci            continue;
482b1994897Sopenharmony_ci        }
483b1994897Sopenharmony_ci
484b1994897Sopenharmony_ci        original_offset = cur_offset;
485b1994897Sopenharmony_ci        cur_offset = RoundUp(cur_offset, item->Alignment());
486b1994897Sopenharmony_ci        items_round_up_size_[name] += CalculateRoundUpSize(original_offset, cur_offset);
487b1994897Sopenharmony_ci        item->SetOffset(cur_offset);
488b1994897Sopenharmony_ci        item->ComputeLayout();
489b1994897Sopenharmony_ci        cur_offset += item->GetSize();
490b1994897Sopenharmony_ci    }
491b1994897Sopenharmony_ci
492b1994897Sopenharmony_ci    // Line number program should be last because it's size is known only after deduplication
493b1994897Sopenharmony_ci    original_offset = cur_offset;
494b1994897Sopenharmony_ci    cur_offset = RoundUp(cur_offset, line_number_program_index_item_.Alignment());
495b1994897Sopenharmony_ci    line_number_item_roundup_size_ = CalculateRoundUpSize(original_offset, cur_offset);
496b1994897Sopenharmony_ci    line_number_program_index_item_.SetOffset(cur_offset);
497b1994897Sopenharmony_ci    line_number_program_index_item_.ComputeLayout();
498b1994897Sopenharmony_ci    cur_offset += line_number_program_index_item_.GetSize();
499b1994897Sopenharmony_ci
500b1994897Sopenharmony_ci    end_->SetOffset(cur_offset);
501b1994897Sopenharmony_ci
502b1994897Sopenharmony_ci    return cur_offset;
503b1994897Sopenharmony_ci}
504b1994897Sopenharmony_ci
505b1994897Sopenharmony_civoid ItemContainer::RebuildLineNumberProgramIndex()
506b1994897Sopenharmony_ci{
507b1994897Sopenharmony_ci    line_number_program_index_item_.Reset();
508b1994897Sopenharmony_ci    line_number_program_index_item_.UpdateItems(nullptr, nullptr);
509b1994897Sopenharmony_ci}
510b1994897Sopenharmony_ci
511b1994897Sopenharmony_civoid ItemContainer::RebuildIndexSection()
512b1994897Sopenharmony_ci{
513b1994897Sopenharmony_ci    index_section_item_.Reset();
514b1994897Sopenharmony_ci
515b1994897Sopenharmony_ci    for (auto &item : foreign_items_) {
516b1994897Sopenharmony_ci        ProcessIndexDependecies(item.get());
517b1994897Sopenharmony_ci    }
518b1994897Sopenharmony_ci
519b1994897Sopenharmony_ci    for (auto &item : items_) {
520b1994897Sopenharmony_ci        if (!item->NeedsEmit()) {
521b1994897Sopenharmony_ci            continue;
522b1994897Sopenharmony_ci        }
523b1994897Sopenharmony_ci
524b1994897Sopenharmony_ci        ProcessIndexDependecies(item.get());
525b1994897Sopenharmony_ci    }
526b1994897Sopenharmony_ci
527b1994897Sopenharmony_ci    if (!index_section_item_.IsEmpty()) {
528b1994897Sopenharmony_ci        index_section_item_.GetCurrentHeader()->SetEnd(end_);
529b1994897Sopenharmony_ci    }
530b1994897Sopenharmony_ci
531b1994897Sopenharmony_ci    index_section_item_.UpdateItems();
532b1994897Sopenharmony_ci}
533b1994897Sopenharmony_ci
534b1994897Sopenharmony_civoid ItemContainer::UpdateOrderIndexes()
535b1994897Sopenharmony_ci{
536b1994897Sopenharmony_ci    size_t idx = 0;
537b1994897Sopenharmony_ci
538b1994897Sopenharmony_ci    for (auto &item : foreign_items_) {
539b1994897Sopenharmony_ci        item->SetOrderIndex(idx++);
540b1994897Sopenharmony_ci        item->Visit([&idx](BaseItem *param_item) {
541b1994897Sopenharmony_ci            param_item->SetOrderIndex(idx++);
542b1994897Sopenharmony_ci            return true;
543b1994897Sopenharmony_ci        });
544b1994897Sopenharmony_ci    }
545b1994897Sopenharmony_ci
546b1994897Sopenharmony_ci    for (auto &item : items_) {
547b1994897Sopenharmony_ci        if (!item->NeedsEmit()) {
548b1994897Sopenharmony_ci            continue;
549b1994897Sopenharmony_ci        }
550b1994897Sopenharmony_ci
551b1994897Sopenharmony_ci        item->SetOrderIndex(idx++);
552b1994897Sopenharmony_ci        item->Visit([&idx](BaseItem *param_item) {
553b1994897Sopenharmony_ci            param_item->SetOrderIndex(idx++);
554b1994897Sopenharmony_ci            return true;
555b1994897Sopenharmony_ci        });
556b1994897Sopenharmony_ci    }
557b1994897Sopenharmony_ci
558b1994897Sopenharmony_ci    end_->SetOrderIndex(idx++);
559b1994897Sopenharmony_ci}
560b1994897Sopenharmony_ci
561b1994897Sopenharmony_civoid ItemContainer::ReorderItems(panda::panda_file::pgo::ProfileOptimizer *profile_opt)
562b1994897Sopenharmony_ci{
563b1994897Sopenharmony_ci    profile_opt->ProfileGuidedRelayout(items_);
564b1994897Sopenharmony_ci}
565b1994897Sopenharmony_ci
566b1994897Sopenharmony_civoid ItemContainer::AddIndexDependecies(BaseItem *item)
567b1994897Sopenharmony_ci{
568b1994897Sopenharmony_ci    if (index_section_item_.IsEmpty()) {
569b1994897Sopenharmony_ci        index_section_item_.AddHeader();
570b1994897Sopenharmony_ci        index_section_item_.GetCurrentHeader()->SetStart(item);
571b1994897Sopenharmony_ci    }
572b1994897Sopenharmony_ci    const auto &item_deps = item->GetIndexDependencies();
573b1994897Sopenharmony_ci    if (!index_section_item_.GetCurrentHeader()->Add(item_deps)) {
574b1994897Sopenharmony_ci        index_section_item_.GetCurrentHeader()->SetEnd(item);
575b1994897Sopenharmony_ci        index_section_item_.AddHeader();
576b1994897Sopenharmony_ci        index_section_item_.GetCurrentHeader()->SetStart(item);
577b1994897Sopenharmony_ci        if (!index_section_item_.GetCurrentHeader()->Add(item_deps)) {
578b1994897Sopenharmony_ci            LOG(FATAL, PANDAFILE) << "Cannot add " << item_deps.size() << " items to index";
579b1994897Sopenharmony_ci            UNREACHABLE();
580b1994897Sopenharmony_ci        }
581b1994897Sopenharmony_ci    }
582b1994897Sopenharmony_ci    if (item->GetName() == "method_item") {
583b1994897Sopenharmony_ci        ASSERT(index_section_item_.GetNumHeaders() >= 1);
584b1994897Sopenharmony_ci        static_cast<BaseMethodItem *>(item)->SetHeaderIndex(index_section_item_.GetNumHeaders() - 1);
585b1994897Sopenharmony_ci    }
586b1994897Sopenharmony_ci}
587b1994897Sopenharmony_ci
588b1994897Sopenharmony_civoid ItemContainer::ProcessIndexDependecies(BaseItem *item)
589b1994897Sopenharmony_ci{
590b1994897Sopenharmony_ci    AddIndexDependecies(item);
591b1994897Sopenharmony_ci    item->Visit([&](BaseItem *param_item) {
592b1994897Sopenharmony_ci        AddIndexDependecies(param_item);
593b1994897Sopenharmony_ci        return true;
594b1994897Sopenharmony_ci    });
595b1994897Sopenharmony_ci}
596b1994897Sopenharmony_ci
597b1994897Sopenharmony_cibool ItemContainer::WriteHeaderIndexInfo(Writer *writer)
598b1994897Sopenharmony_ci{
599b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(class_map_.size())) {
600b1994897Sopenharmony_ci        return false;
601b1994897Sopenharmony_ci    }
602b1994897Sopenharmony_ci
603b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(sizeof(File::Header))) {
604b1994897Sopenharmony_ci        return false;
605b1994897Sopenharmony_ci    }
606b1994897Sopenharmony_ci
607b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(line_number_program_index_item_.GetNumItems())) {
608b1994897Sopenharmony_ci        return false;
609b1994897Sopenharmony_ci    }
610b1994897Sopenharmony_ci
611b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(line_number_program_index_item_.GetOffset())) {
612b1994897Sopenharmony_ci        return false;
613b1994897Sopenharmony_ci    }
614b1994897Sopenharmony_ci
615b1994897Sopenharmony_ci    const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
616b1994897Sopenharmony_ci
617b1994897Sopenharmony_ci    uint32_t num_literalarrays = INVALID_INDEX;
618b1994897Sopenharmony_ci    uint32_t literalarray_idx_offset = INVALID_OFFSET;
619b1994897Sopenharmony_ci    size_t index_section_off = sizeof(File::Header) + class_map_.size() * ID_SIZE;
620b1994897Sopenharmony_ci
621b1994897Sopenharmony_ci    if (ContainsLiteralArrayInHeader(bc_version.value())) {
622b1994897Sopenharmony_ci        num_literalarrays = literalarray_map_.size();
623b1994897Sopenharmony_ci        literalarray_idx_offset = sizeof(File::Header) + class_map_.size() * ID_SIZE;
624b1994897Sopenharmony_ci        index_section_off = literalarray_idx_offset + num_literalarrays * ID_SIZE;
625b1994897Sopenharmony_ci    }
626b1994897Sopenharmony_ci
627b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(num_literalarrays)) {
628b1994897Sopenharmony_ci        return false;
629b1994897Sopenharmony_ci    }
630b1994897Sopenharmony_ci
631b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(literalarray_idx_offset)) {
632b1994897Sopenharmony_ci        return false;
633b1994897Sopenharmony_ci    }
634b1994897Sopenharmony_ci
635b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(index_section_item_.GetNumHeaders())) {
636b1994897Sopenharmony_ci        return false;
637b1994897Sopenharmony_ci    }
638b1994897Sopenharmony_ci
639b1994897Sopenharmony_ci    return writer->Write<uint32_t>(index_section_off);
640b1994897Sopenharmony_ci}
641b1994897Sopenharmony_ci
642b1994897Sopenharmony_cibool ItemContainer::WriteHeader(Writer *writer, ssize_t *checksum_offset)
643b1994897Sopenharmony_ci{
644b1994897Sopenharmony_ci    uint32_t file_size = ComputeLayout();
645b1994897Sopenharmony_ci    writer->ReserveBufferCapacity(file_size);
646b1994897Sopenharmony_ci
647b1994897Sopenharmony_ci    std::vector<uint8_t> magic;
648b1994897Sopenharmony_ci    magic.assign(File::MAGIC.cbegin(), File::MAGIC.cend());
649b1994897Sopenharmony_ci    if (!writer->WriteBytes(magic)) {
650b1994897Sopenharmony_ci        return false;
651b1994897Sopenharmony_ci    }
652b1994897Sopenharmony_ci
653b1994897Sopenharmony_ci    *checksum_offset = writer->GetOffset();
654b1994897Sopenharmony_ci    uint32_t checksum = 0;
655b1994897Sopenharmony_ci    if (!writer->Write(checksum)) {
656b1994897Sopenharmony_ci        return false;
657b1994897Sopenharmony_ci    }
658b1994897Sopenharmony_ci    writer->CountChecksum(true);
659b1994897Sopenharmony_ci
660b1994897Sopenharmony_ci    const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
661b1994897Sopenharmony_ci    std::vector<uint8_t> versionVec(std::begin(bc_version.value()), std::end(bc_version.value()));
662b1994897Sopenharmony_ci
663b1994897Sopenharmony_ci    if (!writer->WriteBytes(versionVec)) {
664b1994897Sopenharmony_ci        return false;
665b1994897Sopenharmony_ci    }
666b1994897Sopenharmony_ci
667b1994897Sopenharmony_ci    if (!writer->Write(file_size)) {
668b1994897Sopenharmony_ci        return false;
669b1994897Sopenharmony_ci    }
670b1994897Sopenharmony_ci
671b1994897Sopenharmony_ci    uint32_t foreign_offset = GetForeignOffset();
672b1994897Sopenharmony_ci    if (!writer->Write(foreign_offset)) {
673b1994897Sopenharmony_ci        return false;
674b1994897Sopenharmony_ci    }
675b1994897Sopenharmony_ci
676b1994897Sopenharmony_ci    uint32_t foreign_size = GetForeignSize();
677b1994897Sopenharmony_ci    if (!writer->Write(foreign_size)) {
678b1994897Sopenharmony_ci        return false;
679b1994897Sopenharmony_ci    }
680b1994897Sopenharmony_ci
681b1994897Sopenharmony_ci    return WriteHeaderIndexInfo(writer);
682b1994897Sopenharmony_ci}
683b1994897Sopenharmony_ci
684b1994897Sopenharmony_cibool ItemContainer::WriteItems(Writer *writer)
685b1994897Sopenharmony_ci{
686b1994897Sopenharmony_ci    ASSERT(writer != nullptr);
687b1994897Sopenharmony_ci    for (auto &item : foreign_items_) {
688b1994897Sopenharmony_ci        if (!writer->Align(item->Alignment())) {
689b1994897Sopenharmony_ci            return false;
690b1994897Sopenharmony_ci        }
691b1994897Sopenharmony_ci
692b1994897Sopenharmony_ci        if (!item->Write(writer)) {
693b1994897Sopenharmony_ci            return false;
694b1994897Sopenharmony_ci        }
695b1994897Sopenharmony_ci    }
696b1994897Sopenharmony_ci
697b1994897Sopenharmony_ci    for (auto &item : items_) {
698b1994897Sopenharmony_ci        if (!item->NeedsEmit()) {
699b1994897Sopenharmony_ci            continue;
700b1994897Sopenharmony_ci        }
701b1994897Sopenharmony_ci
702b1994897Sopenharmony_ci        if (!writer->Align(item->Alignment())) {
703b1994897Sopenharmony_ci            return false;
704b1994897Sopenharmony_ci        }
705b1994897Sopenharmony_ci
706b1994897Sopenharmony_ci        if (!item->Write(writer)) {
707b1994897Sopenharmony_ci            return false;
708b1994897Sopenharmony_ci        }
709b1994897Sopenharmony_ci    }
710b1994897Sopenharmony_ci    return true;
711b1994897Sopenharmony_ci}
712b1994897Sopenharmony_ci
713b1994897Sopenharmony_cibool ItemContainer::Write(Writer *writer, bool deduplicateItems)
714b1994897Sopenharmony_ci{
715b1994897Sopenharmony_ci    if (deduplicateItems) {
716b1994897Sopenharmony_ci        DeduplicateItems();
717b1994897Sopenharmony_ci    }
718b1994897Sopenharmony_ci
719b1994897Sopenharmony_ci    ssize_t checksum_offset = -1;
720b1994897Sopenharmony_ci    if (!WriteHeader(writer, &checksum_offset)) {
721b1994897Sopenharmony_ci        return false;
722b1994897Sopenharmony_ci    }
723b1994897Sopenharmony_ci    ASSERT(checksum_offset != -1);
724b1994897Sopenharmony_ci
725b1994897Sopenharmony_ci    // Write class idx
726b1994897Sopenharmony_ci
727b1994897Sopenharmony_ci    for (auto &entry : class_map_) {
728b1994897Sopenharmony_ci        if (!writer->Write(entry.second->GetOffset())) {
729b1994897Sopenharmony_ci            return false;
730b1994897Sopenharmony_ci        }
731b1994897Sopenharmony_ci    }
732b1994897Sopenharmony_ci
733b1994897Sopenharmony_ci    // Write literalArray idx
734b1994897Sopenharmony_ci
735b1994897Sopenharmony_ci    const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
736b1994897Sopenharmony_ci    if (ContainsLiteralArrayInHeader(bc_version.value())) {
737b1994897Sopenharmony_ci        for (auto &entry : literalarray_map_) {
738b1994897Sopenharmony_ci            if (!writer->Write(entry.second->GetOffset())) {
739b1994897Sopenharmony_ci                return false;
740b1994897Sopenharmony_ci            }
741b1994897Sopenharmony_ci        }
742b1994897Sopenharmony_ci    }
743b1994897Sopenharmony_ci
744b1994897Sopenharmony_ci    // Write index section
745b1994897Sopenharmony_ci
746b1994897Sopenharmony_ci    if (!index_section_item_.Write(writer)) {
747b1994897Sopenharmony_ci        return false;
748b1994897Sopenharmony_ci    }
749b1994897Sopenharmony_ci
750b1994897Sopenharmony_ci    if (!WriteItems(writer)) {
751b1994897Sopenharmony_ci        return false;
752b1994897Sopenharmony_ci    }
753b1994897Sopenharmony_ci
754b1994897Sopenharmony_ci    if (!writer->Align(line_number_program_index_item_.Alignment())) {
755b1994897Sopenharmony_ci        return false;
756b1994897Sopenharmony_ci    }
757b1994897Sopenharmony_ci
758b1994897Sopenharmony_ci    // Write line number program idx
759b1994897Sopenharmony_ci
760b1994897Sopenharmony_ci    if (!line_number_program_index_item_.Write(writer)) {
761b1994897Sopenharmony_ci        return false;
762b1994897Sopenharmony_ci    }
763b1994897Sopenharmony_ci
764b1994897Sopenharmony_ci    writer->CountChecksum(false);
765b1994897Sopenharmony_ci    writer->RewriteChecksum(checksum_offset);
766b1994897Sopenharmony_ci
767b1994897Sopenharmony_ci    return writer->FinishWrite();
768b1994897Sopenharmony_ci}
769b1994897Sopenharmony_ci
770b1994897Sopenharmony_cistd::map<std::string, size_t> ItemContainer::GetStat()
771b1994897Sopenharmony_ci{
772b1994897Sopenharmony_ci    std::map<std::string, size_t> stat;
773b1994897Sopenharmony_ci
774b1994897Sopenharmony_ci    DeduplicateItems();
775b1994897Sopenharmony_ci    ComputeLayout();
776b1994897Sopenharmony_ci
777b1994897Sopenharmony_ci    stat["header_item"] = sizeof(File::Header);
778b1994897Sopenharmony_ci    stat["class_idx_item"] = class_map_.size() * ID_SIZE;
779b1994897Sopenharmony_ci    stat["line_number_program_idx_item"] = line_number_program_index_item_.GetNumItems() * ID_SIZE
780b1994897Sopenharmony_ci                                           + line_number_item_roundup_size_;
781b1994897Sopenharmony_ci    const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
782b1994897Sopenharmony_ci    if (ContainsLiteralArrayInHeader(bc_version.value())) {
783b1994897Sopenharmony_ci        stat["literalarray_idx"] = literalarray_map_.size() * ID_SIZE;
784b1994897Sopenharmony_ci    } else {
785b1994897Sopenharmony_ci        stat["literalarray_idx"] = 0;
786b1994897Sopenharmony_ci    }
787b1994897Sopenharmony_ci
788b1994897Sopenharmony_ci    stat["index_section_item"] = index_section_item_.GetSize();
789b1994897Sopenharmony_ci    stat["foreign_item"] = GetForeignSize() + foreign_item_roundup_size_;
790b1994897Sopenharmony_ci
791b1994897Sopenharmony_ci    size_t num_ins = 0;
792b1994897Sopenharmony_ci    size_t codesize = 0;
793b1994897Sopenharmony_ci    for (auto &item : items_) {
794b1994897Sopenharmony_ci        if (!item->NeedsEmit()) {
795b1994897Sopenharmony_ci            continue;
796b1994897Sopenharmony_ci        }
797b1994897Sopenharmony_ci
798b1994897Sopenharmony_ci        const auto &name = item->GetName();
799b1994897Sopenharmony_ci        size_t size = item->GetSize();
800b1994897Sopenharmony_ci        auto it = stat.find(name);
801b1994897Sopenharmony_ci        if (it != stat.cend()) {
802b1994897Sopenharmony_ci            stat[name] += size;
803b1994897Sopenharmony_ci        } else if (size != 0) {
804b1994897Sopenharmony_ci            stat[name] = size;
805b1994897Sopenharmony_ci        }
806b1994897Sopenharmony_ci        if (name == "code_item") {
807b1994897Sopenharmony_ci            num_ins += static_cast<CodeItem *>(item.get())->GetNumInstructions();
808b1994897Sopenharmony_ci            codesize += static_cast<CodeItem *>(item.get())->GetCodeSize();
809b1994897Sopenharmony_ci        }
810b1994897Sopenharmony_ci    }
811b1994897Sopenharmony_ci
812b1994897Sopenharmony_ci    for (const auto &[name, round_up_size] : items_round_up_size_) {
813b1994897Sopenharmony_ci        stat[name] += round_up_size;
814b1994897Sopenharmony_ci    }
815b1994897Sopenharmony_ci    stat["instructions_number"] = num_ins;
816b1994897Sopenharmony_ci    stat["codesize"] = codesize;
817b1994897Sopenharmony_ci
818b1994897Sopenharmony_ci    return stat;
819b1994897Sopenharmony_ci}
820b1994897Sopenharmony_ci
821b1994897Sopenharmony_civoid ItemContainer::DumpItemsStat(std::ostream &os) const
822b1994897Sopenharmony_ci{
823b1994897Sopenharmony_ci    struct Stat {
824b1994897Sopenharmony_ci        size_t n;
825b1994897Sopenharmony_ci        size_t total_size;
826b1994897Sopenharmony_ci    };
827b1994897Sopenharmony_ci
828b1994897Sopenharmony_ci    std::map<std::string, Stat> stat;
829b1994897Sopenharmony_ci
830b1994897Sopenharmony_ci    auto collect_stat = [&stat](auto &items) {
831b1994897Sopenharmony_ci        for (auto &item : items) {
832b1994897Sopenharmony_ci            if (!item->NeedsEmit()) {
833b1994897Sopenharmony_ci                continue;
834b1994897Sopenharmony_ci            }
835b1994897Sopenharmony_ci
836b1994897Sopenharmony_ci            const auto &name = item->GetName();
837b1994897Sopenharmony_ci            size_t size = item->GetSize();
838b1994897Sopenharmony_ci            auto it = stat.find(name);
839b1994897Sopenharmony_ci            if (it != stat.cend()) {
840b1994897Sopenharmony_ci                stat[name].n += 1;
841b1994897Sopenharmony_ci                stat[name].total_size += size;
842b1994897Sopenharmony_ci            } else if (size != 0) {
843b1994897Sopenharmony_ci                stat[name] = {1, size};
844b1994897Sopenharmony_ci            }
845b1994897Sopenharmony_ci        }
846b1994897Sopenharmony_ci    };
847b1994897Sopenharmony_ci
848b1994897Sopenharmony_ci    collect_stat(foreign_items_);
849b1994897Sopenharmony_ci    collect_stat(items_);
850b1994897Sopenharmony_ci
851b1994897Sopenharmony_ci    for (auto &[name, elem] : stat) {
852b1994897Sopenharmony_ci        os << name << ":" << std::endl;
853b1994897Sopenharmony_ci        os << "    n          = " << elem.n << std::endl;
854b1994897Sopenharmony_ci        os << "    total size = " << elem.total_size << std::endl;
855b1994897Sopenharmony_ci    }
856b1994897Sopenharmony_ci}
857b1994897Sopenharmony_ci
858b1994897Sopenharmony_cisize_t ItemContainer::GetForeignOffset() const
859b1994897Sopenharmony_ci{
860b1994897Sopenharmony_ci    if (foreign_items_.empty()) {
861b1994897Sopenharmony_ci        return 0;
862b1994897Sopenharmony_ci    }
863b1994897Sopenharmony_ci
864b1994897Sopenharmony_ci    return foreign_items_.front()->GetOffset();
865b1994897Sopenharmony_ci}
866b1994897Sopenharmony_ci
867b1994897Sopenharmony_cisize_t ItemContainer::GetForeignSize() const
868b1994897Sopenharmony_ci{
869b1994897Sopenharmony_ci    if (foreign_items_.empty()) {
870b1994897Sopenharmony_ci        return 0;
871b1994897Sopenharmony_ci    }
872b1994897Sopenharmony_ci
873b1994897Sopenharmony_ci    size_t begin = foreign_items_.front()->GetOffset();
874b1994897Sopenharmony_ci    size_t end = foreign_items_.back()->GetOffset() + foreign_items_.back()->GetSize();
875b1994897Sopenharmony_ci
876b1994897Sopenharmony_ci    return end - begin;
877b1994897Sopenharmony_ci}
878b1994897Sopenharmony_ci
879b1994897Sopenharmony_cibool ItemContainer::IndexHeaderItem::Write(Writer *writer)
880b1994897Sopenharmony_ci{
881b1994897Sopenharmony_ci    ASSERT(GetOffset() == writer->GetOffset());
882b1994897Sopenharmony_ci    ASSERT(start_ != nullptr);
883b1994897Sopenharmony_ci    ASSERT(start_->GetOffset() != 0);
884b1994897Sopenharmony_ci    ASSERT(end_ != nullptr);
885b1994897Sopenharmony_ci    ASSERT(end_->GetOffset() != 0);
886b1994897Sopenharmony_ci
887b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(start_->GetOffset())) {
888b1994897Sopenharmony_ci        return false;
889b1994897Sopenharmony_ci    }
890b1994897Sopenharmony_ci
891b1994897Sopenharmony_ci    if (!writer->Write<uint32_t>(end_->GetOffset())) {
892b1994897Sopenharmony_ci        return false;
893b1994897Sopenharmony_ci    }
894b1994897Sopenharmony_ci
895b1994897Sopenharmony_ci    for (auto *index_item : indexes_) {
896b1994897Sopenharmony_ci        if (!index_item->NeedsEmit()) {
897b1994897Sopenharmony_ci            // reserve [field_idx_size] | [proto_idx_size] field
898b1994897Sopenharmony_ci            if (!writer->Write<uint32_t>(INVALID_INDEX)) {
899b1994897Sopenharmony_ci                return false;
900b1994897Sopenharmony_ci            }
901b1994897Sopenharmony_ci            // reserve [field_idx_off] | [proto_idx_off] field
902b1994897Sopenharmony_ci            if (!writer->Write<uint32_t>(INVALID_OFFSET)) {
903b1994897Sopenharmony_ci                return false;
904b1994897Sopenharmony_ci            }
905b1994897Sopenharmony_ci        } else {
906b1994897Sopenharmony_ci            if (!writer->Write<uint32_t>(index_item->GetNumItems())) {
907b1994897Sopenharmony_ci                return false;
908b1994897Sopenharmony_ci            }
909b1994897Sopenharmony_ci
910b1994897Sopenharmony_ci            ASSERT(index_item->GetOffset() != 0);
911b1994897Sopenharmony_ci            if (!writer->Write<uint32_t>(index_item->GetOffset())) {
912b1994897Sopenharmony_ci                return false;
913b1994897Sopenharmony_ci            }
914b1994897Sopenharmony_ci        }
915b1994897Sopenharmony_ci    }
916b1994897Sopenharmony_ci
917b1994897Sopenharmony_ci    return true;
918b1994897Sopenharmony_ci}
919b1994897Sopenharmony_ci
920b1994897Sopenharmony_cibool ItemContainer::IndexHeaderItem::Add(const std::list<IndexedItem *> &items)
921b1994897Sopenharmony_ci{
922b1994897Sopenharmony_ci    std::list<IndexedItem *> added_items;
923b1994897Sopenharmony_ci
924b1994897Sopenharmony_ci    for (auto *item : items) {
925b1994897Sopenharmony_ci        auto type = item->GetIndexType();
926b1994897Sopenharmony_ci        ASSERT(type != IndexType::NONE);
927b1994897Sopenharmony_ci
928b1994897Sopenharmony_ci        auto *index_item = IndexGetIndexByType(type);
929b1994897Sopenharmony_ci
930b1994897Sopenharmony_ci        if (index_item->Has(item)) {
931b1994897Sopenharmony_ci            continue;
932b1994897Sopenharmony_ci        }
933b1994897Sopenharmony_ci
934b1994897Sopenharmony_ci        if (!index_item->Add(item)) {
935b1994897Sopenharmony_ci            Remove(added_items);
936b1994897Sopenharmony_ci            return false;
937b1994897Sopenharmony_ci        }
938b1994897Sopenharmony_ci
939b1994897Sopenharmony_ci        added_items.push_back(item);
940b1994897Sopenharmony_ci    }
941b1994897Sopenharmony_ci
942b1994897Sopenharmony_ci    return true;
943b1994897Sopenharmony_ci}
944b1994897Sopenharmony_ci
945b1994897Sopenharmony_civoid ItemContainer::IndexHeaderItem::Remove(const std::list<IndexedItem *> &items)
946b1994897Sopenharmony_ci{
947b1994897Sopenharmony_ci    for (auto *item : items) {
948b1994897Sopenharmony_ci        auto type = item->GetIndexType();
949b1994897Sopenharmony_ci        ASSERT(type != IndexType::NONE);
950b1994897Sopenharmony_ci
951b1994897Sopenharmony_ci        auto *index_item = IndexGetIndexByType(type);
952b1994897Sopenharmony_ci        index_item->Remove(item);
953b1994897Sopenharmony_ci    }
954b1994897Sopenharmony_ci}
955b1994897Sopenharmony_ci
956b1994897Sopenharmony_cibool ItemContainer::IndexItem::Write(Writer *writer)
957b1994897Sopenharmony_ci{
958b1994897Sopenharmony_ci    ASSERT(GetOffset() == writer->GetOffset());
959b1994897Sopenharmony_ci
960b1994897Sopenharmony_ci    if (NeedsEmit()) {
961b1994897Sopenharmony_ci        for (auto *item : index_) {
962b1994897Sopenharmony_ci            if (!writer->Write<uint32_t>(item->GetOffset())) {
963b1994897Sopenharmony_ci                return false;
964b1994897Sopenharmony_ci            }
965b1994897Sopenharmony_ci        }
966b1994897Sopenharmony_ci    }
967b1994897Sopenharmony_ci
968b1994897Sopenharmony_ci    return true;
969b1994897Sopenharmony_ci}
970b1994897Sopenharmony_ci
971b1994897Sopenharmony_ciItemTypes ItemContainer::IndexItem::GetItemType() const
972b1994897Sopenharmony_ci{
973b1994897Sopenharmony_ci    switch (type_) {
974b1994897Sopenharmony_ci        case IndexType::CLASS:
975b1994897Sopenharmony_ci            return ItemTypes::CLASS_INDEX_ITEM;
976b1994897Sopenharmony_ci        case IndexType::METHOD_STRING_LITERAL:
977b1994897Sopenharmony_ci            return ItemTypes::METHOD_INDEX_ITEM;
978b1994897Sopenharmony_ci        case IndexType::FIELD:
979b1994897Sopenharmony_ci            return ItemTypes::FIELD_INDEX_ITEM;
980b1994897Sopenharmony_ci        case IndexType::PROTO:
981b1994897Sopenharmony_ci            return ItemTypes::PROTO_INDEX_ITEM;
982b1994897Sopenharmony_ci        case IndexType::LINE_NUMBER_PROG:
983b1994897Sopenharmony_ci            return ItemTypes::LINE_NUMBER_PROGRAM_INDEX_ITEM;
984b1994897Sopenharmony_ci        default:
985b1994897Sopenharmony_ci            break;
986b1994897Sopenharmony_ci    }
987b1994897Sopenharmony_ci
988b1994897Sopenharmony_ci    UNREACHABLE();
989b1994897Sopenharmony_ci}
990b1994897Sopenharmony_ci
991b1994897Sopenharmony_cibool ItemContainer::IndexItem::Add(IndexedItem *item)
992b1994897Sopenharmony_ci{
993b1994897Sopenharmony_ci    auto size = index_.size();
994b1994897Sopenharmony_ci    ASSERT(size <= max_index_);
995b1994897Sopenharmony_ci
996b1994897Sopenharmony_ci    if (size == max_index_) {
997b1994897Sopenharmony_ci        return false;
998b1994897Sopenharmony_ci    }
999b1994897Sopenharmony_ci
1000b1994897Sopenharmony_ci    auto res = index_.insert(item);
1001b1994897Sopenharmony_ci    ASSERT(res.second);
1002b1994897Sopenharmony_ci
1003b1994897Sopenharmony_ci    return res.second;
1004b1994897Sopenharmony_ci}
1005b1994897Sopenharmony_ci
1006b1994897Sopenharmony_civoid ItemContainer::IndexSectionItem::AddHeader()
1007b1994897Sopenharmony_ci{
1008b1994897Sopenharmony_ci    std::vector<IndexItem *> index_items;
1009b1994897Sopenharmony_ci    for (size_t i = 0; i < INDEX_COUNT_16; i++) {
1010b1994897Sopenharmony_ci        auto type = static_cast<IndexType>(i);
1011b1994897Sopenharmony_ci        indexes_.emplace_back(type, MAX_INDEX_16);
1012b1994897Sopenharmony_ci        index_items.push_back(&indexes_.back());
1013b1994897Sopenharmony_ci    }
1014b1994897Sopenharmony_ci    headers_.emplace_back(index_items);
1015b1994897Sopenharmony_ci}
1016b1994897Sopenharmony_ci
1017b1994897Sopenharmony_cisize_t ItemContainer::IndexSectionItem::CalculateSize() const
1018b1994897Sopenharmony_ci{
1019b1994897Sopenharmony_ci    size_t size = headers_.size() * sizeof(File::IndexHeader);
1020b1994897Sopenharmony_ci    for (auto &index_item : indexes_) {
1021b1994897Sopenharmony_ci        size += index_item.GetSize();
1022b1994897Sopenharmony_ci    }
1023b1994897Sopenharmony_ci    return size;
1024b1994897Sopenharmony_ci}
1025b1994897Sopenharmony_ci
1026b1994897Sopenharmony_civoid ItemContainer::IndexSectionItem::ComputeLayout()
1027b1994897Sopenharmony_ci{
1028b1994897Sopenharmony_ci    size_t offset = GetOffset();
1029b1994897Sopenharmony_ci
1030b1994897Sopenharmony_ci    for (auto &header : headers_) {
1031b1994897Sopenharmony_ci        header.SetOffset(offset);
1032b1994897Sopenharmony_ci        header.ComputeLayout();
1033b1994897Sopenharmony_ci        offset += header.GetSize();
1034b1994897Sopenharmony_ci    }
1035b1994897Sopenharmony_ci
1036b1994897Sopenharmony_ci    for (auto &index : indexes_) {
1037b1994897Sopenharmony_ci        index.SetOffset(offset);
1038b1994897Sopenharmony_ci        index.ComputeLayout();
1039b1994897Sopenharmony_ci        offset += index.GetSize();
1040b1994897Sopenharmony_ci    }
1041b1994897Sopenharmony_ci}
1042b1994897Sopenharmony_ci
1043b1994897Sopenharmony_cibool ItemContainer::IndexSectionItem::Write(Writer *writer)
1044b1994897Sopenharmony_ci{
1045b1994897Sopenharmony_ci    ASSERT(GetOffset() == writer->GetOffset());
1046b1994897Sopenharmony_ci
1047b1994897Sopenharmony_ci    for (auto &header : headers_) {
1048b1994897Sopenharmony_ci        if (!header.Write(writer)) {
1049b1994897Sopenharmony_ci            return false;
1050b1994897Sopenharmony_ci        }
1051b1994897Sopenharmony_ci    }
1052b1994897Sopenharmony_ci
1053b1994897Sopenharmony_ci    for (auto &index : indexes_) {
1054b1994897Sopenharmony_ci        if (!index.Write(writer)) {
1055b1994897Sopenharmony_ci            return false;
1056b1994897Sopenharmony_ci        }
1057b1994897Sopenharmony_ci    }
1058b1994897Sopenharmony_ci
1059b1994897Sopenharmony_ci    return true;
1060b1994897Sopenharmony_ci}
1061b1994897Sopenharmony_ci
1062b1994897Sopenharmony_ciItemContainer::ProtoKey::ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> &params)
1063b1994897Sopenharmony_ci{
1064b1994897Sopenharmony_ci    Add(ret_type);
1065b1994897Sopenharmony_ci    for (const auto &param : params) {
1066b1994897Sopenharmony_ci        Add(param.GetType());
1067b1994897Sopenharmony_ci    }
1068b1994897Sopenharmony_ci    size_t shorty_hash = std::hash<std::string>()(shorty_);
1069b1994897Sopenharmony_ci    size_t ret_type_hash = std::hash<TypeItem *>()(ret_type);
1070b1994897Sopenharmony_ci    // combine hashes of shorty and ref_types
1071b1994897Sopenharmony_ci    hash_ = panda::merge_hashes(shorty_hash, ret_type_hash);
1072b1994897Sopenharmony_ci    // combine hashes of all param types
1073b1994897Sopenharmony_ci    for (const auto &item : params) {
1074b1994897Sopenharmony_ci        size_t param_type_hash = std::hash<TypeItem *>()(item.GetType());
1075b1994897Sopenharmony_ci        hash_ = panda::merge_hashes(hash_, param_type_hash);
1076b1994897Sopenharmony_ci    }
1077b1994897Sopenharmony_ci}
1078b1994897Sopenharmony_ci
1079b1994897Sopenharmony_civoid ItemContainer::ProtoKey::Add(TypeItem *item)
1080b1994897Sopenharmony_ci{
1081b1994897Sopenharmony_ci    auto type = item->GetType();
1082b1994897Sopenharmony_ci    shorty_.append(Type::GetSignatureByTypeId(type));
1083b1994897Sopenharmony_ci    if (type.IsReference()) {
1084b1994897Sopenharmony_ci        ref_types_.push_back(item);
1085b1994897Sopenharmony_ci    }
1086b1994897Sopenharmony_ci}
1087b1994897Sopenharmony_ci
1088b1994897Sopenharmony_ci}  // namespace panda::panda_file
1089