• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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     PANDA_PUBLIC_API void MarkLiteralarrayMap();
119     PANDA_PUBLIC_API void DeleteReferenceFromAnno(AnnotationItem *annoItem);
120     PANDA_PUBLIC_API void CleanupArrayValueItems(ValueItem *value);
121     PANDA_PUBLIC_API uint32_t DeleteItems();
122     PANDA_PUBLIC_API uint32_t DeleteForeignItems();
123 
124     PANDA_PUBLIC_API bool Write(Writer *writer, bool deduplicateItems = true, bool computeLayout = true);
125 
126     PANDA_PUBLIC_API std::map<std::string, size_t> GetStat();
127 
128     void DumpItemsStat(std::ostream &os) const;
129 
GetStringMap()130     std::unordered_map<std::string, StringItem *> *GetStringMap()
131     {
132         return &stringMap_;
133     }
134 
GetLiteralArrayItem(const std::string & key)135     LiteralArrayItem *GetLiteralArrayItem(const std::string &key)
136     {
137         return literalarrayMap_.at(key);
138     }
139 
GetClassMap()140     std::map<std::string, BaseClassItem *> *GetClassMap()
141     {
142         return &classMap_;
143     }
144 
GetIntValueMap()145     std::unordered_map<uint32_t, ValueItem *> *GetIntValueMap()
146     {
147         return &intValueMap_;
148     }
149 
GetLongValueMap()150     std::unordered_map<uint64_t, ValueItem *> *GetLongValueMap()
151     {
152         return &longValueMap_;
153     }
154 
GetFloatValueMap()155     std::unordered_map<uint32_t, ValueItem *> *GetFloatValueMap()
156     {
157         return &floatValueMap_;
158     }
159 
GetDoubleValueMap()160     std::unordered_map<uint64_t, ValueItem *> *GetDoubleValueMap()
161     {
162         return &doubleValueMap_;
163     }
164 
GetScalarValueMap()165     std::unordered_map<BaseItem *, ValueItem *> *GetScalarValueMap()
166     {
167         return &idValueMap_;
168     }
169 
GetProtoItem(TypeItem * retType,const std::vector<MethodParamItem> & params)170     ProtoItem *GetProtoItem(TypeItem *retType, const std::vector<MethodParamItem> &params)
171     {
172         return protoMap_.at(ProtoKey {retType, params});
173     }
174 
GetPrimitiveTypeMap()175     std::unordered_map<Type::TypeId, PrimitiveTypeItem *> *GetPrimitiveTypeMap()
176     {
177         return &primitiveTypeMap_;
178     }
179 
GetItems()180     const std::list<std::unique_ptr<BaseItem>> &GetItems() const
181     {
182         return items_;
183     }
184 
GetForeignItems()185     const std::vector<std::unique_ptr<BaseItem>> &GetForeignItems()
186     {
187         return foreignItems_;
188     }
189 
GetEndItem()190     BaseItem *GetEndItem()
191     {
192         return end_;
193     }
194 
195     PANDA_PUBLIC_API void ReorderItems(ark::panda_file::pgo::ProfileOptimizer *profileOpt);
196 
197     void DeduplicateItems(bool computeLayout = true);
198 
199     void DeduplicateCodeAndDebugInfo();
200 
201     void DeduplicateAnnotations();
202 
203     void DeduplicateLineNumberProgram(DebugInfoItem *item, ItemDeduper *deduper);
204 
205     void DeduplicateDebugInfo(MethodItem *method, ItemDeduper *debugInfoDeduper, ItemDeduper *lineNumberProgramDeduper);
206 
207 private:
208     template <class T>
GetInsertPosition()209     auto GetInsertPosition()
210     {
211         if (std::is_same_v<T, CodeItem>) {
212             return codeItemsEnd_;
213         }
214 
215         if (std::is_same_v<T, DebugInfoItem>) {
216             return debugItemsEnd_;
217         }
218 
219         if (std::is_same_v<T, AnnotationItem> || std::is_base_of_v<ValueItem, T>) {
220             return annotationItemsEnd_;
221         }
222 
223         return itemsEnd_;
224     }
225 
226     class PANDA_PUBLIC_API IndexItem : public BaseItem {
227     public:
IndexItem(IndexType type,size_t maxIndex)228         IndexItem(IndexType type, size_t maxIndex) : type_(type), maxIndex_(maxIndex)
229         {
230             ASSERT(type_ != IndexType::NONE);
231         }
232 
233         ~IndexItem() override = default;
234 
235         DEFAULT_COPY_SEMANTIC(IndexItem);
236         NO_MOVE_SEMANTIC(IndexItem);
237 
Alignment()238         size_t Alignment() override
239         {
240             return sizeof(uint32_t);
241         }
242 
243         PANDA_PUBLIC_API bool Write(Writer *writer) override;
244 
245         ItemTypes GetItemType() const override;
246 
247         bool Add(IndexedItem *item);
248 
Has(IndexedItem * item)249         bool Has(IndexedItem *item) const
250         {
251             auto res = index_.find(item);
252             return res != index_.cend();
253         }
254 
Remove(IndexedItem * item)255         void Remove(IndexedItem *item)
256         {
257             index_.erase(item);
258         }
259 
GetNumItems()260         size_t GetNumItems() const
261         {
262             return index_.size();
263         }
264 
UpdateItems(BaseItem * start,BaseItem * end)265         void UpdateItems(BaseItem *start, BaseItem *end)
266         {
267             size_t i = 0;
268             for (auto *item : index_) {
269                 item->SetIndex(start, end, i++);
270             }
271         }
272 
Reset()273         void Reset()
274         {
275             for (auto *item : index_) {
276                 item->ClearIndexes();
277             }
278         }
279 
280     protected:
CalculateSize()281         size_t CalculateSize() const override
282         {
283             return index_.size() * ID_SIZE;
284         }
285 
286     private:
287         struct Comparator {
operatorComparator288             bool operator()(IndexedItem *item1, IndexedItem *item2) const noexcept
289             {
290                 auto indexType = item1->GetIndexType();
291                 if (indexType == IndexType::CLASS) {
292                     auto typeItem1 = static_cast<TypeItem *>(item1);
293                     auto typeItem2 = static_cast<TypeItem *>(item2);
294 
295                     auto typeId1 = static_cast<size_t>(typeItem1->GetType().GetId());
296                     auto typeId2 = static_cast<size_t>(typeItem2->GetType().GetId());
297                     if (typeId1 != typeId2) {
298                         return typeId1 < typeId2;
299                     }
300                 }
301 
302                 if (indexType == IndexType::LINE_NUMBER_PROG) {
303                     auto refCount1 = item1->GetRefCount();
304                     auto refCount2 = item2->GetRefCount();
305                     if (refCount1 != refCount2) {
306                         return refCount1 > refCount2;
307                     }
308                 }
309 
310                 return item1->GetItemAllocId() < item2->GetItemAllocId();
311             }
312         };
313 
314         IndexType type_;
315         size_t maxIndex_;
316         std::set<IndexedItem *, Comparator> index_;
317     };
318 
319     class LineNumberProgramIndexItem : public IndexItem {
320     public:
LineNumberProgramIndexItem()321         LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {}
322         ~LineNumberProgramIndexItem() override = default;
323         DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem);
324         NO_MOVE_SEMANTIC(LineNumberProgramIndexItem);
325 
IncRefCount(LineNumberProgramItem * item)326         void IncRefCount(LineNumberProgramItem *item)
327         {
328             ASSERT(item->GetRefCount() > 0);
329             ASSERT(Has(item));
330             Remove(item);
331             item->IncRefCount();
332             Add(item);
333         }
334 
DecRefCount(LineNumberProgramItem * item)335         void DecRefCount(LineNumberProgramItem *item)
336         {
337             ASSERT(Has(item));
338             Remove(item);
339             item->DecRefCount();
340             if (item->GetRefCount() == 0) {
341                 item->SetNeedsEmit(false);
342             } else {
343                 Add(item);
344             }
345         }
346     };
347 
348     class RegionHeaderItem : public BaseItem {
349     public:
RegionHeaderItem(std::vector<IndexItem * > indexes)350         explicit RegionHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes))
351         {
352             ASSERT(indexes_.size() == INDEX_COUNT_16);
353         }
354 
355         ~RegionHeaderItem() override = default;
356 
357         DEFAULT_COPY_SEMANTIC(RegionHeaderItem);
358         NO_MOVE_SEMANTIC(RegionHeaderItem);
359 
Alignment()360         size_t Alignment() override
361         {
362             return ID_SIZE;
363         }
364 
365         bool Write(Writer *writer) override;
366 
GetItemType()367         ItemTypes GetItemType() const override
368         {
369             return ItemTypes::REGION_HEADER;
370         }
371 
372         bool Add(const std::list<IndexedItem *> &items);
373 
374         void Remove(const std::list<IndexedItem *> &items);
375 
SetStart(BaseItem * item)376         void SetStart(BaseItem *item)
377         {
378             start_ = item;
379         }
380 
SetEnd(BaseItem * item)381         void SetEnd(BaseItem *item)
382         {
383             end_ = item;
384         }
385 
UpdateItems()386         void UpdateItems()
387         {
388             for (auto *index : indexes_) {
389                 index->UpdateItems(start_, end_);
390             }
391         }
392 
393     protected:
CalculateSize()394         size_t CalculateSize() const override
395         {
396             return sizeof(File::RegionHeader);
397         }
398 
399     private:
GetIndexByType(IndexType type)400         IndexItem *GetIndexByType(IndexType type) const
401         {
402             auto i = static_cast<size_t>(type);
403             return indexes_[i];
404         }
405 
406         BaseItem *start_ {nullptr};
407         BaseItem *end_ {nullptr};
408         std::vector<IndexItem *> indexes_;
409     };
410 
411     class PANDA_PUBLIC_API RegionSectionItem : public BaseItem {
412     public:
Alignment()413         size_t Alignment() override
414         {
415             return ID_SIZE;
416         }
417 
418         bool Write(Writer *writer) override;
419 
GetItemType()420         ItemTypes GetItemType() const override
421         {
422             return ItemTypes::REGION_SECTION;
423         }
424 
Reset()425         void Reset()
426         {
427             headers_.clear();
428 
429             for (auto &index : indexes_) {
430                 index.Reset();
431             }
432 
433             indexes_.clear();
434         }
435 
436         void AddHeader();
437 
GetCurrentHeader()438         RegionHeaderItem *GetCurrentHeader()
439         {
440             return &headers_.back();
441         }
442 
IsEmpty()443         bool IsEmpty() const
444         {
445             return headers_.empty();
446         }
447 
GetNumHeaders()448         size_t GetNumHeaders() const
449         {
450             return headers_.size();
451         }
452 
453         void ComputeLayout() override;
454 
UpdateItems()455         void UpdateItems()
456         {
457             for (auto &header : headers_) {
458                 header.UpdateItems();
459             }
460         }
461 
462     protected:
463         size_t CalculateSize() const override;
464 
465     private:
466         std::list<RegionHeaderItem> headers_;
467         std::list<IndexItem> indexes_;
468     };
469 
470     class ProtoKey {
471     public:
472         ProtoKey(TypeItem *retType, const std::vector<MethodParamItem> &params);
473 
474         ~ProtoKey() = default;
475 
476         DEFAULT_COPY_SEMANTIC(ProtoKey);
477         NO_MOVE_SEMANTIC(ProtoKey);
478 
GetHash()479         size_t GetHash() const
480         {
481             return hash_;
482         }
483 
484         bool operator==(const ProtoKey &key) const
485         {
486             return shorty_ == key.shorty_ && refTypes_ == key.refTypes_;
487         }
488 
489     private:
490         void Add(TypeItem *item);
491 
492         size_t hash_;
493         std::string shorty_;
494         std::vector<TypeItem *> refTypes_;
495     };
496 
497     struct ProtoKeyHash {
operatorProtoKeyHash498         size_t operator()(const ProtoKey &key) const noexcept
499         {
500             return key.GetHash();
501         };
502     };
503 
504     struct LiteralArrayCompare {
operatorLiteralArrayCompare505         bool operator()(const std::string &lhs, const std::string &rhs) const
506         {
507             return lhs.length() < rhs.length() || (lhs.length() == rhs.length() && lhs < rhs);
508         }
509     };
510 
511     class EndItem : public BaseItem {
512     public:
EndItem()513         EndItem()
514         {
515             SetNeedsEmit(false);
516         }
517 
518         ~EndItem() override = default;
519 
520         DEFAULT_COPY_SEMANTIC(EndItem);
521         NO_MOVE_SEMANTIC(EndItem);
522 
CalculateSize()523         size_t CalculateSize() const override
524         {
525             return 0;
526         }
527 
Write(Writer * writer)528         bool Write([[maybe_unused]] Writer *writer) override
529         {
530             return true;
531         }
532 
GetItemType()533         ItemTypes GetItemType() const override
534         {
535             return ItemTypes::END_ITEM;
536         }
537     };
538 
539     bool WriteHeader(Writer *writer, ssize_t *checksumOffset);
540 
541     bool WriteHeaderIndexInfo(Writer *writer);
542 
543     void RebuildRegionSection();
544 
545     void RebuildLineNumberProgramIndex();
546 
547     void UpdateOrderIndexes();
548 
549     void UpdateLiteralIndexes();
550 
551     void ProcessIndexDependecies(BaseItem *item);
552 
553     size_t GetForeignOffset() const;
554 
555     size_t GetForeignSize() const;
556 
557     std::unordered_map<std::string, StringItem *> stringMap_;
558     std::map<std::string, LiteralArrayItem *, LiteralArrayCompare> literalarrayMap_;
559 
560     std::map<std::string, BaseClassItem *> classMap_;
561 
562     std::unordered_map<uint32_t, ValueItem *> intValueMap_;
563     std::unordered_map<uint64_t, ValueItem *> longValueMap_;
564     // NB! For f32 and f64 value maps we use integral keys
565     // (in fact, bit patterns of corresponding values) to
566     // workaround 0.0 == -0.0 semantics.
567     std::unordered_map<uint32_t, ValueItem *> floatValueMap_;
568     std::unordered_map<uint64_t, ValueItem *> doubleValueMap_;
569     std::unordered_map<BaseItem *, ValueItem *> idValueMap_;
570     std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> protoMap_;
571     std::unordered_map<Type::TypeId, PrimitiveTypeItem *> primitiveTypeMap_;
572 
573     std::list<std::unique_ptr<BaseItem>> items_;
574 
575     std::vector<std::unique_ptr<BaseItem>> foreignItems_;
576 
577     RegionSectionItem regionSectionItem_;
578 
579     LineNumberProgramIndexItem lineNumberProgramIndexItem_;
580 
581     std::list<std::unique_ptr<BaseItem>>::iterator itemsEnd_;
582     std::list<std::unique_ptr<BaseItem>>::iterator annotationItemsEnd_;
583     std::list<std::unique_ptr<BaseItem>>::iterator codeItemsEnd_;
584     std::list<std::unique_ptr<BaseItem>>::iterator debugItemsEnd_;
585 
586     BaseItem *end_;
587 
588     bool isQuickened_ = false;
589 };
590 
591 }  // namespace ark::panda_file
592 
593 #endif  // LIBPANDAFILE_FILE_ITEM_CONTAINER_H_
594