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