• 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 ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H
17 #define ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H
18 
19 #include <iostream>
20 #include <fstream>
21 #include <sstream>
22 
23 #include "common_components/serialize/serialize_utils.h"
24 #include "ecmascript/serializer/serialize_data.h"
25 #include "ecmascript/snapshot/mem/encode_bit.h"
26 #include "ecmascript/jspandafile/method_literal.h"
27 #include "ecmascript/js_tagged_value.h"
28 #include "ecmascript/mem/object_xray.h"
29 
30 #include "libpandabase/macros.h"
31 
32 namespace panda::ecmascript {
33 class EcmaVM;
34 class JSPandaFile;
35 class AOTFileManager;
36 
37 enum class SnapshotType {
38     VM_ROOT,
39     BUILTINS,
40     AI
41 };
42 
43 struct SnapshotRegionHeadInfo {
44     size_t regionIndex_ {0};
45     size_t aliveObjectSize_ {0};
46 
RegionHeadInfoSizeSnapshotRegionHeadInfo47     static constexpr size_t RegionHeadInfoSize()
48     {
49         return sizeof(SnapshotRegionHeadInfo);
50     }
51 };
52 
53 using ObjectEncode = std::pair<uint64_t, ecmascript::EncodeBit>;
54 
55 class SnapshotProcessor final {
56 public:
SnapshotProcessor(EcmaVM * vm)57     explicit SnapshotProcessor(EcmaVM *vm)
58         : vm_(vm), sHeap_(SharedHeap::GetInstance()) {}
59     ~SnapshotProcessor();
60 
61     struct AllocResult {
62         uintptr_t address;
63         size_t offset;
64         size_t regionIndex;
65     };
66 
67     void Initialize();
68     void StopAllocate();
69     void WriteObjectToFile(std::fstream &write);
70     std::vector<size_t> StatisticsObjectSize();
71     void ProcessObjectQueue(CQueue<TaggedObject *> *queue, std::unordered_map<uint64_t, ObjectEncode> *data);
72     void SerializeObject(TaggedObject *objectHeader, CQueue<TaggedObject *> *queue,
73                          std::unordered_map<uint64_t, ObjectEncode> *data);
74     void Relocate(SnapshotType type, const JSPandaFile *jsPandaFile,
75                   uint64_t rootObjSize);
76     void RelocateSpaceObject(std::vector<std::pair<uintptr_t, size_t>> &regions, SnapshotType type,
77         MethodLiteral* methods, size_t methodNums, size_t rootObjSize);
78     void RelocateSpaceObject(Space* space, SnapshotType type, MethodLiteral* methods,
79                              size_t methodNums, size_t rootObjSize);
80     void SerializePandaFileMethod();
81     AllocResult GetNewObj(size_t objectSize, TaggedObject *objectHeader);
82     uintptr_t GetNewObjAddress(size_t objectSize, TaggedObject *objectHeader);
83     EncodeBit EncodeTaggedObject(TaggedObject *objectHeader, CQueue<TaggedObject *> *queue,
84                                  std::unordered_map<uint64_t, ObjectEncode> *data);
85     EncodeBit GetObjectEncode(JSTaggedValue object, CQueue<TaggedObject *> *queue,
86                               std::unordered_map<uint64_t, ObjectEncode> *data);
87     void EncodeTaggedObjectRange(ObjectSlot start, ObjectSlot end, CQueue<TaggedObject *> *queue,
88                                  std::unordered_map<uint64_t, ObjectEncode> *data);
89     void DeserializeObjectExcludeString(uintptr_t regularObjBegin, size_t regularObjSize, size_t pinnedObjSize,
90                                         size_t largeObjSize);
91     void DeserializeObjectExcludeString(uintptr_t oldSpaceBegin, size_t oldSpaceObjSize, size_t nonMovableObjSize,
92                                         size_t machineCodeObjSize, size_t snapshotObjSize, size_t hugeSpaceObjSize);
93     void DeserializeString(uintptr_t stringBegin, uintptr_t stringEnd);
94 
95     // ONLY used in UT to get the deserialize value result
GetDeserializeResultForUT()96     JSTaggedValue GetDeserializeResultForUT() const
97     {
98         return root_;
99     }
100 
101     void AddRootObjectToAOTFileManager(SnapshotType type, const CString &fileName);
102 
SetProgramSerializeStart()103     void SetProgramSerializeStart()
104     {
105         programSerialize_ = true;
106     }
107 
SetBuiltinsSerializeStart()108     void SetBuiltinsSerializeStart()
109     {
110         builtinsSerialize_ = true;
111     }
112 
SetBuiltinsDeserializeStart()113     void SetBuiltinsDeserializeStart()
114     {
115         builtinsDeserialize_ = true;
116     }
117 
GetStringVector()118     const CVector<uintptr_t> GetStringVector() const
119     {
120         return stringVector_;
121     }
122 
123     size_t GetNativeTableSize() const;
124 
125 private:
126     class SerializeObjectVisitor final : public BaseObjectVisitor<SerializeObjectVisitor> {
127     public:
128         explicit SerializeObjectVisitor(SnapshotProcessor *processor, uintptr_t snapshotObj,
129             CQueue<TaggedObject *> *queue, std::unordered_map<uint64_t, ObjectEncode> *data);
130         ~SerializeObjectVisitor() override = default;
131 
132         void VisitObjectRangeImpl(BaseObject *rootObject, uintptr_t startAddr,
133                                   uintptr_t endAddr, VisitObjectArea area) override;
134     private:
135         SnapshotProcessor *processor_ {nullptr};
136         uintptr_t snapshotObj_ {-1};
137         CQueue<TaggedObject *> *queue_ {nullptr};
138         std::unordered_map<uint64_t, ObjectEncode> *data_{nullptr};
139     };
140 
141     class DeserializeFieldVisitor final : public BaseObjectVisitor<DeserializeFieldVisitor> {
142     public:
143         explicit DeserializeFieldVisitor(SnapshotProcessor *processor);
144         ~DeserializeFieldVisitor() override = default;
145 
146         void VisitObjectRangeImpl(BaseObject *rootObject, uintptr_t startAddr, uintptr_t endAddr,
147                                   VisitObjectArea area) override;
148     private:
149         SnapshotProcessor *processor_ {nullptr};
150     };
GetMarkGCBitSetSize()151     size_t GetMarkGCBitSetSize() const
152     {
153         return GCBitset::SizeOfGCBitset(DEFAULT_REGION_SIZE -
154             AlignUp(sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION)));
155     }
156 
157     bool VisitObjectBodyWithRep(TaggedObject *root, ObjectSlot slot, uintptr_t obj, int index, VisitObjectArea area);
158     void SetObjectEncodeField(uintptr_t obj, size_t offset, uint64_t value);
159 
160     EncodeBit SerializeObjectHeader(TaggedObject *objectHeader, size_t objectType, CQueue<TaggedObject *> *queue,
161                                     std::unordered_map<uint64_t, ObjectEncode> *data);
162     uint64_t SerializeTaggedField(JSTaggedType *tagged, CQueue<TaggedObject *> *queue,
163                                   std::unordered_map<uint64_t, ObjectEncode> *data);
164     void DeserializeField(TaggedObject *objectHeader);
165     void DeserializeTaggedField(uint64_t *value, TaggedObject *root);
166     void DeserializeNativePointer(uint64_t *value);
167     void DeserializeClassWord(TaggedObject *object);
168     void DeserializePandaMethod(uintptr_t begin, uintptr_t end, MethodLiteral *methods,
169                                 size_t &methodNums, size_t &others);
170     void DeserializeSpaceObject(uintptr_t beginAddr, size_t objSize, SerializedObjectSpace spaceType);
171     void DeserializeSpaceObject(uintptr_t beginAddr, Space* space, size_t spaceObjSize);
172     void DeserializeHugeSpaceObject(uintptr_t beginAddr, HugeObjectSpace* space, size_t hugeSpaceObjSize);
173     void HandleRootObject(SnapshotType type, uintptr_t rootObjectAddr, size_t objType, size_t &constSpecialIndex);
174 
175     EncodeBit NativePointerToEncodeBit(void *nativePointer);
176     size_t SearchNativeMethodIndex(void *nativePointer);
177     uintptr_t TaggedObjectEncodeBitToAddr(EncodeBit taggedBit);
178     void WriteSpaceObjectToFile(Space* space, std::fstream &write);
179     void WriteHugeObjectToFile(HugeObjectSpace* space, std::fstream &writer);
180     size_t StatisticsSpaceObjectSize(Space* space);
181     size_t StatisticsHugeObjectSize(HugeObjectSpace* space);
182     uintptr_t AllocateObjectToLocalSpace(Space *space, size_t objectSize);
183     SnapshotRegionHeadInfo GenerateRegionHeadInfo(Region *region);
184     void ResetRegionUnusedRange(Region *region);
185 
186     EcmaVM *vm_ {nullptr};
187     SharedHeap* sHeap_ {nullptr};
188     class RegionProxy {
189     public:
190         RegionProxy() = default;
191         ~RegionProxy() = default;
192 
IsEmpty()193         bool IsEmpty() const
194         {
195             return begin_ == 0;
196         }
197 
Allocate(size_t size)198         AllocResult Allocate(size_t size)
199         {
200             if (top_ + size <= end_) {
201                 uintptr_t addr = top_;
202                 top_ += size;
203                 return {addr, addr - begin_, regionIndex_};
204             }
205             return {0, 0, -1};
206         }
207 
Reset(uintptr_t begin,uintptr_t end,size_t regionIndex)208         void Reset(uintptr_t begin, uintptr_t end, size_t regionIndex)
209         {
210             begin_ = begin;
211             top_ = begin;
212             end_ = end;
213             regionIndex_ = regionIndex;
214         }
215 
GetBegin()216         uintptr_t GetBegin() const
217         {
218             return begin_;
219         }
220 
GetTop()221         uintptr_t GetTop() const
222         {
223             return top_;
224         }
225 
GetEnd()226         uintptr_t GetEnd() const
227         {
228             return end_;
229         }
230 
GetRegionIndex()231         size_t GetRegionIndex() const
232         {
233             return regionIndex_;
234         }
235     private:
236         uintptr_t begin_ {0};
237         uintptr_t top_ {0};
238         uintptr_t end_ {0};
239         size_t regionIndex_ {-1};
240     };
241 
242     class AllocateProxy {
243     public:
AllocateProxy(SerializedObjectSpace spaceType)244         AllocateProxy(SerializedObjectSpace spaceType) : spaceType_(spaceType) {}
~AllocateProxy()245         ~AllocateProxy()
246         {
247             for (RegionProxy &proxy : regions_) {
248                 ASSERT(!proxy.IsEmpty());
249                 void *ptr = reinterpret_cast<void*>(proxy.GetBegin());
250                 free(ptr);
251             }
252         }
253 
254         void Initialize(size_t commonRegionSize);
255 
256         AllocResult Allocate(size_t size, uintptr_t &regionIndex);
257 
258         void StopAllocate(SharedHeap *sHeap);
259 
GetAllocatedSize()260         size_t GetAllocatedSize() const
261         {
262             return allocatedSize_;
263         }
264 
265         void WriteToFile(std::fstream &writer);
266     private:
267         void AllocateNewRegion(size_t size, uintptr_t &regionIndex);
268         std::vector<RegionProxy> regions_ {};
269         RegionProxy currentRegion_ {};
270         SerializedObjectSpace spaceType_ {SerializedObjectSpace::OTHER};
271         size_t allocatedSize_ {0};
272         size_t commonRegionSize_ {0};
273     };
274     AllocateProxy regularObjAllocator_ {SerializedObjectSpace::REGULAR_SPACE};
275     AllocateProxy pinnedObjAllocator_ {SerializedObjectSpace::PIN_SPACE};
276     AllocateProxy largeObjAllocator_ {SerializedObjectSpace::LARGE_SPACE};
277     size_t commonRegionSize_ {0};
278     LocalSpace *oldLocalSpace_ {nullptr};
279     LocalSpace *nonMovableLocalSpace_ {nullptr};
280     LocalSpace *machineCodeLocalSpace_ {nullptr};
281     SnapshotSpace *snapshotLocalSpace_ {nullptr};
282     HugeObjectSpace *hugeObjectLocalSpace_ {nullptr};
283     bool programSerialize_ {false};
284     bool builtinsSerialize_ {false};
285     bool builtinsDeserialize_ {false};
286     CVector<uintptr_t> pandaMethod_;
287     CVector<uintptr_t> stringVector_;
288     /**
289      * In deserialize, RuntimeLock for string table may cause a SharedGC, making strings just created invalid,
290      * so use handle to protect.
291     */
292     CVector<JSHandle<EcmaString>> deserializeStringVector_;
293     std::unordered_map<size_t, uintptr_t> regionIndexMap_;
294     size_t regionIndex_ {0};
295     bool isRootObjRelocate_ {false};
296     JSTaggedValue root_ {JSTaggedValue::Hole()};
297     std::vector<std::pair<uintptr_t, size_t>> regularRegions_ {};
298     std::vector<std::pair<uintptr_t, size_t>> pinnedRegions_ {};
299     std::vector<std::pair<uintptr_t, size_t>> largeRegions_ {};
300 
301     NO_COPY_SEMANTIC(SnapshotProcessor);
302     NO_MOVE_SEMANTIC(SnapshotProcessor);
303 };
304 
305 class SnapshotHelper {
306 public:
307     // when snapshot serialize, huge obj size is writed to region snapshotData_ high 32 bits
EncodeHugeObjectSize(uint64_t objSize)308     static inline uint64_t EncodeHugeObjectSize(uint64_t objSize)
309     {
310         return objSize << Constants::UINT_32_BITS_COUNT;
311     }
312 
313     // get huge object size which is saved in region snapshotData_ high 32 bits
GetHugeObjectSize(uint64_t snapshotData)314     static inline size_t GetHugeObjectSize(uint64_t snapshotData)
315     {
316         return snapshotData >> Constants::UINT_32_BITS_COUNT;
317     }
318 
319     // get huge object region index which is saved in region snapshotMark_ low 32 bits
GetHugeObjectRegionIndex(uint64_t snapshotData)320     static inline size_t GetHugeObjectRegionIndex(uint64_t snapshotData)
321     {
322         return snapshotData & Constants::MAX_UINT_32;
323     }
324 };
325 }  // namespace panda::ecmascript
326 
327 #endif  // ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H
328