• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PANDA_LIBPANDAFILE_FILE_ITEM_CONTAINER_H_
17 #define PANDA_LIBPANDAFILE_FILE_ITEM_CONTAINER_H_
18 
19 #include "file_items.h"
20 #include "file_writer.h"
21 
22 #include <map>
23 #include <memory>
24 #include <set>
25 #include <string>
26 #include <unordered_map>
27 #include <unordered_set>
28 
29 namespace panda::panda_file {
30 
31 class ItemDeduper;
32 
33 class ItemContainer {
34 public:
35     ItemContainer() = default;
36     ~ItemContainer() = default;
37     NO_COPY_SEMANTIC(ItemContainer);
38     NO_MOVE_SEMANTIC(ItemContainer);
39 
40     StringItem *GetOrCreateStringItem(const std::string &str);
41 
42     LiteralArrayItem *GetOrCreateLiteralArrayItem(const std::string &id);
43 
44     ClassItem *GetOrCreateClassItem(const std::string &str);
45 
46     ForeignClassItem *GetOrCreateForeignClassItem(const std::string &str);
47 
48     ScalarValueItem *GetOrCreateIntegerValueItem(uint32_t v);
49 
50     ScalarValueItem *GetOrCreateLongValueItem(uint64_t v);
51 
52     ScalarValueItem *GetOrCreateFloatValueItem(float v);
53 
54     ScalarValueItem *GetOrCreateDoubleValueItem(double v);
55 
56     ScalarValueItem *GetOrCreateIdValueItem(BaseItem *v);
57 
GetOrCreateGlobalClassItem()58     ClassItem *GetOrCreateGlobalClassItem()
59     {
60         return GetOrCreateClassItem("L_GLOBAL;");
61     }
62 
63     ProtoItem *GetOrCreateProtoItem(TypeItem *ret_type, const std::vector<MethodParamItem> &params);
64 
65     LineNumberProgramItem *CreateLineNumberProgramItem();
66 
67     template <class T, class... Args>
CreateItem(Args &&...args)68     T *CreateItem(Args &&... args)
69     {
70         static_assert(!std::is_same_v<T, StringItem>, "Use GetOrCreateStringItem to create StringItem");
71         static_assert(!std::is_same_v<T, ClassItem>, "Use GetOrCreateClassItem to create ClassItem");
72         static_assert(!std::is_same_v<T, ForeignClassItem>,
73                       "Use GetOrCreateForeignClassItem to create ForeignClassItem");
74         static_assert(!std::is_same_v<T, ValueItem>, "Use GetOrCreateValueItem functions to create ValueItem");
75         static_assert(!std::is_same_v<T, ProtoItem>, "Use GetOrCreateProtoItem to create ValueItem");
76         static_assert(!std::is_same_v<T, LineNumberProgramItem>,
77                       "Use CreateLineNumberProgramItem to create LineNumberProgramItem");
78 
79         auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
80         auto ret = ptr.get();
81         if (ptr->IsForeign()) {
82             foreign_items_.emplace_back(std::move(ptr));
83         } else {
84             items_.emplace_back(std::move(ptr));
85         }
86         return ret;
87     }
88 
89     uint32_t ComputeLayout();
90     bool Write(Writer *writer);
91 
92     std::map<std::string, size_t> GetStat();
93 
94     void DumpItemsStat(std::ostream &os) const;
95 
96 private:
97     class IndexItem : public BaseItem {
98     public:
IndexItem(IndexType type,size_t max_index)99         IndexItem(IndexType type, size_t max_index) : type_(type), max_index_(max_index)
100         {
101             ASSERT(type_ != IndexType::NONE);
102         }
103 
104         ~IndexItem() override = default;
105 
106         DEFAULT_COPY_SEMANTIC(IndexItem);
107         NO_MOVE_SEMANTIC(IndexItem);
108 
Alignment()109         size_t Alignment() override
110         {
111             return sizeof(uint32_t);
112         }
113 
114         bool Write(Writer *writer) override;
115 
116         std::string GetName() const override;
117 
118         bool Add(IndexedItem *item);
119 
Has(IndexedItem * item)120         bool Has(IndexedItem *item) const
121         {
122             auto res = index_.find(item);
123             return res != index_.cend();
124         }
125 
Remove(IndexedItem * item)126         void Remove(IndexedItem *item)
127         {
128             index_.erase(item);
129         }
130 
GetNumItems()131         size_t GetNumItems() const
132         {
133             return index_.size();
134         }
135 
UpdateItems(BaseItem * start,BaseItem * end)136         void UpdateItems(BaseItem *start, BaseItem *end)
137         {
138             size_t i = 0;
139             for (auto *item : index_) {
140                 item->SetIndex(start, end, i++);
141             }
142         }
143 
Reset()144         void Reset()
145         {
146             for (auto *item : index_) {
147                 item->ClearIndexes();
148             }
149         }
150 
151     protected:
CalculateSize()152         size_t CalculateSize() const override
153         {
154             return index_.size() * ID_SIZE;
155         }
156 
157     private:
158         struct Comparator {
operatorComparator159             bool operator()(IndexedItem *item1, IndexedItem *item2) const noexcept
160             {
161                 auto index_type = item1->GetIndexType();
162 
163                 if (index_type == IndexType::CLASS) {
164                     auto type_item1 = static_cast<TypeItem *>(item1);
165                     auto type_item2 = static_cast<TypeItem *>(item2);
166                     auto type_id1 = static_cast<size_t>(type_item1->GetType().GetId());
167                     auto type_id2 = static_cast<size_t>(type_item2->GetType().GetId());
168 
169                     if (type_id1 != type_id2) {
170                         return type_id1 < type_id2;
171                     }
172                 }
173 
174                 if (index_type == IndexType::LINE_NUMBER_PROG) {
175                     auto ref_count1 = item1->GetRefCount();
176                     auto ref_count2 = item2->GetRefCount();
177 
178                     if (ref_count1 != ref_count2) {
179                         return ref_count1 > ref_count2;
180                     }
181                 }
182 
183                 return item1->GetIndexedItemCount() < item2->GetIndexedItemCount();
184             }
185         };
186 
187         IndexType type_;
188         size_t max_index_;
189         std::set<IndexedItem *, Comparator> index_;
190     };
191 
192     class LineNumberProgramIndexItem : public IndexItem {
193     public:
LineNumberProgramIndexItem()194         LineNumberProgramIndexItem() : IndexItem(IndexType::LINE_NUMBER_PROG, MAX_INDEX_32) {}
195         ~LineNumberProgramIndexItem() override = default;
196         DEFAULT_COPY_SEMANTIC(LineNumberProgramIndexItem);
197         NO_MOVE_SEMANTIC(LineNumberProgramIndexItem);
198 
IncRefCount(LineNumberProgramItem * item)199         void IncRefCount(LineNumberProgramItem *item)
200         {
201             ASSERT(Has(item));
202             Remove(item);
203             item->IncRefCount();
204             Add(item);
205         }
206 
DecRefCount(LineNumberProgramItem * item)207         void DecRefCount(LineNumberProgramItem *item)
208         {
209             ASSERT(Has(item));
210             Remove(item);
211             item->DecRefCount();
212             Add(item);
213         }
214     };
215 
216     class IndexHeaderItem : public BaseItem {
217     public:
IndexHeaderItem(std::vector<IndexItem * > indexes)218         explicit IndexHeaderItem(std::vector<IndexItem *> indexes) : indexes_(std::move(indexes))
219         {
220             ASSERT(indexes_.size() == INDEX_COUNT_16);
221         }
222 
223         ~IndexHeaderItem() override = default;
224 
225         DEFAULT_COPY_SEMANTIC(IndexHeaderItem);
226         NO_MOVE_SEMANTIC(IndexHeaderItem);
227 
Alignment()228         size_t Alignment() override
229         {
230             return ID_SIZE;
231         }
232 
233         bool Write(Writer *writer) override;
234 
GetName()235         std::string GetName() const override
236         {
237             return "index_header";
238         }
239 
240         bool Add(const std::list<IndexedItem *> &items);
241 
242         void Remove(const std::list<IndexedItem *> &items);
243 
SetStart(BaseItem * item)244         void SetStart(BaseItem *item)
245         {
246             start_ = item;
247         }
248 
SetEnd(BaseItem * item)249         void SetEnd(BaseItem *item)
250         {
251             end_ = item;
252         }
253 
UpdateItems()254         void UpdateItems()
255         {
256             for (auto *index : indexes_) {
257                 index->UpdateItems(start_, end_);
258             }
259         }
260 
261     protected:
CalculateSize()262         size_t CalculateSize() const override
263         {
264             return sizeof(File::IndexHeader);
265         }
266 
267     private:
IndexGetIndexByType(IndexType type)268         IndexItem *IndexGetIndexByType(IndexType type) const
269         {
270             auto i = static_cast<size_t>(type);
271             return indexes_[i];
272         }
273 
274         BaseItem *start_ {nullptr};
275         BaseItem *end_ {nullptr};
276         std::vector<IndexItem *> indexes_;
277     };
278 
279     class IndexSectionItem : public BaseItem {
280     public:
Alignment()281         size_t Alignment() override
282         {
283             return ID_SIZE;
284         }
285 
286         bool Write(Writer *writer) override;
287 
GetName()288         std::string GetName() const override
289         {
290             return "index_section";
291         }
292 
Reset()293         void Reset()
294         {
295             headers_.clear();
296 
297             for (auto &index : indexes_) {
298                 index.Reset();
299             }
300 
301             indexes_.clear();
302         }
303 
304         void AddHeader();
305 
GetCurrentHeader()306         IndexHeaderItem *GetCurrentHeader()
307         {
308             return &headers_.back();
309         }
310 
IsEmpty()311         bool IsEmpty() const
312         {
313             return headers_.empty();
314         }
315 
GetNumHeaders()316         size_t GetNumHeaders() const
317         {
318             return headers_.size();
319         }
320 
321         void ComputeLayout() override;
322 
UpdateItems()323         void UpdateItems()
324         {
325             for (auto &header : headers_) {
326                 header.UpdateItems();
327             }
328         }
329 
330     protected:
331         size_t CalculateSize() const override;
332 
333     private:
334         std::list<IndexHeaderItem> headers_;
335         std::list<IndexItem> indexes_;
336     };
337 
338     class ProtoKey {
339     public:
340         ProtoKey(TypeItem *ret_type, const std::vector<MethodParamItem> &params);
341 
342         ~ProtoKey() = default;
343 
344         DEFAULT_COPY_SEMANTIC(ProtoKey);
345         NO_MOVE_SEMANTIC(ProtoKey);
346 
GetHash()347         size_t GetHash() const
348         {
349             return hash_;
350         }
351 
352         bool operator==(const ProtoKey &key) const
353         {
354             return shorty_ == key.shorty_ && ref_types_ == key.ref_types_;
355         }
356 
357     private:
358         void Add(TypeItem *item);
359 
360         size_t hash_ {0};
361         std::string shorty_;
362         std::vector<TypeItem *> ref_types_;
363     };
364 
365     struct ProtoKeyHash {
operatorProtoKeyHash366         size_t operator()(const ProtoKey &key) const noexcept
367         {
368             return key.GetHash();
369         };
370     };
371 
372     struct LiteralArrayCompare {
operatorLiteralArrayCompare373         bool operator()(const std::string &lhs, const std::string &rhs) const
374         {
375             return lhs.length() < rhs.length() || (lhs.length() == rhs.length() && lhs < rhs);
376         }
377     };
378 
379     class EndItem : public BaseItem {
380     public:
EndItem()381         EndItem()
382         {
383             SetNeedsEmit(false);
384         }
385 
386         ~EndItem() override = default;
387 
388         DEFAULT_COPY_SEMANTIC(EndItem);
389         NO_MOVE_SEMANTIC(EndItem);
390 
CalculateSize()391         size_t CalculateSize() const override
392         {
393             return 0;
394         }
395 
Write(Writer * writer)396         bool Write([[maybe_unused]] Writer *writer) override
397         {
398             return true;
399         }
400 
GetName()401         std::string GetName() const override
402         {
403             return "end_item";
404         }
405     };
406 
407     bool WriteHeader(Writer *writer, ssize_t *checksum_offset);
408 
409     bool WriteHeaderIndexInfo(Writer *writer);
410 
411     void RebuildIndexSection();
412 
413     void RebuildLineNumberProgramIndex();
414 
415     void UpdateOrderIndexes();
416 
417     void ProcessIndexDependecies(BaseItem *item);
418 
419     size_t GetForeignOffset() const;
420 
421     size_t GetForeignSize() const;
422 
423     void DeduplicateItems();
424 
425     void DeduplicateCodeAndDebugInfo();
426 
427     void DeduplicateAnnotations();
428 
429     void DeduplicateLineNumberProgram(DebugInfoItem *item, ItemDeduper *deduper);
430 
431     void DeduplicateDebugInfo(MethodItem *method, ItemDeduper *debug_info_deduper,
432                               ItemDeduper *line_number_program_deduper);
433 
434     std::unordered_map<std::string, StringItem *> string_map_;
435     std::map<std::string, LiteralArrayItem *, LiteralArrayCompare> literalarray_map_;
436 
437     std::map<std::string, BaseClassItem *> class_map_;
438 
439     std::unordered_map<uint32_t, ValueItem *> int_value_map_;
440     std::unordered_map<uint64_t, ValueItem *> long_value_map_;
441     // NB! For f32 and f64 value maps we use integral keys
442     // (in fact, bit patterns of corresponding values) to
443     // workaround 0.0 == -0.0 semantics.
444     std::unordered_map<uint32_t, ValueItem *> float_value_map_;
445     std::unordered_map<uint64_t, ValueItem *> double_value_map_;
446     std::unordered_map<BaseItem *, ValueItem *> id_value_map_;
447     std::unordered_map<ProtoKey, ProtoItem *, ProtoKeyHash> proto_map_;
448 
449     std::vector<std::unique_ptr<BaseItem>> items_;
450     std::vector<std::unique_ptr<BaseItem>> foreign_items_;
451 
452     IndexSectionItem index_section_item_;
453 
454     LineNumberProgramIndexItem line_number_program_index_item_;
455 
456     EndItem end_;
457 };
458 
459 }  // namespace panda::panda_file
460 
461 #endif  // PANDA_LIBPANDAFILE_FILE_ITEM_CONTAINER_H_
462