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