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 if (index_type == IndexType::CLASS) { 288 auto type_item1 = static_cast<TypeItem *>(item1); 289 auto type_item2 = static_cast<TypeItem *>(item2); 290 auto type_id1 = static_cast<size_t>(type_item1->GetType().GetId()); 291 auto type_id2 = static_cast<size_t>(type_item2->GetType().GetId()); 292 if (type_id1 != type_id2) { 293 return type_id1 < type_id2; 294 } 295 } 296 297 if (index_type == IndexType::LINE_NUMBER_PROG) { 298 auto ref_count1 = item1->GetRefCount(); 299 auto ref_count2 = item2->GetRefCount(); 300 if (ref_count1 != ref_count2) { 301 return ref_count1 > ref_count2; 302 } 303 } 304 305 return item1->GetIndexedItemCount() < item2->GetIndexedItemCount(); 306 } 307 }; 308 309 IndexType type_; 310 size_t max_index_; 311 std::set<IndexedItem *, Comparator> index_; 312 }; 313 314 class LineNumberProgramIndexItem : public IndexItem { 315 public: LineNumberProgramIndexItem()316 LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {} 317 ~LineNumberProgramIndexItem() override = default; 318 DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem); 319 NO_MOVE_SEMANTIC(LineNumberProgramIndexItem); 320 IncRefCount(LineNumberProgramItem * item)321 void IncRefCount(LineNumberProgramItem *item) 322 { 323 ASSERT(Has(item)); 324 Remove(item); 325 item->IncRefCount(); 326 Add(item); 327 } 328 DecRefCount(LineNumberProgramItem * item)329 void DecRefCount(LineNumberProgramItem *item) 330 { 331 ASSERT(Has(item)); 332 Remove(item); 333 item->DecRefCount(); 334 Add(item); 335 } 336 }; 337 338 class IndexHeaderItem : public BaseItem { 339 public: IndexHeaderItem(std::vector<IndexItem * > indexes)340 explicit IndexHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes)) 341 { 342 ASSERT(indexes_.size() == INDEX_COUNT_16); 343 } 344 345 ~IndexHeaderItem() override = default; 346 347 DEFAULT_COPY_SEMANTIC(IndexHeaderItem); 348 NO_MOVE_SEMANTIC(IndexHeaderItem); 349 Alignment()350 size_t Alignment() override 351 { 352 return ID_SIZE; 353 } 354 355 bool Write(Writer *writer) override; 356 GetItemType()357 ItemTypes GetItemType() const override 358 { 359 return ItemTypes::INDEX_HEADER; 360 } 361 362 bool Add(const std::list<IndexedItem *> &items); 363 364 void Remove(const std::list<IndexedItem *> &items); 365 SetStart(BaseItem * item)366 void SetStart(BaseItem *item) 367 { 368 start_ = item; 369 } 370 SetEnd(BaseItem * item)371 void SetEnd(BaseItem *item) 372 { 373 end_ = item; 374 } 375 UpdateItems()376 void UpdateItems() 377 { 378 for (auto *index : indexes_) { 379 index->UpdateItems(start_, end_); 380 } 381 } 382 383 protected: CalculateSize()384 size_t CalculateSize() const override 385 { 386 return sizeof(File::IndexHeader); 387 } 388 389 private: IndexGetIndexByType(IndexType type)390 IndexItem *IndexGetIndexByType(IndexType type) const 391 { 392 auto i = static_cast<size_t>(type); 393 return indexes_[i]; 394 } 395 396 BaseItem *start_ {nullptr}; 397 BaseItem *end_ {nullptr}; 398 std::vector<IndexItem *> indexes_; 399 }; 400 401 class IndexSectionItem : public BaseItem { 402 public: Alignment()403 size_t Alignment() override 404 { 405 return ID_SIZE; 406 } 407 408 bool Write(Writer *writer) override; 409 GetItemType()410 ItemTypes GetItemType() const override 411 { 412 return ItemTypes::INDEX_SECTION; 413 } 414 Reset()415 void Reset() 416 { 417 headers_.clear(); 418 419 for (auto &index : indexes_) { 420 index.Reset(); 421 } 422 423 indexes_.clear(); 424 } 425 426 void AddHeader(); 427 GetCurrentHeader()428 IndexHeaderItem *GetCurrentHeader() 429 { 430 return &headers_.back(); 431 } 432 IsEmpty()433 bool IsEmpty() const 434 { 435 return headers_.empty(); 436 } 437 GetNumHeaders()438 size_t GetNumHeaders() const 439 { 440 return headers_.size(); 441 } 442 443 void ComputeLayout() override; 444 UpdateItems()445 void UpdateItems() 446 { 447 for (auto &header : headers_) { 448 header.UpdateItems(); 449 } 450 } 451 452 protected: 453 size_t CalculateSize() const override; 454 455 private: 456 std::list<IndexHeaderItem> headers_; 457 std::list<IndexItem> indexes_; 458 }; 459 460 class ProtoKey { 461 public: 462 ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> ¶ms); 463 464 ~ProtoKey() = default; 465 466 DEFAULT_COPY_SEMANTIC(ProtoKey); 467 NO_MOVE_SEMANTIC(ProtoKey); 468 GetHash()469 size_t GetHash() const 470 { 471 return hash_; 472 } 473 474 bool operator==(const ProtoKey &key) const 475 { 476 return shorty_ == key.shorty_ && ref_types_ == key.ref_types_; 477 } 478 479 private: 480 void Add(TypeItem *item); 481 482 size_t hash_; 483 std::string shorty_; 484 std::vector<TypeItem *> ref_types_; 485 }; 486 487 struct ProtoKeyHash { operatorProtoKeyHash488 size_t operator()(const ProtoKey &key) const noexcept 489 { 490 return key.GetHash(); 491 }; 492 }; 493 494 class EndItem : public BaseItem { 495 public: EndItem()496 EndItem() 497 { 498 SetNeedsEmit(false); 499 } 500 501 ~EndItem() override = default; 502 503 DEFAULT_COPY_SEMANTIC(EndItem); 504 NO_MOVE_SEMANTIC(EndItem); 505 CalculateSize()506 size_t CalculateSize() const override 507 { 508 return 0; 509 } 510 Write(Writer * writer)511 bool Write([[maybe_unused]] Writer *writer) override 512 { 513 return true; 514 } 515 GetItemType()516 ItemTypes GetItemType() const override 517 { 518 return ItemTypes::END_ITEM; 519 } 520 }; 521 522 bool WriteHeader(Writer *writer, ssize_t *checksum_offset); 523 524 bool WriteHeaderIndexInfo(Writer *writer); 525 526 void RebuildIndexSection(); 527 528 void RebuildLineNumberProgramIndex(); 529 530 void UpdateOrderIndexes(); 531 532 void AddIndexDependecies(BaseItem *item); 533 534 void ProcessIndexDependecies(BaseItem *item); 535 536 size_t GetForeignOffset() const; 537 538 size_t GetForeignSize() const; 539 540 std::unordered_map<std::string, StringItem *> string_map_; 541 std::unordered_map<std::string, LiteralArrayItem *> literalarray_map_; 542 543 std::map<std::string, BaseClassItem *> class_map_; 544 545 std::unordered_map<uint32_t, ValueItem *> int_value_map_; 546 std::unordered_map<uint64_t, ValueItem *> long_value_map_; 547 // NB! For f32 and f64 value maps we use integral keys 548 // (in fact, bit patterns of corresponding values) to 549 // workaround 0.0 == -0.0 semantics. 550 std::unordered_map<uint32_t, ValueItem *> float_value_map_; 551 std::unordered_map<uint64_t, ValueItem *> double_value_map_; 552 std::unordered_map<BaseItem *, ValueItem *> id_value_map_; 553 std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> proto_map_; 554 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitive_type_map_; 555 556 std::list<std::unique_ptr<BaseItem>> items_; 557 558 std::vector<std::unique_ptr<BaseItem>> foreign_items_; 559 560 IndexSectionItem index_section_item_; 561 562 LineNumberProgramIndexItem line_number_program_index_item_; 563 564 std::list<std::unique_ptr<BaseItem>>::iterator items_end_; 565 std::list<std::unique_ptr<BaseItem>>::iterator code_items_end_; 566 std::list<std::unique_ptr<BaseItem>>::iterator debug_items_end_; 567 568 BaseItem *end_; 569 size_t indexed_item_count_ {0}; 570 }; 571 572 } // namespace panda::panda_file 573 574 #endif // LIBPANDAFILE_FILE_ITEM_CONTAINER_H 575