• 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                 if (index_type == IndexType::CLASS) {
288                     auto type_item1 = static_cast<TypeItem *>(item1);
289                     auto type_item2 = static_cast<TypeItem *>(item2);
290                     auto type_id1 = static_cast<size_t>(type_item1->GetType().GetId());
291                     auto type_id2 = static_cast<size_t>(type_item2->GetType().GetId());
292                     if (type_id1 != type_id2) {
293                         return type_id1 < type_id2;
294                     }
295                 }
296 
297                 if (index_type == IndexType::LINE_NUMBER_PROG) {
298                     auto ref_count1 = item1->GetRefCount();
299                     auto ref_count2 = item2->GetRefCount();
300                     if (ref_count1 != ref_count2) {
301                         return ref_count1 > ref_count2;
302                     }
303                 }
304 
305                 return item1->GetIndexedItemCount() < item2->GetIndexedItemCount();
306             }
307         };
308 
309         IndexType type_;
310         size_t max_index_;
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(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             Add(item);
335         }
336     };
337 
338     class IndexHeaderItem : public BaseItem {
339     public:
IndexHeaderItem(std::vector<IndexItem * > indexes)340         explicit IndexHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes))
341         {
342             ASSERT(indexes_.size() == INDEX_COUNT_16);
343         }
344 
345         ~IndexHeaderItem() override = default;
346 
347         DEFAULT_COPY_SEMANTIC(IndexHeaderItem);
348         NO_MOVE_SEMANTIC(IndexHeaderItem);
349 
Alignment()350         size_t Alignment() override
351         {
352             return ID_SIZE;
353         }
354 
355         bool Write(Writer *writer) override;
356 
GetItemType()357         ItemTypes GetItemType() const override
358         {
359             return ItemTypes::INDEX_HEADER;
360         }
361 
362         bool Add(const std::list<IndexedItem *> &items);
363 
364         void Remove(const std::list<IndexedItem *> &items);
365 
SetStart(BaseItem * item)366         void SetStart(BaseItem *item)
367         {
368             start_ = item;
369         }
370 
SetEnd(BaseItem * item)371         void SetEnd(BaseItem *item)
372         {
373             end_ = item;
374         }
375 
UpdateItems()376         void UpdateItems()
377         {
378             for (auto *index : indexes_) {
379                 index->UpdateItems(start_, end_);
380             }
381         }
382 
383     protected:
CalculateSize()384         size_t CalculateSize() const override
385         {
386             return sizeof(File::IndexHeader);
387         }
388 
389     private:
IndexGetIndexByType(IndexType type)390         IndexItem *IndexGetIndexByType(IndexType type) const
391         {
392             auto i = static_cast<size_t>(type);
393             return indexes_[i];
394         }
395 
396         BaseItem *start_ {nullptr};
397         BaseItem *end_ {nullptr};
398         std::vector<IndexItem *> indexes_;
399     };
400 
401     class IndexSectionItem : public BaseItem {
402     public:
Alignment()403         size_t Alignment() override
404         {
405             return ID_SIZE;
406         }
407 
408         bool Write(Writer *writer) override;
409 
GetItemType()410         ItemTypes GetItemType() const override
411         {
412             return ItemTypes::INDEX_SECTION;
413         }
414 
Reset()415         void Reset()
416         {
417             headers_.clear();
418 
419             for (auto &index : indexes_) {
420                 index.Reset();
421             }
422 
423             indexes_.clear();
424         }
425 
426         void AddHeader();
427 
GetCurrentHeader()428         IndexHeaderItem *GetCurrentHeader()
429         {
430             return &headers_.back();
431         }
432 
IsEmpty()433         bool IsEmpty() const
434         {
435             return headers_.empty();
436         }
437 
GetNumHeaders()438         size_t GetNumHeaders() const
439         {
440             return headers_.size();
441         }
442 
443         void ComputeLayout() override;
444 
UpdateItems()445         void UpdateItems()
446         {
447             for (auto &header : headers_) {
448                 header.UpdateItems();
449             }
450         }
451 
452     protected:
453         size_t CalculateSize() const override;
454 
455     private:
456         std::list<IndexHeaderItem> headers_;
457         std::list<IndexItem> indexes_;
458     };
459 
460     class ProtoKey {
461     public:
462         ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> &params);
463 
464         ~ProtoKey() = default;
465 
466         DEFAULT_COPY_SEMANTIC(ProtoKey);
467         NO_MOVE_SEMANTIC(ProtoKey);
468 
GetHash()469         size_t GetHash() const
470         {
471             return hash_;
472         }
473 
474         bool operator==(const ProtoKey &key) const
475         {
476             return shorty_ == key.shorty_ && ref_types_ == key.ref_types_;
477         }
478 
479     private:
480         void Add(TypeItem *item);
481 
482         size_t hash_;
483         std::string shorty_;
484         std::vector<TypeItem *> ref_types_;
485     };
486 
487     struct ProtoKeyHash {
operatorProtoKeyHash488         size_t operator()(const ProtoKey &key) const noexcept
489         {
490             return key.GetHash();
491         };
492     };
493 
494     class EndItem : public BaseItem {
495     public:
EndItem()496         EndItem()
497         {
498             SetNeedsEmit(false);
499         }
500 
501         ~EndItem() override = default;
502 
503         DEFAULT_COPY_SEMANTIC(EndItem);
504         NO_MOVE_SEMANTIC(EndItem);
505 
CalculateSize()506         size_t CalculateSize() const override
507         {
508             return 0;
509         }
510 
Write(Writer * writer)511         bool Write([[maybe_unused]] Writer *writer) override
512         {
513             return true;
514         }
515 
GetItemType()516         ItemTypes GetItemType() const override
517         {
518             return ItemTypes::END_ITEM;
519         }
520     };
521 
522     bool WriteHeader(Writer *writer, ssize_t *checksum_offset);
523 
524     bool WriteHeaderIndexInfo(Writer *writer);
525 
526     void RebuildIndexSection();
527 
528     void RebuildLineNumberProgramIndex();
529 
530     void UpdateOrderIndexes();
531 
532     void AddIndexDependecies(BaseItem *item);
533 
534     void ProcessIndexDependecies(BaseItem *item);
535 
536     size_t GetForeignOffset() const;
537 
538     size_t GetForeignSize() const;
539 
540     std::unordered_map<std::string, StringItem *> string_map_;
541     std::unordered_map<std::string, LiteralArrayItem *> literalarray_map_;
542 
543     std::map<std::string, BaseClassItem *> class_map_;
544 
545     std::unordered_map<uint32_t, ValueItem *> int_value_map_;
546     std::unordered_map<uint64_t, ValueItem *> long_value_map_;
547     // NB! For f32 and f64 value maps we use integral keys
548     // (in fact, bit patterns of corresponding values) to
549     // workaround 0.0 == -0.0 semantics.
550     std::unordered_map<uint32_t, ValueItem *> float_value_map_;
551     std::unordered_map<uint64_t, ValueItem *> double_value_map_;
552     std::unordered_map<BaseItem *, ValueItem *> id_value_map_;
553     std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> proto_map_;
554     std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitive_type_map_;
555 
556     std::list<std::unique_ptr<BaseItem>> items_;
557 
558     std::vector<std::unique_ptr<BaseItem>> foreign_items_;
559 
560     IndexSectionItem index_section_item_;
561 
562     LineNumberProgramIndexItem line_number_program_index_item_;
563 
564     std::list<std::unique_ptr<BaseItem>>::iterator items_end_;
565     std::list<std::unique_ptr<BaseItem>>::iterator code_items_end_;
566     std::list<std::unique_ptr<BaseItem>>::iterator debug_items_end_;
567 
568     BaseItem *end_;
569     size_t indexed_item_count_ {0};
570 };
571 
572 }  // namespace panda::panda_file
573 
574 #endif  // LIBPANDAFILE_FILE_ITEM_CONTAINER_H
575