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