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> ¶ms) 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> ¶ms) 1063b1994897Sopenharmony_ci{ 1064b1994897Sopenharmony_ci Add(ret_type); 1065b1994897Sopenharmony_ci for (const auto ¶m : 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