1 /* 2 * Copyright (c) 2021 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 PANDA_LIBPANDAFILE_FILE_ITEM_CONTAINER_H_ 17 #define PANDA_LIBPANDAFILE_FILE_ITEM_CONTAINER_H_ 18 19 #include "file_items.h" 20 #include "file_writer.h" 21 22 #include <map> 23 #include <memory> 24 #include <set> 25 #include <string> 26 #include <unordered_map> 27 #include <unordered_set> 28 29 namespace panda::panda_file { 30 31 class ItemDeduper; 32 33 class ItemContainer { 34 public: 35 ItemContainer() = default; 36 ~ItemContainer() = default; 37 NO_COPY_SEMANTIC(ItemContainer); 38 NO_MOVE_SEMANTIC(ItemContainer); 39 40 StringItem *GetOrCreateStringItem(const std::string &str); 41 42 LiteralArrayItem *GetOrCreateLiteralArrayItem(const std::string &id); 43 44 ClassItem *GetOrCreateClassItem(const std::string &str); 45 46 ForeignClassItem *GetOrCreateForeignClassItem(const std::string &str); 47 48 ScalarValueItem *GetOrCreateIntegerValueItem(uint32_t v); 49 50 ScalarValueItem *GetOrCreateLongValueItem(uint64_t v); 51 52 ScalarValueItem *GetOrCreateFloatValueItem(float v); 53 54 ScalarValueItem *GetOrCreateDoubleValueItem(double v); 55 56 ScalarValueItem *GetOrCreateIdValueItem(BaseItem *v); 57 GetOrCreateGlobalClassItem()58 ClassItem *GetOrCreateGlobalClassItem() 59 { 60 return GetOrCreateClassItem("L_GLOBAL;"); 61 } 62 63 ProtoItem *GetOrCreateProtoItem(TypeItem *ret_type, const std::vector<MethodParamItem> ¶ms); 64 65 LineNumberProgramItem *CreateLineNumberProgramItem(); 66 67 template <class T, class... Args> CreateItem(Args &&...args)68 T *CreateItem(Args &&... args) 69 { 70 static_assert(!std::is_same_v<T, StringItem>, "Use GetOrCreateStringItem to create StringItem"); 71 static_assert(!std::is_same_v<T, ClassItem>, "Use GetOrCreateClassItem to create ClassItem"); 72 static_assert(!std::is_same_v<T, ForeignClassItem>, 73 "Use GetOrCreateForeignClassItem to create ForeignClassItem"); 74 static_assert(!std::is_same_v<T, ValueItem>, "Use GetOrCreateValueItem functions to create ValueItem"); 75 static_assert(!std::is_same_v<T, ProtoItem>, "Use GetOrCreateProtoItem to create ValueItem"); 76 static_assert(!std::is_same_v<T, LineNumberProgramItem>, 77 "Use CreateLineNumberProgramItem to create LineNumberProgramItem"); 78 79 auto ptr = std::make_unique<T>(std::forward<Args>(args)...); 80 auto ret = ptr.get(); 81 if (ptr->IsForeign()) { 82 foreign_items_.emplace_back(std::move(ptr)); 83 } else { 84 items_.emplace_back(std::move(ptr)); 85 } 86 return ret; 87 } 88 89 uint32_t ComputeLayout(); 90 bool Write(Writer *writer); 91 92 std::map<std::string, size_t> GetStat(); 93 94 void DumpItemsStat(std::ostream &os) const; 95 96 private: 97 class IndexItem : public BaseItem { 98 public: IndexItem(IndexType type,size_t max_index)99 IndexItem(IndexType type, size_t max_index) : type_(type), max_index_(max_index) 100 { 101 ASSERT(type_ != IndexType::NONE); 102 } 103 104 ~IndexItem() override = default; 105 106 DEFAULT_COPY_SEMANTIC(IndexItem); 107 NO_MOVE_SEMANTIC(IndexItem); 108 Alignment()109 size_t Alignment() override 110 { 111 return sizeof(uint32_t); 112 } 113 114 bool Write(Writer *writer) override; 115 116 std::string GetName() const override; 117 118 bool Add(IndexedItem *item); 119 Has(IndexedItem * item)120 bool Has(IndexedItem *item) const 121 { 122 auto res = index_.find(item); 123 return res != index_.cend(); 124 } 125 Remove(IndexedItem * item)126 void Remove(IndexedItem *item) 127 { 128 index_.erase(item); 129 } 130 GetNumItems()131 size_t GetNumItems() const 132 { 133 return index_.size(); 134 } 135 UpdateItems(BaseItem * start,BaseItem * end)136 void UpdateItems(BaseItem *start, BaseItem *end) 137 { 138 size_t i = 0; 139 for (auto *item : index_) { 140 item->SetIndex(start, end, i++); 141 } 142 } 143 Reset()144 void Reset() 145 { 146 for (auto *item : index_) { 147 item->ClearIndexes(); 148 } 149 } 150 151 protected: CalculateSize()152 size_t CalculateSize() const override 153 { 154 return index_.size() * ID_SIZE; 155 } 156 157 private: 158 struct Comparator { operatorComparator159 bool operator()(IndexedItem *item1, IndexedItem *item2) const noexcept 160 { 161 auto index_type = item1->GetIndexType(); 162 163 if (index_type == IndexType::CLASS) { 164 auto type_item1 = static_cast<TypeItem *>(item1); 165 auto type_item2 = static_cast<TypeItem *>(item2); 166 auto type_id1 = static_cast<size_t>(type_item1->GetType().GetId()); 167 auto type_id2 = static_cast<size_t>(type_item2->GetType().GetId()); 168 169 if (type_id1 != type_id2) { 170 return type_id1 < type_id2; 171 } 172 } 173 174 if (index_type == IndexType::LINE_NUMBER_PROG) { 175 auto ref_count1 = item1->GetRefCount(); 176 auto ref_count2 = item2->GetRefCount(); 177 178 if (ref_count1 != ref_count2) { 179 return ref_count1 > ref_count2; 180 } 181 } 182 183 return item1->GetIndexedItemCount() < item2->GetIndexedItemCount(); 184 } 185 }; 186 187 IndexType type_; 188 size_t max_index_; 189 std::set<IndexedItem *, Comparator> index_; 190 }; 191 192 class LineNumberProgramIndexItem : public IndexItem { 193 public: LineNumberProgramIndexItem()194 LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {} 195 ~LineNumberProgramIndexItem() override = default; 196 DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem); 197 NO_MOVE_SEMANTIC(LineNumberProgramIndexItem); 198 IncRefCount(LineNumberProgramItem * item)199 void IncRefCount(LineNumberProgramItem *item) 200 { 201 ASSERT(Has(item)); 202 Remove(item); 203 item->IncRefCount(); 204 Add(item); 205 } 206 DecRefCount(LineNumberProgramItem * item)207 void DecRefCount(LineNumberProgramItem *item) 208 { 209 ASSERT(Has(item)); 210 Remove(item); 211 item->DecRefCount(); 212 Add(item); 213 } 214 }; 215 216 class IndexHeaderItem : public BaseItem { 217 public: IndexHeaderItem(std::vector<IndexItem * > indexes)218 explicit IndexHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes)) 219 { 220 ASSERT(indexes_.size() == INDEX_COUNT_16); 221 } 222 223 ~IndexHeaderItem() override = default; 224 225 DEFAULT_COPY_SEMANTIC(IndexHeaderItem); 226 NO_MOVE_SEMANTIC(IndexHeaderItem); 227 Alignment()228 size_t Alignment() override 229 { 230 return ID_SIZE; 231 } 232 233 bool Write(Writer *writer) override; 234 GetName()235 std::string GetName() const override 236 { 237 return "index_header"; 238 } 239 240 bool Add(const std::list<IndexedItem *> &items); 241 242 void Remove(const std::list<IndexedItem *> &items); 243 SetStart(BaseItem * item)244 void SetStart(BaseItem *item) 245 { 246 start_ = item; 247 } 248 SetEnd(BaseItem * item)249 void SetEnd(BaseItem *item) 250 { 251 end_ = item; 252 } 253 UpdateItems()254 void UpdateItems() 255 { 256 for (auto *index : indexes_) { 257 index->UpdateItems(start_, end_); 258 } 259 } 260 261 protected: CalculateSize()262 size_t CalculateSize() const override 263 { 264 return sizeof(File::IndexHeader); 265 } 266 267 private: IndexGetIndexByType(IndexType type)268 IndexItem *IndexGetIndexByType(IndexType type) const 269 { 270 auto i = static_cast<size_t>(type); 271 return indexes_[i]; 272 } 273 274 BaseItem *start_ {nullptr}; 275 BaseItem *end_ {nullptr}; 276 std::vector<IndexItem *> indexes_; 277 }; 278 279 class IndexSectionItem : public BaseItem { 280 public: Alignment()281 size_t Alignment() override 282 { 283 return ID_SIZE; 284 } 285 286 bool Write(Writer *writer) override; 287 GetName()288 std::string GetName() const override 289 { 290 return "index_section"; 291 } 292 Reset()293 void Reset() 294 { 295 headers_.clear(); 296 297 for (auto &index : indexes_) { 298 index.Reset(); 299 } 300 301 indexes_.clear(); 302 } 303 304 void AddHeader(); 305 GetCurrentHeader()306 IndexHeaderItem *GetCurrentHeader() 307 { 308 return &headers_.back(); 309 } 310 IsEmpty()311 bool IsEmpty() const 312 { 313 return headers_.empty(); 314 } 315 GetNumHeaders()316 size_t GetNumHeaders() const 317 { 318 return headers_.size(); 319 } 320 321 void ComputeLayout() override; 322 UpdateItems()323 void UpdateItems() 324 { 325 for (auto &header : headers_) { 326 header.UpdateItems(); 327 } 328 } 329 330 protected: 331 size_t CalculateSize() const override; 332 333 private: 334 std::list<IndexHeaderItem> headers_; 335 std::list<IndexItem> indexes_; 336 }; 337 338 class ProtoKey { 339 public: 340 ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> ¶ms); 341 342 ~ProtoKey() = default; 343 344 DEFAULT_COPY_SEMANTIC(ProtoKey); 345 NO_MOVE_SEMANTIC(ProtoKey); 346 GetHash()347 size_t GetHash() const 348 { 349 return hash_; 350 } 351 352 bool operator==(const ProtoKey &key) const 353 { 354 return shorty_ == key.shorty_ && ref_types_ == key.ref_types_; 355 } 356 357 private: 358 void Add(TypeItem *item); 359 360 size_t hash_ {0}; 361 std::string shorty_; 362 std::vector<TypeItem *> ref_types_; 363 }; 364 365 struct ProtoKeyHash { operatorProtoKeyHash366 size_t operator()(const ProtoKey &key) const noexcept 367 { 368 return key.GetHash(); 369 }; 370 }; 371 372 struct LiteralArrayCompare { operatorLiteralArrayCompare373 bool operator()(const std::string &lhs, const std::string &rhs) const 374 { 375 return lhs.length() < rhs.length() || (lhs.length() == rhs.length() && lhs < rhs); 376 } 377 }; 378 379 class EndItem : public BaseItem { 380 public: EndItem()381 EndItem() 382 { 383 SetNeedsEmit(false); 384 } 385 386 ~EndItem() override = default; 387 388 DEFAULT_COPY_SEMANTIC(EndItem); 389 NO_MOVE_SEMANTIC(EndItem); 390 CalculateSize()391 size_t CalculateSize() const override 392 { 393 return 0; 394 } 395 Write(Writer * writer)396 bool Write([[maybe_unused]] Writer *writer) override 397 { 398 return true; 399 } 400 GetName()401 std::string GetName() const override 402 { 403 return "end_item"; 404 } 405 }; 406 407 bool WriteHeader(Writer *writer, ssize_t *checksum_offset); 408 409 bool WriteHeaderIndexInfo(Writer *writer); 410 411 void RebuildIndexSection(); 412 413 void RebuildLineNumberProgramIndex(); 414 415 void UpdateOrderIndexes(); 416 417 void ProcessIndexDependecies(BaseItem *item); 418 419 size_t GetForeignOffset() const; 420 421 size_t GetForeignSize() const; 422 423 void DeduplicateItems(); 424 425 void DeduplicateCodeAndDebugInfo(); 426 427 void DeduplicateAnnotations(); 428 429 void DeduplicateLineNumberProgram(DebugInfoItem *item, ItemDeduper *deduper); 430 431 void DeduplicateDebugInfo(MethodItem *method, ItemDeduper *debug_info_deduper, 432 ItemDeduper *line_number_program_deduper); 433 434 std::unordered_map<std::string, StringItem *> string_map_; 435 std::map<std::string, LiteralArrayItem *, LiteralArrayCompare> literalarray_map_; 436 437 std::map<std::string, BaseClassItem *> class_map_; 438 439 std::unordered_map<uint32_t, ValueItem *> int_value_map_; 440 std::unordered_map<uint64_t, ValueItem *> long_value_map_; 441 // NB! For f32 and f64 value maps we use integral keys 442 // (in fact, bit patterns of corresponding values) to 443 // workaround 0.0 == -0.0 semantics. 444 std::unordered_map<uint32_t, ValueItem *> float_value_map_; 445 std::unordered_map<uint64_t, ValueItem *> double_value_map_; 446 std::unordered_map<BaseItem *, ValueItem *> id_value_map_; 447 std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> proto_map_; 448 449 std::vector<std::unique_ptr<BaseItem>> items_; 450 std::vector<std::unique_ptr<BaseItem>> foreign_items_; 451 452 IndexSectionItem index_section_item_; 453 454 LineNumberProgramIndexItem line_number_program_index_item_; 455 456 EndItem end_; 457 }; 458 459 } // namespace panda::panda_file 460 461 #endif // PANDA_LIBPANDAFILE_FILE_ITEM_CONTAINER_H_ 462