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 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 GetOrCreateGlobalClassItem()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> CreateItem(Args &&...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 uint32_t ComputeLayout(); 108 bool Write(Writer *writer, bool deduplicateItems = true); 109 110 std::map<std::string, size_t> GetStat(); 111 112 void DumpItemsStat(std::ostream &os) const; 113 GetStringMap()114 std::unordered_map<std::string, StringItem *> *GetStringMap() 115 { 116 return &string_map_; 117 } 118 GetLiteralArrayItem(const std::string & key)119 LiteralArrayItem *GetLiteralArrayItem(const std::string &key) 120 { 121 return literalarray_map_.at(key); 122 } 123 GetClassMap()124 std::map<std::string, BaseClassItem *> *GetClassMap() 125 { 126 return &class_map_; 127 } 128 GetIntValueMap()129 std::unordered_map<uint32_t, ValueItem *> *GetIntValueMap() 130 { 131 return &int_value_map_; 132 } 133 GetLongValueMap()134 std::unordered_map<uint64_t, ValueItem *> *GetLongValueMap() 135 { 136 return &long_value_map_; 137 } 138 GetFloatValueMap()139 std::unordered_map<uint32_t, ValueItem *> *GetFloatValueMap() 140 { 141 return &float_value_map_; 142 } 143 GetDoubleValueMap()144 std::unordered_map<uint64_t, ValueItem *> *GetDoubleValueMap() 145 { 146 return &double_value_map_; 147 } 148 GetScalarValueMap()149 std::unordered_map<BaseItem *, ValueItem *> *GetScalarValueMap() 150 { 151 return &id_value_map_; 152 } 153 GetProtoItem(TypeItem * retType,const std::vector<MethodParamItem> & params)154 ProtoItem *GetProtoItem(TypeItem *retType, const std::vector<MethodParamItem> ¶ms) 155 { 156 return proto_map_.at(ProtoKey {retType, params}); 157 } 158 GetPrimitiveTypeMap()159 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> *GetPrimitiveTypeMap() 160 { 161 return &primitive_type_map_; 162 } 163 GetItems()164 std::list<std::unique_ptr<BaseItem>> &GetItems() 165 { 166 return items_; 167 } 168 GetItems()169 const std::list<std::unique_ptr<BaseItem>> &GetItems() const 170 { 171 return items_; 172 } 173 GetForeigtems()174 const std::vector<std::unique_ptr<BaseItem>> &GetForeigtems() 175 { 176 return foreign_items_; 177 } 178 GetEndItem()179 BaseItem *GetEndItem() 180 { 181 return end_; 182 } 183 184 void ReorderItems(panda::panda_file::pgo::ProfileOptimizer *profile_opt); 185 186 void DeduplicateItems(bool computeLayout = true); 187 188 void DeduplicateCodeAndDebugInfo(); 189 190 void DeduplicateAnnotations(); 191 192 void DeduplicateLineNumberProgram(DebugInfoItem *item, ItemDeduper *deduper); 193 194 void DeduplicateDebugInfo(MethodItem *method, ItemDeduper *debug_info_deduper, 195 ItemDeduper *line_number_program_deduper); 196 GetIndexedItemCount()197 size_t GetIndexedItemCount() const 198 { 199 return indexed_item_count_; 200 } 201 IncIndexedItemCount()202 void IncIndexedItemCount() 203 { 204 indexed_item_count_++; 205 } 206 207 private: 208 template <class T> GetInsertPosition()209 auto GetInsertPosition() 210 { 211 if (std::is_same_v<T, CodeItem>) { 212 return code_items_end_; 213 } 214 215 if (std::is_same_v<T, DebugInfoItem>) { 216 return debug_items_end_; 217 } 218 219 return items_end_; 220 } 221 222 class IndexItem : public BaseItem { 223 public: IndexItem(IndexType type,size_t max_index)224 IndexItem(IndexType type, size_t max_index) : type_(type), max_index_(max_index) 225 { 226 ASSERT(type_ != IndexType::NONE); 227 } 228 229 ~IndexItem() override = default; 230 231 DEFAULT_COPY_SEMANTIC(IndexItem); 232 NO_MOVE_SEMANTIC(IndexItem); 233 Alignment()234 size_t Alignment() override 235 { 236 return sizeof(uint32_t); 237 } 238 239 bool Write(Writer *writer) override; 240 241 ItemTypes GetItemType() const override; 242 243 bool Add(IndexedItem *item); 244 Has(IndexedItem * item)245 bool Has(IndexedItem *item) const 246 { 247 auto res = index_.find(item); 248 return res != index_.cend(); 249 } 250 Remove(IndexedItem * item)251 void Remove(IndexedItem *item) 252 { 253 index_.erase(item); 254 } 255 GetNumItems()256 size_t GetNumItems() const 257 { 258 return index_.size(); 259 } 260 UpdateItems(BaseItem * start,BaseItem * end)261 void UpdateItems(BaseItem *start, BaseItem *end) 262 { 263 size_t i = 0; 264 for (auto *item : index_) { 265 item->SetIndex(start, end, i++); 266 } 267 } 268 Reset()269 void Reset() 270 { 271 for (auto *item : index_) { 272 item->ClearIndexes(); 273 } 274 } 275 276 protected: CalculateSize()277 size_t CalculateSize() const override 278 { 279 return index_.size() * ID_SIZE; 280 } 281 282 private: 283 struct Comparator { operatorComparator284 bool operator()(IndexedItem *item1, IndexedItem *item2) const noexcept 285 { 286 auto index_type = item1->GetIndexType(); 287 288 if (index_type == IndexType::CLASS) { 289 auto type_item1 = static_cast<TypeItem *>(item1); 290 auto type_item2 = static_cast<TypeItem *>(item2); 291 auto type_id1 = static_cast<size_t>(type_item1->GetType().GetId()); 292 auto type_id2 = static_cast<size_t>(type_item2->GetType().GetId()); 293 294 if (type_id1 != type_id2) { 295 return type_id1 < type_id2; 296 } 297 } 298 299 if (index_type == IndexType::LINE_NUMBER_PROG) { 300 auto ref_count1 = item1->GetRefCount(); 301 auto ref_count2 = item2->GetRefCount(); 302 303 if (ref_count1 != ref_count2) { 304 return ref_count1 > ref_count2; 305 } 306 } 307 308 return item1->GetIndexedItemCount() < item2->GetIndexedItemCount(); 309 } 310 }; 311 312 IndexType type_; 313 size_t max_index_; 314 std::set<IndexedItem *, Comparator> index_; 315 }; 316 317 class LineNumberProgramIndexItem : public IndexItem { 318 public: LineNumberProgramIndexItem()319 LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {} 320 ~LineNumberProgramIndexItem() override = default; 321 DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem); 322 NO_MOVE_SEMANTIC(LineNumberProgramIndexItem); 323 IncRefCount(LineNumberProgramItem * item)324 void IncRefCount(LineNumberProgramItem *item) 325 { 326 ASSERT(Has(item)); 327 Remove(item); 328 item->IncRefCount(); 329 Add(item); 330 } 331 DecRefCount(LineNumberProgramItem * item)332 void DecRefCount(LineNumberProgramItem *item) 333 { 334 ASSERT(Has(item)); 335 Remove(item); 336 item->DecRefCount(); 337 Add(item); 338 } 339 }; 340 341 class IndexHeaderItem : public BaseItem { 342 public: IndexHeaderItem(std::vector<IndexItem * > indexes)343 explicit IndexHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes)) 344 { 345 ASSERT(indexes_.size() == INDEX_COUNT_16); 346 } 347 348 ~IndexHeaderItem() override = default; 349 350 DEFAULT_COPY_SEMANTIC(IndexHeaderItem); 351 NO_MOVE_SEMANTIC(IndexHeaderItem); 352 Alignment()353 size_t Alignment() override 354 { 355 return ID_SIZE; 356 } 357 358 bool Write(Writer *writer) override; 359 GetItemType()360 ItemTypes GetItemType() const override 361 { 362 return ItemTypes::INDEX_HEADER; 363 } 364 365 bool Add(const std::list<IndexedItem *> &items); 366 367 void Remove(const std::list<IndexedItem *> &items); 368 SetStart(BaseItem * item)369 void SetStart(BaseItem *item) 370 { 371 start_ = item; 372 } 373 SetEnd(BaseItem * item)374 void SetEnd(BaseItem *item) 375 { 376 end_ = item; 377 } 378 UpdateItems()379 void UpdateItems() 380 { 381 for (auto *index : indexes_) { 382 index->UpdateItems(start_, end_); 383 } 384 } 385 386 protected: CalculateSize()387 size_t CalculateSize() const override 388 { 389 return sizeof(File::IndexHeader); 390 } 391 392 private: IndexGetIndexByType(IndexType type)393 IndexItem *IndexGetIndexByType(IndexType type) const 394 { 395 auto i = static_cast<size_t>(type); 396 return indexes_[i]; 397 } 398 399 BaseItem *start_ {nullptr}; 400 BaseItem *end_ {nullptr}; 401 std::vector<IndexItem *> indexes_; 402 }; 403 404 class IndexSectionItem : public BaseItem { 405 public: Alignment()406 size_t Alignment() override 407 { 408 return ID_SIZE; 409 } 410 411 bool Write(Writer *writer) override; 412 GetItemType()413 ItemTypes GetItemType() const override 414 { 415 return ItemTypes::INDEX_SECTION; 416 } 417 Reset()418 void Reset() 419 { 420 headers_.clear(); 421 422 for (auto &index : indexes_) { 423 index.Reset(); 424 } 425 426 indexes_.clear(); 427 } 428 429 void AddHeader(); 430 GetCurrentHeader()431 IndexHeaderItem *GetCurrentHeader() 432 { 433 return &headers_.back(); 434 } 435 IsEmpty()436 bool IsEmpty() const 437 { 438 return headers_.empty(); 439 } 440 GetNumHeaders()441 size_t GetNumHeaders() const 442 { 443 return headers_.size(); 444 } 445 446 void ComputeLayout() override; 447 UpdateItems()448 void UpdateItems() 449 { 450 for (auto &header : headers_) { 451 header.UpdateItems(); 452 } 453 } 454 455 protected: 456 size_t CalculateSize() const override; 457 458 private: 459 std::list<IndexHeaderItem> headers_; 460 std::list<IndexItem> indexes_; 461 }; 462 463 class ProtoKey { 464 public: 465 ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> ¶ms); 466 467 ~ProtoKey() = default; 468 469 DEFAULT_COPY_SEMANTIC(ProtoKey); 470 NO_MOVE_SEMANTIC(ProtoKey); 471 GetHash()472 size_t GetHash() const 473 { 474 return hash_; 475 } 476 477 bool operator==(const ProtoKey &key) const 478 { 479 return shorty_ == key.shorty_ && ref_types_ == key.ref_types_; 480 } 481 482 private: 483 void Add(TypeItem *item); 484 485 size_t hash_; 486 std::string shorty_; 487 std::vector<TypeItem *> ref_types_; 488 }; 489 490 struct ProtoKeyHash { operatorProtoKeyHash491 size_t operator()(const ProtoKey &key) const noexcept 492 { 493 return key.GetHash(); 494 }; 495 }; 496 497 class EndItem : public BaseItem { 498 public: EndItem()499 EndItem() 500 { 501 SetNeedsEmit(false); 502 } 503 504 ~EndItem() override = default; 505 506 DEFAULT_COPY_SEMANTIC(EndItem); 507 NO_MOVE_SEMANTIC(EndItem); 508 CalculateSize()509 size_t CalculateSize() const override 510 { 511 return 0; 512 } 513 Write(Writer * writer)514 bool Write([[maybe_unused]] Writer *writer) override 515 { 516 return true; 517 } 518 GetItemType()519 ItemTypes GetItemType() const override 520 { 521 return ItemTypes::END_ITEM; 522 } 523 }; 524 525 bool WriteHeader(Writer *writer, ssize_t *checksum_offset); 526 527 bool WriteHeaderIndexInfo(Writer *writer); 528 529 void RebuildIndexSection(); 530 531 void RebuildLineNumberProgramIndex(); 532 533 void UpdateOrderIndexes(); 534 535 void AddIndexDependecies(BaseItem *item); 536 537 void ProcessIndexDependecies(BaseItem *item); 538 539 size_t GetForeignOffset() const; 540 541 size_t GetForeignSize() const; 542 543 std::unordered_map<std::string, StringItem *> string_map_; 544 std::unordered_map<std::string, LiteralArrayItem *> literalarray_map_; 545 546 std::map<std::string, BaseClassItem *> class_map_; 547 548 std::unordered_map<uint32_t, ValueItem *> int_value_map_; 549 std::unordered_map<uint64_t, ValueItem *> long_value_map_; 550 // NB! For f32 and f64 value maps we use integral keys 551 // (in fact, bit patterns of corresponding values) to 552 // workaround 0.0 == -0.0 semantics. 553 std::unordered_map<uint32_t, ValueItem *> float_value_map_; 554 std::unordered_map<uint64_t, ValueItem *> double_value_map_; 555 std::unordered_map<BaseItem *, ValueItem *> id_value_map_; 556 std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> proto_map_; 557 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitive_type_map_; 558 559 std::list<std::unique_ptr<BaseItem>> items_; 560 561 std::vector<std::unique_ptr<BaseItem>> foreign_items_; 562 563 IndexSectionItem index_section_item_; 564 565 LineNumberProgramIndexItem line_number_program_index_item_; 566 567 std::list<std::unique_ptr<BaseItem>>::iterator items_end_; 568 std::list<std::unique_ptr<BaseItem>>::iterator code_items_end_; 569 std::list<std::unique_ptr<BaseItem>>::iterator debug_items_end_; 570 571 BaseItem *end_; 572 size_t indexed_item_count_ {0}; 573 }; 574 575 } // namespace panda::panda_file 576 577 #endif // LIBPANDAFILE_FILE_ITEM_CONTAINER_H_ 578