1 /** 2 * Copyright (c) 2021-2024 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 119 PANDA_PUBLIC_API bool Write(Writer *writer, bool deduplicateItems = true, bool computeLayout = true); 120 121 PANDA_PUBLIC_API std::map<std::string, size_t> GetStat(); 122 123 void DumpItemsStat(std::ostream &os) const; 124 GetStringMap()125 std::unordered_map<std::string, StringItem *> *GetStringMap() 126 { 127 return &stringMap_; 128 } 129 GetLiteralArrayItem(const std::string & key)130 LiteralArrayItem *GetLiteralArrayItem(const std::string &key) 131 { 132 return literalarrayMap_.at(key); 133 } 134 GetClassMap()135 std::map<std::string, BaseClassItem *> *GetClassMap() 136 { 137 return &classMap_; 138 } 139 GetIntValueMap()140 std::unordered_map<uint32_t, ValueItem *> *GetIntValueMap() 141 { 142 return &intValueMap_; 143 } 144 GetLongValueMap()145 std::unordered_map<uint64_t, ValueItem *> *GetLongValueMap() 146 { 147 return &longValueMap_; 148 } 149 GetFloatValueMap()150 std::unordered_map<uint32_t, ValueItem *> *GetFloatValueMap() 151 { 152 return &floatValueMap_; 153 } 154 GetDoubleValueMap()155 std::unordered_map<uint64_t, ValueItem *> *GetDoubleValueMap() 156 { 157 return &doubleValueMap_; 158 } 159 GetScalarValueMap()160 std::unordered_map<BaseItem *, ValueItem *> *GetScalarValueMap() 161 { 162 return &idValueMap_; 163 } 164 GetProtoItem(TypeItem * retType,const std::vector<MethodParamItem> & params)165 ProtoItem *GetProtoItem(TypeItem *retType, const std::vector<MethodParamItem> ¶ms) 166 { 167 return protoMap_.at(ProtoKey {retType, params}); 168 } 169 GetPrimitiveTypeMap()170 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> *GetPrimitiveTypeMap() 171 { 172 return &primitiveTypeMap_; 173 } 174 GetItems()175 const std::list<std::unique_ptr<BaseItem>> &GetItems() const 176 { 177 return items_; 178 } 179 GetForeignItems()180 const std::vector<std::unique_ptr<BaseItem>> &GetForeignItems() 181 { 182 return foreignItems_; 183 } 184 GetEndItem()185 BaseItem *GetEndItem() 186 { 187 return end_; 188 } 189 190 PANDA_PUBLIC_API void ReorderItems(ark::panda_file::pgo::ProfileOptimizer *profileOpt); 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 *debugInfoDeduper, ItemDeduper *lineNumberProgramDeduper); 201 202 private: 203 template <class T> GetInsertPosition()204 auto GetInsertPosition() 205 { 206 if (std::is_same_v<T, CodeItem>) { 207 return codeItemsEnd_; 208 } 209 210 if (std::is_same_v<T, DebugInfoItem>) { 211 return debugItemsEnd_; 212 } 213 214 if (std::is_same_v<T, AnnotationItem> || std::is_base_of_v<ValueItem, T>) { 215 return annotationItemsEnd_; 216 } 217 218 return itemsEnd_; 219 } 220 221 class PANDA_PUBLIC_API IndexItem : public BaseItem { 222 public: IndexItem(IndexType type,size_t maxIndex)223 IndexItem(IndexType type, size_t maxIndex) : type_(type), maxIndex_(maxIndex) 224 { 225 ASSERT(type_ != IndexType::NONE); 226 } 227 228 ~IndexItem() override = default; 229 230 DEFAULT_COPY_SEMANTIC(IndexItem); 231 NO_MOVE_SEMANTIC(IndexItem); 232 Alignment()233 size_t Alignment() override 234 { 235 return sizeof(uint32_t); 236 } 237 238 PANDA_PUBLIC_API bool Write(Writer *writer) override; 239 240 ItemTypes GetItemType() const override; 241 242 bool Add(IndexedItem *item); 243 Has(IndexedItem * item)244 bool Has(IndexedItem *item) const 245 { 246 auto res = index_.find(item); 247 return res != index_.cend(); 248 } 249 Remove(IndexedItem * item)250 void Remove(IndexedItem *item) 251 { 252 index_.erase(item); 253 } 254 GetNumItems()255 size_t GetNumItems() const 256 { 257 return index_.size(); 258 } 259 UpdateItems(BaseItem * start,BaseItem * end)260 void UpdateItems(BaseItem *start, BaseItem *end) 261 { 262 size_t i = 0; 263 for (auto *item : index_) { 264 item->SetIndex(start, end, i++); 265 } 266 } 267 Reset()268 void Reset() 269 { 270 for (auto *item : index_) { 271 item->ClearIndexes(); 272 } 273 } 274 275 protected: CalculateSize()276 size_t CalculateSize() const override 277 { 278 return index_.size() * ID_SIZE; 279 } 280 281 private: 282 struct Comparator { operatorComparator283 bool operator()(IndexedItem *item1, IndexedItem *item2) const noexcept 284 { 285 auto indexType = item1->GetIndexType(); 286 if (indexType == IndexType::CLASS) { 287 auto typeItem1 = static_cast<TypeItem *>(item1); 288 auto typeItem2 = static_cast<TypeItem *>(item2); 289 290 auto typeId1 = static_cast<size_t>(typeItem1->GetType().GetId()); 291 auto typeId2 = static_cast<size_t>(typeItem2->GetType().GetId()); 292 if (typeId1 != typeId2) { 293 return typeId1 < typeId2; 294 } 295 } 296 297 if (indexType == IndexType::LINE_NUMBER_PROG) { 298 auto refCount1 = item1->GetRefCount(); 299 auto refCount2 = item2->GetRefCount(); 300 if (refCount1 != refCount2) { 301 return refCount1 > refCount2; 302 } 303 } 304 305 return item1->GetItemAllocId() < item2->GetItemAllocId(); 306 } 307 }; 308 309 IndexType type_; 310 size_t maxIndex_; 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(item->GetRefCount() > 0); 324 ASSERT(Has(item)); 325 Remove(item); 326 item->IncRefCount(); 327 Add(item); 328 } 329 DecRefCount(LineNumberProgramItem * item)330 void DecRefCount(LineNumberProgramItem *item) 331 { 332 ASSERT(Has(item)); 333 Remove(item); 334 item->DecRefCount(); 335 if (item->GetRefCount() == 0) { 336 item->SetNeedsEmit(false); 337 } else { 338 Add(item); 339 } 340 } 341 }; 342 343 class RegionHeaderItem : public BaseItem { 344 public: RegionHeaderItem(std::vector<IndexItem * > indexes)345 explicit RegionHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes)) 346 { 347 ASSERT(indexes_.size() == INDEX_COUNT_16); 348 } 349 350 ~RegionHeaderItem() override = default; 351 352 DEFAULT_COPY_SEMANTIC(RegionHeaderItem); 353 NO_MOVE_SEMANTIC(RegionHeaderItem); 354 Alignment()355 size_t Alignment() override 356 { 357 return ID_SIZE; 358 } 359 360 bool Write(Writer *writer) override; 361 GetItemType()362 ItemTypes GetItemType() const override 363 { 364 return ItemTypes::REGION_HEADER; 365 } 366 367 bool Add(const std::list<IndexedItem *> &items); 368 369 void Remove(const std::list<IndexedItem *> &items); 370 SetStart(BaseItem * item)371 void SetStart(BaseItem *item) 372 { 373 start_ = item; 374 } 375 SetEnd(BaseItem * item)376 void SetEnd(BaseItem *item) 377 { 378 end_ = item; 379 } 380 UpdateItems()381 void UpdateItems() 382 { 383 for (auto *index : indexes_) { 384 index->UpdateItems(start_, end_); 385 } 386 } 387 388 protected: CalculateSize()389 size_t CalculateSize() const override 390 { 391 return sizeof(File::RegionHeader); 392 } 393 394 private: GetIndexByType(IndexType type)395 IndexItem *GetIndexByType(IndexType type) const 396 { 397 auto i = static_cast<size_t>(type); 398 return indexes_[i]; 399 } 400 401 BaseItem *start_ {nullptr}; 402 BaseItem *end_ {nullptr}; 403 std::vector<IndexItem *> indexes_; 404 }; 405 406 class PANDA_PUBLIC_API RegionSectionItem : public BaseItem { 407 public: Alignment()408 size_t Alignment() override 409 { 410 return ID_SIZE; 411 } 412 413 bool Write(Writer *writer) override; 414 GetItemType()415 ItemTypes GetItemType() const override 416 { 417 return ItemTypes::REGION_SECTION; 418 } 419 Reset()420 void Reset() 421 { 422 headers_.clear(); 423 424 for (auto &index : indexes_) { 425 index.Reset(); 426 } 427 428 indexes_.clear(); 429 } 430 431 void AddHeader(); 432 GetCurrentHeader()433 RegionHeaderItem *GetCurrentHeader() 434 { 435 return &headers_.back(); 436 } 437 IsEmpty()438 bool IsEmpty() const 439 { 440 return headers_.empty(); 441 } 442 GetNumHeaders()443 size_t GetNumHeaders() const 444 { 445 return headers_.size(); 446 } 447 448 void ComputeLayout() override; 449 UpdateItems()450 void UpdateItems() 451 { 452 for (auto &header : headers_) { 453 header.UpdateItems(); 454 } 455 } 456 457 protected: 458 size_t CalculateSize() const override; 459 460 private: 461 std::list<RegionHeaderItem> headers_; 462 std::list<IndexItem> indexes_; 463 }; 464 465 class ProtoKey { 466 public: 467 ProtoKey(TypeItem *retType, const std::vector<MethodParamItem> ¶ms); 468 469 ~ProtoKey() = default; 470 471 DEFAULT_COPY_SEMANTIC(ProtoKey); 472 NO_MOVE_SEMANTIC(ProtoKey); 473 GetHash()474 size_t GetHash() const 475 { 476 return hash_; 477 } 478 479 bool operator==(const ProtoKey &key) const 480 { 481 return shorty_ == key.shorty_ && refTypes_ == key.refTypes_; 482 } 483 484 private: 485 void Add(TypeItem *item); 486 487 size_t hash_; 488 std::string shorty_; 489 std::vector<TypeItem *> refTypes_; 490 }; 491 492 struct ProtoKeyHash { operatorProtoKeyHash493 size_t operator()(const ProtoKey &key) const noexcept 494 { 495 return key.GetHash(); 496 }; 497 }; 498 499 struct LiteralArrayCompare { operatorLiteralArrayCompare500 bool operator()(const std::string &lhs, const std::string &rhs) const 501 { 502 return lhs.length() < rhs.length() || (lhs.length() == rhs.length() && lhs < rhs); 503 } 504 }; 505 506 class EndItem : public BaseItem { 507 public: EndItem()508 EndItem() 509 { 510 SetNeedsEmit(false); 511 } 512 513 ~EndItem() override = default; 514 515 DEFAULT_COPY_SEMANTIC(EndItem); 516 NO_MOVE_SEMANTIC(EndItem); 517 CalculateSize()518 size_t CalculateSize() const override 519 { 520 return 0; 521 } 522 Write(Writer * writer)523 bool Write([[maybe_unused]] Writer *writer) override 524 { 525 return true; 526 } 527 GetItemType()528 ItemTypes GetItemType() const override 529 { 530 return ItemTypes::END_ITEM; 531 } 532 }; 533 534 bool WriteHeader(Writer *writer, ssize_t *checksumOffset); 535 536 bool WriteHeaderIndexInfo(Writer *writer); 537 538 void RebuildRegionSection(); 539 540 void RebuildLineNumberProgramIndex(); 541 542 void UpdateOrderIndexes(); 543 544 void UpdateLiteralIndexes(); 545 546 void ProcessIndexDependecies(BaseItem *item); 547 548 size_t GetForeignOffset() const; 549 550 size_t GetForeignSize() const; 551 552 std::unordered_map<std::string, StringItem *> stringMap_; 553 std::map<std::string, LiteralArrayItem *, LiteralArrayCompare> literalarrayMap_; 554 555 std::map<std::string, BaseClassItem *> classMap_; 556 557 std::unordered_map<uint32_t, ValueItem *> intValueMap_; 558 std::unordered_map<uint64_t, ValueItem *> longValueMap_; 559 // NB! For f32 and f64 value maps we use integral keys 560 // (in fact, bit patterns of corresponding values) to 561 // workaround 0.0 == -0.0 semantics. 562 std::unordered_map<uint32_t, ValueItem *> floatValueMap_; 563 std::unordered_map<uint64_t, ValueItem *> doubleValueMap_; 564 std::unordered_map<BaseItem *, ValueItem *> idValueMap_; 565 std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> protoMap_; 566 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitiveTypeMap_; 567 568 std::list<std::unique_ptr<BaseItem>> items_; 569 570 std::vector<std::unique_ptr<BaseItem>> foreignItems_; 571 572 RegionSectionItem regionSectionItem_; 573 574 LineNumberProgramIndexItem lineNumberProgramIndexItem_; 575 576 std::list<std::unique_ptr<BaseItem>>::iterator itemsEnd_; 577 std::list<std::unique_ptr<BaseItem>>::iterator annotationItemsEnd_; 578 std::list<std::unique_ptr<BaseItem>>::iterator codeItemsEnd_; 579 std::list<std::unique_ptr<BaseItem>>::iterator debugItemsEnd_; 580 581 BaseItem *end_; 582 583 bool isQuickened_ = false; 584 }; 585 586 } // namespace ark::panda_file 587 588 #endif // LIBPANDAFILE_FILE_ITEM_CONTAINER_H_ 589