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