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 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 StringItem *GetOrCreateStringItem(const std::string &str); 49 50 LiteralArrayItem *GetOrCreateLiteralArrayItem(const std::string &id); 51 52 ClassItem *GetOrCreateClassItem(const std::string &str); 53 54 ForeignClassItem *GetOrCreateForeignClassItem(const std::string &str); 55 56 ScalarValueItem *GetOrCreateIntegerValueItem(uint32_t v); 57 58 ScalarValueItem *GetOrCreateLongValueItem(uint64_t v); 59 60 ScalarValueItem *GetOrCreateFloatValueItem(float v); 61 62 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 ProtoItem *GetOrCreateProtoItem(TypeItem *retType, const std::vector<MethodParamItem> ¶ms); 72 73 PrimitiveTypeItem *GetOrCreatePrimitiveTypeItem(Type type); 74 75 PrimitiveTypeItem *GetOrCreatePrimitiveTypeItem(Type::TypeId type); 76 77 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 uint32_t ComputeLayout(); 118 119 bool Write(Writer *writer, bool deduplicateItems = true, bool computeLayout = true); 120 121 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 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 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 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 287 if (indexType == IndexType::CLASS) { 288 auto typeItem1 = static_cast<TypeItem *>(item1); 289 auto typeItem2 = static_cast<TypeItem *>(item2); 290 auto typeId1 = static_cast<size_t>(typeItem1->GetType().GetId()); 291 auto typeId2 = static_cast<size_t>(typeItem2->GetType().GetId()); 292 293 if (typeId1 != typeId2) { 294 return typeId1 < typeId2; 295 } 296 } 297 298 if (indexType == IndexType::LINE_NUMBER_PROG) { 299 auto refCount1 = item1->GetRefCount(); 300 auto refCount2 = item2->GetRefCount(); 301 302 if (refCount1 != refCount2) { 303 return refCount1 > refCount2; 304 } 305 } 306 307 return item1->GetItemAllocId() < item2->GetItemAllocId(); 308 } 309 }; 310 311 IndexType type_; 312 size_t maxIndex_; 313 std::set<IndexedItem *, Comparator> index_; 314 }; 315 316 class LineNumberProgramIndexItem : public IndexItem { 317 public: LineNumberProgramIndexItem()318 LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {} 319 ~LineNumberProgramIndexItem() override = default; 320 DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem); 321 NO_MOVE_SEMANTIC(LineNumberProgramIndexItem); 322 IncRefCount(LineNumberProgramItem * item)323 void IncRefCount(LineNumberProgramItem *item) 324 { 325 ASSERT(item->GetRefCount() > 0); 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 if (item->GetRefCount() == 0) { 338 item->SetNeedsEmit(false); 339 } else { 340 Add(item); 341 } 342 } 343 }; 344 345 class RegionHeaderItem : public BaseItem { 346 public: RegionHeaderItem(std::vector<IndexItem * > indexes)347 explicit RegionHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes)) 348 { 349 ASSERT(indexes_.size() == INDEX_COUNT_16); 350 } 351 352 ~RegionHeaderItem() override = default; 353 354 DEFAULT_COPY_SEMANTIC(RegionHeaderItem); 355 NO_MOVE_SEMANTIC(RegionHeaderItem); 356 Alignment()357 size_t Alignment() override 358 { 359 return ID_SIZE; 360 } 361 362 bool Write(Writer *writer) override; 363 GetItemType()364 ItemTypes GetItemType() const override 365 { 366 return ItemTypes::REGION_HEADER; 367 } 368 369 bool Add(const std::list<IndexedItem *> &items); 370 371 void Remove(const std::list<IndexedItem *> &items); 372 SetStart(BaseItem * item)373 void SetStart(BaseItem *item) 374 { 375 start_ = item; 376 } 377 SetEnd(BaseItem * item)378 void SetEnd(BaseItem *item) 379 { 380 end_ = item; 381 } 382 UpdateItems()383 void UpdateItems() 384 { 385 for (auto *index : indexes_) { 386 index->UpdateItems(start_, end_); 387 } 388 } 389 390 protected: CalculateSize()391 size_t CalculateSize() const override 392 { 393 return sizeof(File::RegionHeader); 394 } 395 396 private: GetIndexByType(IndexType type)397 IndexItem *GetIndexByType(IndexType type) const 398 { 399 auto i = static_cast<size_t>(type); 400 return indexes_[i]; 401 } 402 403 BaseItem *start_ {nullptr}; 404 BaseItem *end_ {nullptr}; 405 std::vector<IndexItem *> indexes_; 406 }; 407 408 class RegionSectionItem : public BaseItem { 409 public: Alignment()410 size_t Alignment() override 411 { 412 return ID_SIZE; 413 } 414 415 bool Write(Writer *writer) override; 416 GetItemType()417 ItemTypes GetItemType() const override 418 { 419 return ItemTypes::REGION_SECTION; 420 } 421 Reset()422 void Reset() 423 { 424 headers_.clear(); 425 426 for (auto &index : indexes_) { 427 index.Reset(); 428 } 429 430 indexes_.clear(); 431 } 432 433 void AddHeader(); 434 GetCurrentHeader()435 RegionHeaderItem *GetCurrentHeader() 436 { 437 return &headers_.back(); 438 } 439 IsEmpty()440 bool IsEmpty() const 441 { 442 return headers_.empty(); 443 } 444 GetNumHeaders()445 size_t GetNumHeaders() const 446 { 447 return headers_.size(); 448 } 449 450 void ComputeLayout() override; 451 UpdateItems()452 void UpdateItems() 453 { 454 for (auto &header : headers_) { 455 header.UpdateItems(); 456 } 457 } 458 459 protected: 460 size_t CalculateSize() const override; 461 462 private: 463 std::list<RegionHeaderItem> headers_; 464 std::list<IndexItem> indexes_; 465 }; 466 467 class ProtoKey { 468 public: 469 ProtoKey(TypeItem *retType, const std::vector<MethodParamItem> ¶ms); 470 471 ~ProtoKey() = default; 472 473 DEFAULT_COPY_SEMANTIC(ProtoKey); 474 NO_MOVE_SEMANTIC(ProtoKey); 475 GetHash()476 size_t GetHash() const 477 { 478 return hash_; 479 } 480 481 bool operator==(const ProtoKey &key) const 482 { 483 return shorty_ == key.shorty_ && refTypes_ == key.refTypes_; 484 } 485 486 private: 487 void Add(TypeItem *item); 488 489 size_t hash_; 490 std::string shorty_; 491 std::vector<TypeItem *> refTypes_; 492 }; 493 494 struct ProtoKeyHash { operatorProtoKeyHash495 size_t operator()(const ProtoKey &key) const noexcept 496 { 497 return key.GetHash(); 498 }; 499 }; 500 501 struct LiteralArrayCompare { operatorLiteralArrayCompare502 bool operator()(const std::string &lhs, const std::string &rhs) const 503 { 504 return lhs.length() < rhs.length() || (lhs.length() == rhs.length() && lhs < rhs); 505 } 506 }; 507 508 class EndItem : public BaseItem { 509 public: EndItem()510 EndItem() 511 { 512 SetNeedsEmit(false); 513 } 514 515 ~EndItem() override = default; 516 517 DEFAULT_COPY_SEMANTIC(EndItem); 518 NO_MOVE_SEMANTIC(EndItem); 519 CalculateSize()520 size_t CalculateSize() const override 521 { 522 return 0; 523 } 524 Write(Writer * writer)525 bool Write([[maybe_unused]] Writer *writer) override 526 { 527 return true; 528 } 529 GetItemType()530 ItemTypes GetItemType() const override 531 { 532 return ItemTypes::END_ITEM; 533 } 534 }; 535 536 bool WriteHeader(Writer *writer, ssize_t *checksumOffset); 537 538 bool WriteHeaderIndexInfo(Writer *writer); 539 540 void RebuildRegionSection(); 541 542 void RebuildLineNumberProgramIndex(); 543 544 void UpdateOrderIndexes(); 545 546 void UpdateLiteralIndexes(); 547 548 void ProcessIndexDependecies(BaseItem *item); 549 550 size_t GetForeignOffset() const; 551 552 size_t GetForeignSize() const; 553 554 std::unordered_map<std::string, StringItem *> stringMap_; 555 std::map<std::string, LiteralArrayItem *, LiteralArrayCompare> literalarrayMap_; 556 557 std::map<std::string, BaseClassItem *> classMap_; 558 559 std::unordered_map<uint32_t, ValueItem *> intValueMap_; 560 std::unordered_map<uint64_t, ValueItem *> longValueMap_; 561 // NB! For f32 and f64 value maps we use integral keys 562 // (in fact, bit patterns of corresponding values) to 563 // workaround 0.0 == -0.0 semantics. 564 std::unordered_map<uint32_t, ValueItem *> floatValueMap_; 565 std::unordered_map<uint64_t, ValueItem *> doubleValueMap_; 566 std::unordered_map<BaseItem *, ValueItem *> idValueMap_; 567 std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> protoMap_; 568 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitiveTypeMap_; 569 570 std::list<std::unique_ptr<BaseItem>> items_; 571 572 std::vector<std::unique_ptr<BaseItem>> foreignItems_; 573 574 RegionSectionItem regionSectionItem_; 575 576 LineNumberProgramIndexItem lineNumberProgramIndexItem_; 577 578 std::list<std::unique_ptr<BaseItem>>::iterator itemsEnd_; 579 std::list<std::unique_ptr<BaseItem>>::iterator annotationItemsEnd_; 580 std::list<std::unique_ptr<BaseItem>>::iterator codeItemsEnd_; 581 std::list<std::unique_ptr<BaseItem>>::iterator debugItemsEnd_; 582 583 BaseItem *end_; 584 585 bool isQuickened_ = false; 586 }; 587 588 } // namespace ark::panda_file 589 590 #endif // LIBPANDAFILE_FILE_ITEM_CONTAINER_H_ 591