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