• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 ark::panda_file {
33 
34 class ItemDeduper;
35 
36 class ItemContainer {
37 public:
38     PANDA_PUBLIC_API 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     PANDA_PUBLIC_API StringItem *GetOrCreateStringItem(const std::string &str);
49 
50     PANDA_PUBLIC_API LiteralArrayItem *GetOrCreateLiteralArrayItem(const std::string &id);
51 
52     PANDA_PUBLIC_API ClassItem *GetOrCreateClassItem(const std::string &str);
53 
54     PANDA_PUBLIC_API ForeignClassItem *GetOrCreateForeignClassItem(const std::string &str);
55 
56     PANDA_PUBLIC_API ScalarValueItem *GetOrCreateIntegerValueItem(uint32_t v);
57 
58     PANDA_PUBLIC_API ScalarValueItem *GetOrCreateLongValueItem(uint64_t v);
59 
60     PANDA_PUBLIC_API ScalarValueItem *GetOrCreateFloatValueItem(float v);
61 
62     PANDA_PUBLIC_API 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     PANDA_PUBLIC_API ProtoItem *GetOrCreateProtoItem(TypeItem *retType, const std::vector<MethodParamItem> &params);
72 
73     PrimitiveTypeItem *GetOrCreatePrimitiveTypeItem(Type type);
74 
75     PANDA_PUBLIC_API PrimitiveTypeItem *GetOrCreatePrimitiveTypeItem(Type::TypeId type);
76 
77     PANDA_PUBLIC_API 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     PANDA_PUBLIC_API uint32_t ComputeLayout();
118 
119     PANDA_PUBLIC_API bool Write(Writer *writer, bool deduplicateItems = true, bool computeLayout = true);
120 
121     PANDA_PUBLIC_API 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     PANDA_PUBLIC_API void ReorderItems(ark::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 PANDA_PUBLIC_API 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         PANDA_PUBLIC_API 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 
290                     auto typeId1 = static_cast<size_t>(typeItem1->GetType().GetId());
291                     auto typeId2 = static_cast<size_t>(typeItem2->GetType().GetId());
292                     if (typeId1 != typeId2) {
293                         return typeId1 < typeId2;
294                     }
295                 }
296 
297                 if (indexType == IndexType::LINE_NUMBER_PROG) {
298                     auto refCount1 = item1->GetRefCount();
299                     auto refCount2 = item2->GetRefCount();
300                     if (refCount1 != refCount2) {
301                         return refCount1 > refCount2;
302                     }
303                 }
304 
305                 return item1->GetItemAllocId() < item2->GetItemAllocId();
306             }
307         };
308 
309         IndexType type_;
310         size_t maxIndex_;
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(item->GetRefCount() > 0);
324             ASSERT(Has(item));
325             Remove(item);
326             item->IncRefCount();
327             Add(item);
328         }
329 
DecRefCount(LineNumberProgramItem * item)330         void DecRefCount(LineNumberProgramItem *item)
331         {
332             ASSERT(Has(item));
333             Remove(item);
334             item->DecRefCount();
335             if (item->GetRefCount() == 0) {
336                 item->SetNeedsEmit(false);
337             } else {
338                 Add(item);
339             }
340         }
341     };
342 
343     class RegionHeaderItem : public BaseItem {
344     public:
RegionHeaderItem(std::vector<IndexItem * > indexes)345         explicit RegionHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes))
346         {
347             ASSERT(indexes_.size() == INDEX_COUNT_16);
348         }
349 
350         ~RegionHeaderItem() override = default;
351 
352         DEFAULT_COPY_SEMANTIC(RegionHeaderItem);
353         NO_MOVE_SEMANTIC(RegionHeaderItem);
354 
Alignment()355         size_t Alignment() override
356         {
357             return ID_SIZE;
358         }
359 
360         bool Write(Writer *writer) override;
361 
GetItemType()362         ItemTypes GetItemType() const override
363         {
364             return ItemTypes::REGION_HEADER;
365         }
366 
367         bool Add(const std::list<IndexedItem *> &items);
368 
369         void Remove(const std::list<IndexedItem *> &items);
370 
SetStart(BaseItem * item)371         void SetStart(BaseItem *item)
372         {
373             start_ = item;
374         }
375 
SetEnd(BaseItem * item)376         void SetEnd(BaseItem *item)
377         {
378             end_ = item;
379         }
380 
UpdateItems()381         void UpdateItems()
382         {
383             for (auto *index : indexes_) {
384                 index->UpdateItems(start_, end_);
385             }
386         }
387 
388     protected:
CalculateSize()389         size_t CalculateSize() const override
390         {
391             return sizeof(File::RegionHeader);
392         }
393 
394     private:
GetIndexByType(IndexType type)395         IndexItem *GetIndexByType(IndexType type) const
396         {
397             auto i = static_cast<size_t>(type);
398             return indexes_[i];
399         }
400 
401         BaseItem *start_ {nullptr};
402         BaseItem *end_ {nullptr};
403         std::vector<IndexItem *> indexes_;
404     };
405 
406     class PANDA_PUBLIC_API RegionSectionItem : public BaseItem {
407     public:
Alignment()408         size_t Alignment() override
409         {
410             return ID_SIZE;
411         }
412 
413         bool Write(Writer *writer) override;
414 
GetItemType()415         ItemTypes GetItemType() const override
416         {
417             return ItemTypes::REGION_SECTION;
418         }
419 
Reset()420         void Reset()
421         {
422             headers_.clear();
423 
424             for (auto &index : indexes_) {
425                 index.Reset();
426             }
427 
428             indexes_.clear();
429         }
430 
431         void AddHeader();
432 
GetCurrentHeader()433         RegionHeaderItem *GetCurrentHeader()
434         {
435             return &headers_.back();
436         }
437 
IsEmpty()438         bool IsEmpty() const
439         {
440             return headers_.empty();
441         }
442 
GetNumHeaders()443         size_t GetNumHeaders() const
444         {
445             return headers_.size();
446         }
447 
448         void ComputeLayout() override;
449 
UpdateItems()450         void UpdateItems()
451         {
452             for (auto &header : headers_) {
453                 header.UpdateItems();
454             }
455         }
456 
457     protected:
458         size_t CalculateSize() const override;
459 
460     private:
461         std::list<RegionHeaderItem> headers_;
462         std::list<IndexItem> indexes_;
463     };
464 
465     class ProtoKey {
466     public:
467         ProtoKey(TypeItem *retType, const std::vector<MethodParamItem> &params);
468 
469         ~ProtoKey() = default;
470 
471         DEFAULT_COPY_SEMANTIC(ProtoKey);
472         NO_MOVE_SEMANTIC(ProtoKey);
473 
GetHash()474         size_t GetHash() const
475         {
476             return hash_;
477         }
478 
479         bool operator==(const ProtoKey &key) const
480         {
481             return shorty_ == key.shorty_ && refTypes_ == key.refTypes_;
482         }
483 
484     private:
485         void Add(TypeItem *item);
486 
487         size_t hash_;
488         std::string shorty_;
489         std::vector<TypeItem *> refTypes_;
490     };
491 
492     struct ProtoKeyHash {
operatorProtoKeyHash493         size_t operator()(const ProtoKey &key) const noexcept
494         {
495             return key.GetHash();
496         };
497     };
498 
499     struct LiteralArrayCompare {
operatorLiteralArrayCompare500         bool operator()(const std::string &lhs, const std::string &rhs) const
501         {
502             return lhs.length() < rhs.length() || (lhs.length() == rhs.length() && lhs < rhs);
503         }
504     };
505 
506     class EndItem : public BaseItem {
507     public:
EndItem()508         EndItem()
509         {
510             SetNeedsEmit(false);
511         }
512 
513         ~EndItem() override = default;
514 
515         DEFAULT_COPY_SEMANTIC(EndItem);
516         NO_MOVE_SEMANTIC(EndItem);
517 
CalculateSize()518         size_t CalculateSize() const override
519         {
520             return 0;
521         }
522 
Write(Writer * writer)523         bool Write([[maybe_unused]] Writer *writer) override
524         {
525             return true;
526         }
527 
GetItemType()528         ItemTypes GetItemType() const override
529         {
530             return ItemTypes::END_ITEM;
531         }
532     };
533 
534     bool WriteHeader(Writer *writer, ssize_t *checksumOffset);
535 
536     bool WriteHeaderIndexInfo(Writer *writer);
537 
538     void RebuildRegionSection();
539 
540     void RebuildLineNumberProgramIndex();
541 
542     void UpdateOrderIndexes();
543 
544     void UpdateLiteralIndexes();
545 
546     void ProcessIndexDependecies(BaseItem *item);
547 
548     size_t GetForeignOffset() const;
549 
550     size_t GetForeignSize() const;
551 
552     std::unordered_map<std::string, StringItem *> stringMap_;
553     std::map<std::string, LiteralArrayItem *, LiteralArrayCompare> literalarrayMap_;
554 
555     std::map<std::string, BaseClassItem *> classMap_;
556 
557     std::unordered_map<uint32_t, ValueItem *> intValueMap_;
558     std::unordered_map<uint64_t, ValueItem *> longValueMap_;
559     // NB! For f32 and f64 value maps we use integral keys
560     // (in fact, bit patterns of corresponding values) to
561     // workaround 0.0 == -0.0 semantics.
562     std::unordered_map<uint32_t, ValueItem *> floatValueMap_;
563     std::unordered_map<uint64_t, ValueItem *> doubleValueMap_;
564     std::unordered_map<BaseItem *, ValueItem *> idValueMap_;
565     std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> protoMap_;
566     std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitiveTypeMap_;
567 
568     std::list<std::unique_ptr<BaseItem>> items_;
569 
570     std::vector<std::unique_ptr<BaseItem>> foreignItems_;
571 
572     RegionSectionItem regionSectionItem_;
573 
574     LineNumberProgramIndexItem lineNumberProgramIndexItem_;
575 
576     std::list<std::unique_ptr<BaseItem>>::iterator itemsEnd_;
577     std::list<std::unique_ptr<BaseItem>>::iterator annotationItemsEnd_;
578     std::list<std::unique_ptr<BaseItem>>::iterator codeItemsEnd_;
579     std::list<std::unique_ptr<BaseItem>>::iterator debugItemsEnd_;
580 
581     BaseItem *end_;
582 
583     bool isQuickened_ = false;
584 };
585 
586 }  // namespace ark::panda_file
587 
588 #endif  // LIBPANDAFILE_FILE_ITEM_CONTAINER_H_
589