• 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 <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> &params);
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> &params)
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> &params);
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