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