1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBPANDAFILE_FILE_ITEM_CONTAINER_H 17 #define LIBPANDAFILE_FILE_ITEM_CONTAINER_H 18 19 #include "file_items.h" 20 #include "file_writer.h" 21 #include "pgo.h" 22 23 #include <list> 24 #include <map> 25 #include <memory> 26 #include <set> 27 #include <string> 28 #include <unordered_map> 29 #include <unordered_set> 30 31 namespace panda::panda_file { 32 33 class ItemDeduper; 34 35 class ItemContainer { 36 public: 37 explicit ItemContainer(); 38 ~ItemContainer() = default; 39 NO_COPY_SEMANTIC(ItemContainer); 40 NO_MOVE_SEMANTIC(ItemContainer); 41 42 StringItem *GetStringItem(const std::string &str) const; 43 44 StringItem *GetOrCreateStringItem(const std::string &str); 45 46 LiteralArrayItem *GetOrCreateLiteralArrayItem(const std::string &id); 47 48 ClassItem *GetOrCreateClassItem(const std::string &str); 49 50 ForeignClassItem *GetOrCreateForeignClassItem(const std::string &str); 51 52 ScalarValueItem *GetOrCreateIntegerValueItem(uint32_t v); 53 54 ScalarValueItem *GetOrCreateLongValueItem(uint64_t v); 55 56 ScalarValueItem *GetOrCreateFloatValueItem(float v); 57 58 ScalarValueItem *GetOrCreateDoubleValueItem(double v); 59 60 ScalarValueItem *GetOrCreateIdValueItem(BaseItem *v); 61 GetOrCreateGlobalClassItem()62 ClassItem *GetOrCreateGlobalClassItem() 63 { 64 return GetOrCreateClassItem("L_GLOBAL;"); 65 } 66 67 ProtoItem *GetOrCreateProtoItem(TypeItem *ret_type, const std::vector<MethodParamItem> ¶ms); 68 69 PrimitiveTypeItem *GetOrCreatePrimitiveTypeItem(Type type); 70 71 PrimitiveTypeItem *GetOrCreatePrimitiveTypeItem(Type::TypeId type); 72 73 LineNumberProgramItem *CreateLineNumberProgramItem(); 74 75 template <class T, class... Args> CreateItem(Args &&...args)76 T *CreateItem(Args &&... args) 77 { 78 static_assert(!std::is_same_v<T, StringItem>, "Use GetOrCreateStringItem to create StringItem"); 79 static_assert(!std::is_same_v<T, ClassItem>, "Use GetOrCreateClassItem to create ClassItem"); 80 static_assert(!std::is_same_v<T, ForeignClassItem>, 81 "Use GetOrCreateForeignClassItem to create ForeignClassItem"); 82 static_assert(!std::is_same_v<T, ValueItem>, "Use GetOrCreateValueItem functions to create ValueItem"); 83 static_assert(!std::is_same_v<T, ProtoItem>, "Use GetOrCreateProtoItem to create ValueItem"); 84 static_assert(!std::is_same_v<T, LineNumberProgramItem>, 85 "Use CreateLineNumberProgramItem to create LineNumberProgramItem"); 86 static_assert(!std::is_same_v<T, PrimitiveTypeItem>, 87 "Use GetOrCreatePrimitiveTypeItem to create PrimitiveTypeItem"); 88 static_assert(!std::is_same_v<T, MethodItem>, "Use ClassItem instance to create MethodItem"); 89 static_assert(!std::is_same_v<T, FieldItem>, "Use ClassItem instance to create FieldItem"); 90 91 std::unique_ptr<T> ptr = nullptr; 92 if constexpr (std::is_same_v<T, ForeignFieldItem> || std::is_same_v<T, ForeignMethodItem> || 93 std::is_same_v<T, ScalarValueItem> || std::is_same_v<T, ArrayValueItem> || 94 std::is_same_v<T, LiteralArrayItem>) { 95 ptr = std::make_unique<T>(std::forward<Args>(args)..., this); 96 } else { 97 ptr = std::make_unique<T>(std::forward<Args>(args)...); 98 } 99 100 auto ret = ptr.get(); 101 if (ptr->IsForeign()) { 102 foreign_items_.emplace_back(std::move(ptr)); 103 } else { 104 items_.insert(GetInsertPosition<T>(), std::move(ptr)); 105 } 106 return ret; 107 } 108 109 void ReLayout(); 110 uint32_t ComputeLayout(); 111 bool Write(Writer *writer, bool deduplicateItems = true); 112 113 std::map<std::string, size_t> GetStat(); 114 115 void DumpItemsStat(std::ostream &os) const; 116 CalculateRoundUpSize(uint32_t before,uint32_t after)117 uint32_t CalculateRoundUpSize(uint32_t before, uint32_t after) 118 { 119 return after - before; 120 } 121 GetStringMap()122 std::unordered_map<std::string, StringItem *> *GetStringMap() 123 { 124 return &string_map_; 125 } 126 GetLiteralArrayItem(const std::string & key)127 LiteralArrayItem *GetLiteralArrayItem(const std::string &key) 128 { 129 return literalarray_map_.at(key); 130 } 131 GetClassMap()132 std::map<std::string, BaseClassItem *> *GetClassMap() 133 { 134 return &class_map_; 135 } 136 GetIntValueMap()137 std::unordered_map<uint32_t, ValueItem *> *GetIntValueMap() 138 { 139 return &int_value_map_; 140 } 141 GetLongValueMap()142 std::unordered_map<uint64_t, ValueItem *> *GetLongValueMap() 143 { 144 return &long_value_map_; 145 } 146 GetFloatValueMap()147 std::unordered_map<uint32_t, ValueItem *> *GetFloatValueMap() 148 { 149 return &float_value_map_; 150 } 151 GetDoubleValueMap()152 std::unordered_map<uint64_t, ValueItem *> *GetDoubleValueMap() 153 { 154 return &double_value_map_; 155 } 156 GetScalarValueMap()157 std::unordered_map<BaseItem *, ValueItem *> *GetScalarValueMap() 158 { 159 return &id_value_map_; 160 } 161 GetProtoItem(TypeItem * retType,const std::vector<MethodParamItem> & params)162 ProtoItem *GetProtoItem(TypeItem *retType, const std::vector<MethodParamItem> ¶ms) 163 { 164 return proto_map_.at(ProtoKey {retType, params}); 165 } 166 GetPrimitiveTypeMap()167 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> *GetPrimitiveTypeMap() 168 { 169 return &primitive_type_map_; 170 } 171 GetItems()172 std::list<std::unique_ptr<BaseItem>> &GetItems() 173 { 174 return items_; 175 } 176 GetItems()177 const std::list<std::unique_ptr<BaseItem>> &GetItems() const 178 { 179 return items_; 180 } 181 GetForeigtems()182 const std::vector<std::unique_ptr<BaseItem>> &GetForeigtems() 183 { 184 return foreign_items_; 185 } 186 GetEndItem()187 BaseItem *GetEndItem() 188 { 189 return end_; 190 } 191 192 void ReorderItems(panda::panda_file::pgo::ProfileOptimizer *profile_opt); 193 194 void DeduplicateItems(bool computeLayout = true); 195 196 void DeduplicateCodeAndDebugInfo(); 197 198 void DeduplicateAnnotations(); 199 200 void DeduplicateLineNumberProgram(DebugInfoItem *item, ItemDeduper *deduper); 201 202 void DeduplicateDebugInfo(MethodItem *method, ItemDeduper *debug_info_deduper, 203 ItemDeduper *line_number_program_deduper); 204 GetIndexedItemCount()205 size_t GetIndexedItemCount() const 206 { 207 return indexed_item_count_; 208 } 209 IncIndexedItemCount()210 void IncIndexedItemCount() 211 { 212 indexed_item_count_++; 213 } 214 SetApi(uint8_t api)215 static void SetApi(uint8_t api) 216 { 217 ItemContainer::apiVersion = api; 218 } 219 SetSubApi(std::string subApi)220 static void SetSubApi(std::string subApi) 221 { 222 ItemContainer::subApiVersion = subApi; 223 } 224 GetSubApi()225 static std::string GetSubApi() 226 { 227 return ItemContainer::subApiVersion; 228 } 229 GetApi()230 static uint8_t GetApi() 231 { 232 return ItemContainer::apiVersion; 233 } 234 235 static uint8_t apiVersion; 236 static std::string subApiVersion; 237 238 private: 239 template <class T> GetInsertPosition()240 auto GetInsertPosition() 241 { 242 if (std::is_same_v<T, CodeItem>) { 243 return code_items_end_; 244 } 245 246 if (std::is_same_v<T, DebugInfoItem>) { 247 return debug_items_end_; 248 } 249 250 return items_end_; 251 } 252 253 class IndexItem : public BaseItem { 254 public: IndexItem(IndexType type,size_t max_index)255 IndexItem(IndexType type, size_t max_index) : type_(type), max_index_(max_index) 256 { 257 ASSERT(type_ != IndexType::NONE); 258 259 const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi()); 260 if (bc_version.value().front() >= API_12 && (type == IndexType::FIELD || type == IndexType::PROTO)) { 261 SetNeedsEmit(false); 262 } 263 } 264 265 ~IndexItem() override = default; 266 267 DEFAULT_COPY_SEMANTIC(IndexItem); 268 NO_MOVE_SEMANTIC(IndexItem); 269 Alignment()270 size_t Alignment() override 271 { 272 return sizeof(uint32_t); 273 } 274 275 bool Write(Writer *writer) override; 276 277 ItemTypes GetItemType() const override; 278 279 bool Add(IndexedItem *item); 280 Has(IndexedItem * item)281 bool Has(IndexedItem *item) const 282 { 283 auto res = index_.find(item); 284 return res != index_.cend(); 285 } 286 Remove(IndexedItem * item)287 void Remove(IndexedItem *item) 288 { 289 index_.erase(item); 290 } 291 GetNumItems()292 size_t GetNumItems() const 293 { 294 return index_.size(); 295 } 296 UpdateItems(BaseItem * start,BaseItem * end)297 void UpdateItems(BaseItem *start, BaseItem *end) 298 { 299 size_t i = 0; 300 for (auto *item : index_) { 301 item->SetIndex(start, end, i++); 302 } 303 } 304 Reset()305 void Reset() 306 { 307 for (auto *item : index_) { 308 item->ClearIndexes(); 309 } 310 } 311 312 protected: CalculateSize()313 size_t CalculateSize() const override 314 { 315 if (NeedsEmit()) { 316 return index_.size() * ID_SIZE; 317 } 318 return 0; 319 } 320 321 private: 322 struct Comparator { operatorComparator323 bool operator()(IndexedItem *item1, IndexedItem *item2) const noexcept 324 { 325 auto index_type = item1->GetIndexType(); 326 if (index_type == IndexType::CLASS) { 327 auto type_item1 = static_cast<TypeItem *>(item1); 328 auto type_item2 = static_cast<TypeItem *>(item2); 329 auto type_id1 = static_cast<size_t>(type_item1->GetType().GetId()); 330 auto type_id2 = static_cast<size_t>(type_item2->GetType().GetId()); 331 if (type_id1 != type_id2) { 332 return type_id1 < type_id2; 333 } 334 } 335 336 if (index_type == IndexType::LINE_NUMBER_PROG) { 337 auto ref_count1 = item1->GetRefCount(); 338 auto ref_count2 = item2->GetRefCount(); 339 if (ref_count1 != ref_count2) { 340 return ref_count1 > ref_count2; 341 } 342 } 343 344 return item1->GetIndexedItemCount() < item2->GetIndexedItemCount(); 345 } 346 }; 347 348 IndexType type_; 349 size_t max_index_; 350 std::set<IndexedItem *, Comparator> index_; 351 }; 352 353 class LineNumberProgramIndexItem : public IndexItem { 354 public: LineNumberProgramIndexItem()355 LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {} 356 ~LineNumberProgramIndexItem() override = default; 357 DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem); 358 NO_MOVE_SEMANTIC(LineNumberProgramIndexItem); 359 IncRefCount(LineNumberProgramItem * item)360 void IncRefCount(LineNumberProgramItem *item) 361 { 362 ASSERT(Has(item)); 363 Remove(item); 364 item->IncRefCount(); 365 Add(item); 366 } 367 DecRefCount(LineNumberProgramItem * item)368 void DecRefCount(LineNumberProgramItem *item) 369 { 370 ASSERT(Has(item)); 371 Remove(item); 372 item->DecRefCount(); 373 Add(item); 374 } 375 }; 376 377 class IndexHeaderItem : public BaseItem { 378 public: IndexHeaderItem(std::vector<IndexItem * > indexes)379 explicit IndexHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes)) 380 { 381 ASSERT(indexes_.size() == INDEX_COUNT_16); 382 } 383 384 ~IndexHeaderItem() override = default; 385 386 DEFAULT_COPY_SEMANTIC(IndexHeaderItem); 387 NO_MOVE_SEMANTIC(IndexHeaderItem); 388 Alignment()389 size_t Alignment() override 390 { 391 return ID_SIZE; 392 } 393 394 bool Write(Writer *writer) override; 395 GetItemType()396 ItemTypes GetItemType() const override 397 { 398 return ItemTypes::INDEX_HEADER; 399 } 400 401 bool Add(const std::list<IndexedItem *> &items); 402 403 void Remove(const std::list<IndexedItem *> &items); 404 SetStart(BaseItem * item)405 void SetStart(BaseItem *item) 406 { 407 start_ = item; 408 } 409 SetEnd(BaseItem * item)410 void SetEnd(BaseItem *item) 411 { 412 end_ = item; 413 } 414 UpdateItems()415 void UpdateItems() 416 { 417 for (auto *index : indexes_) { 418 index->UpdateItems(start_, end_); 419 } 420 } 421 422 protected: CalculateSize()423 size_t CalculateSize() const override 424 { 425 return sizeof(File::IndexHeader); 426 } 427 428 private: IndexGetIndexByType(IndexType type)429 IndexItem *IndexGetIndexByType(IndexType type) const 430 { 431 auto i = static_cast<size_t>(type); 432 return indexes_[i]; 433 } 434 435 BaseItem *start_ {nullptr}; 436 BaseItem *end_ {nullptr}; 437 std::vector<IndexItem *> indexes_; 438 }; 439 440 class IndexSectionItem : public BaseItem { 441 public: Alignment()442 size_t Alignment() override 443 { 444 return ID_SIZE; 445 } 446 447 bool Write(Writer *writer) override; 448 GetItemType()449 ItemTypes GetItemType() const override 450 { 451 return ItemTypes::INDEX_SECTION; 452 } 453 Reset()454 void Reset() 455 { 456 headers_.clear(); 457 458 for (auto &index : indexes_) { 459 index.Reset(); 460 } 461 462 indexes_.clear(); 463 } 464 465 void AddHeader(); 466 GetCurrentHeader()467 IndexHeaderItem *GetCurrentHeader() 468 { 469 return &headers_.back(); 470 } 471 IsEmpty()472 bool IsEmpty() const 473 { 474 return headers_.empty(); 475 } 476 GetNumHeaders()477 size_t GetNumHeaders() const 478 { 479 return headers_.size(); 480 } 481 482 void ComputeLayout() override; 483 UpdateItems()484 void UpdateItems() 485 { 486 for (auto &header : headers_) { 487 header.UpdateItems(); 488 } 489 } 490 491 protected: 492 size_t CalculateSize() const override; 493 494 private: 495 std::list<IndexHeaderItem> headers_; 496 std::list<IndexItem> indexes_; 497 }; 498 499 class ProtoKey { 500 public: 501 ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> ¶ms); 502 503 ~ProtoKey() = default; 504 505 DEFAULT_COPY_SEMANTIC(ProtoKey); 506 NO_MOVE_SEMANTIC(ProtoKey); 507 GetHash()508 size_t GetHash() const 509 { 510 return hash_; 511 } 512 513 bool operator==(const ProtoKey &key) const 514 { 515 return shorty_ == key.shorty_ && ref_types_ == key.ref_types_; 516 } 517 518 private: 519 void Add(TypeItem *item); 520 521 size_t hash_; 522 std::string shorty_; 523 std::vector<TypeItem *> ref_types_; 524 }; 525 526 struct ProtoKeyHash { operatorProtoKeyHash527 size_t operator()(const ProtoKey &key) const noexcept 528 { 529 return key.GetHash(); 530 }; 531 }; 532 533 class EndItem : public BaseItem { 534 public: EndItem()535 EndItem() 536 { 537 SetNeedsEmit(false); 538 } 539 540 ~EndItem() override = default; 541 542 DEFAULT_COPY_SEMANTIC(EndItem); 543 NO_MOVE_SEMANTIC(EndItem); 544 CalculateSize()545 size_t CalculateSize() const override 546 { 547 return 0; 548 } 549 Write(Writer * writer)550 bool Write([[maybe_unused]] Writer *writer) override 551 { 552 return true; 553 } 554 GetItemType()555 ItemTypes GetItemType() const override 556 { 557 return ItemTypes::END_ITEM; 558 } 559 }; 560 561 bool WriteHeader(Writer *writer, ssize_t *checksum_offset); 562 563 bool WriteItems(Writer *writer); 564 565 bool WriteHeaderIndexInfo(Writer *writer); 566 567 void RebuildIndexSection(); 568 569 void RebuildLineNumberProgramIndex(); 570 571 void UpdateOrderIndexes(); 572 573 void AddIndexDependecies(BaseItem *item); 574 575 void ProcessIndexDependecies(BaseItem *item); 576 577 size_t GetForeignOffset() const; 578 579 size_t GetForeignSize() const; 580 581 std::unordered_map<std::string, StringItem *> string_map_; 582 std::unordered_map<std::string, LiteralArrayItem *> literalarray_map_; 583 584 std::map<std::string, BaseClassItem *> class_map_; 585 586 std::unordered_map<uint32_t, ValueItem *> int_value_map_; 587 std::unordered_map<uint64_t, ValueItem *> long_value_map_; 588 // NB! For f32 and f64 value maps we use integral keys 589 // (in fact, bit patterns of corresponding values) to 590 // workaround 0.0 == -0.0 semantics. 591 std::unordered_map<uint32_t, ValueItem *> float_value_map_; 592 std::unordered_map<uint64_t, ValueItem *> double_value_map_; 593 std::unordered_map<BaseItem *, ValueItem *> id_value_map_; 594 std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> proto_map_; 595 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitive_type_map_; 596 597 std::list<std::unique_ptr<BaseItem>> items_; 598 599 std::vector<std::unique_ptr<BaseItem>> foreign_items_; 600 601 IndexSectionItem index_section_item_; 602 603 LineNumberProgramIndexItem line_number_program_index_item_; 604 605 std::list<std::unique_ptr<BaseItem>>::iterator items_end_; 606 std::list<std::unique_ptr<BaseItem>>::iterator code_items_end_; 607 std::list<std::unique_ptr<BaseItem>>::iterator debug_items_end_; 608 609 // Get Roundup Alignment Size 610 std::unordered_map<std::string, size_t> items_round_up_size_; 611 uint32_t foreign_item_roundup_size_ {0}; 612 uint32_t line_number_item_roundup_size_ {0}; 613 614 BaseItem *end_; 615 size_t indexed_item_count_ {0}; 616 }; 617 618 } // namespace panda::panda_file 619 620 #endif // LIBPANDAFILE_FILE_ITEM_CONTAINER_H 621