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 "ecmascript/snapshot/mem/encode_bit.h"
24 #include "ecmascript/jspandafile/method_literal.h"
25 #include "ecmascript/js_tagged_value.h"
26 #include "ecmascript/mem/object_xray.h"
27 
28 #include "libpandabase/macros.h"
29 
30 namespace panda::ecmascript {
31 class EcmaVM;
32 class JSPandaFile;
33 class AOTFileManager;
34 
35 enum class SnapshotType {
36     VM_ROOT,
37     BUILTINS,
38     AI
39 };
40 
41 struct SnapshotRegionHeadInfo {
42     uint32_t regionIndex_ {0};
43     uint32_t aliveObjectSize_ {0};
44 
RegionHeadInfoSizepanda::ecmascript::SnapshotRegionHeadInfo45     static constexpr size_t RegionHeadInfoSize()
46     {
47         return sizeof(SnapshotRegionHeadInfo);
48     }
49 };
50 
51 using ObjectEncode = std::pair<uint64_t, ecmascript::EncodeBit>;
52 
53 class SnapshotProcessor final {
54 public:
SnapshotProcessor(EcmaVM *vm)55     explicit SnapshotProcessor(EcmaVM *vm)
56         : vm_(vm), sHeap_(SharedHeap::GetInstance()) {}
57     ~SnapshotProcessor();
58 
59     void Initialize();
60     void StopAllocate();
61     void WriteObjectToFile(std::fstream &write);
62     std::vector<uint32_t> StatisticsObjectSize();
63     void ProcessObjectQueue(CQueue<TaggedObject *> *queue, std::unordered_map<uint64_t, ObjectEncode> *data);
64     void SerializeObject(TaggedObject *objectHeader, CQueue<TaggedObject *> *queue,
65                          std::unordered_map<uint64_t, ObjectEncode> *data);
66     void Relocate(SnapshotType type, const JSPandaFile *jsPandaFile,
67                   uint64_t rootObjSize);
68     void RelocateSpaceObject(const JSPandaFile *jsPandaFile, Space* space, SnapshotType type, MethodLiteral* methods,
69                              size_t methodNums, size_t rootObjSize);
70     void SerializePandaFileMethod();
71     uintptr_t GetNewObj(size_t objectSize, TaggedObject *objectHeader);
72     EncodeBit EncodeTaggedObject(TaggedObject *objectHeader, CQueue<TaggedObject *> *queue,
73                                  std::unordered_map<uint64_t, ObjectEncode> *data);
74     EncodeBit GetObjectEncode(JSTaggedValue object, CQueue<TaggedObject *> *queue,
75                               std::unordered_map<uint64_t, ObjectEncode> *data);
76     void EncodeTaggedObjectRange(ObjectSlot start, ObjectSlot end, CQueue<TaggedObject *> *queue,
77                                  std::unordered_map<uint64_t, ObjectEncode> *data);
78     void DeserializeObjectExcludeString(uintptr_t oldSpaceBegin, size_t oldSpaceObjSize, size_t nonMovableObjSize,
79                                         size_t machineCodeObjSize, size_t snapshotObjSize, size_t hugeSpaceObjSize);
80     void DeserializeString(uintptr_t stringBegin, uintptr_t stringEnd);
81 
82     void AddRootObjectToAOTFileManager(SnapshotType type, const CString &fileName);
83 
SetProgramSerializeStart()84     void SetProgramSerializeStart()
85     {
86         programSerialize_ = true;
87     }
88 
SetBuiltinsSerializeStart()89     void SetBuiltinsSerializeStart()
90     {
91         builtinsSerialize_ = true;
92     }
93 
SetBuiltinsDeserializeStart()94     void SetBuiltinsDeserializeStart()
95     {
96         builtinsDeserialize_ = true;
97     }
98 
GetStringVector() const99     const CVector<uintptr_t> GetStringVector() const
100     {
101         return stringVector_;
102     }
103 
GetOldLocalSpace() const104     LocalSpace* GetOldLocalSpace() const
105     {
106         return oldLocalSpace_;
107     }
108 
109     size_t GetNativeTableSize() const;
110 
111 private:
GetMarkGCBitSetSize() const112     size_t GetMarkGCBitSetSize() const
113     {
114         return GCBitset::SizeOfGCBitset(DEFAULT_REGION_SIZE -
115             AlignUp(sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION)));
116     }
117 
118     bool VisitObjectBodyWithRep(TaggedObject *root, ObjectSlot slot, uintptr_t obj, int index, VisitObjectArea area);
119     void SetObjectEncodeField(uintptr_t obj, size_t offset, uint64_t value);
120 
121     EncodeBit SerializeObjectHeader(TaggedObject *objectHeader, size_t objectType, CQueue<TaggedObject *> *queue,
122                                     std::unordered_map<uint64_t, ObjectEncode> *data);
123     uint64_t SerializeTaggedField(JSTaggedType *tagged, CQueue<TaggedObject *> *queue,
124                                   std::unordered_map<uint64_t, ObjectEncode> *data);
125     void DeserializeField(TaggedObject *objectHeader);
126     void DeserializeTaggedField(uint64_t *value, TaggedObject *root);
127     void DeserializeNativePointer(uint64_t *value);
128     void DeserializeClassWord(TaggedObject *object);
129     void DeserializePandaMethod(uintptr_t begin, uintptr_t end, MethodLiteral *methods,
130                                 size_t &methodNums, size_t &others);
131     void DeserializeSpaceObject(uintptr_t beginAddr, Space* space, size_t spaceObjSize);
132     void DeserializeHugeSpaceObject(uintptr_t beginAddr, HugeObjectSpace* space, size_t hugeSpaceObjSize);
133     void HandleRootObject(SnapshotType type, uintptr_t rootObjectAddr, size_t objType, size_t &constSpecialIndex);
134 
135     EncodeBit NativePointerToEncodeBit(void *nativePointer);
136     size_t SearchNativeMethodIndex(void *nativePointer);
137     uintptr_t TaggedObjectEncodeBitToAddr(EncodeBit taggedBit);
138     void WriteSpaceObjectToFile(Space* space, std::fstream &write);
139     void WriteHugeObjectToFile(HugeObjectSpace* space, std::fstream &writer);
140     uint32_t StatisticsSpaceObjectSize(Space* space);
141     uint32_t StatisticsHugeObjectSize(HugeObjectSpace* space);
142     uintptr_t AllocateObjectToLocalSpace(Space *space, size_t objectSize);
143     SnapshotRegionHeadInfo GenerateRegionHeadInfo(Region *region);
144     void ResetRegionUnusedRange(Region *region);
145 
146     EcmaVM *vm_ {nullptr};
147     SharedHeap* sHeap_ {nullptr};
148     LocalSpace *oldLocalSpace_ {nullptr};
149     LocalSpace *nonMovableLocalSpace_ {nullptr};
150     LocalSpace *machineCodeLocalSpace_ {nullptr};
151     SnapshotSpace *snapshotLocalSpace_ {nullptr};
152     HugeObjectSpace *hugeObjectLocalSpace_ {nullptr};
153     bool programSerialize_ {false};
154     bool builtinsSerialize_ {false};
155     bool builtinsDeserialize_ {false};
156     CVector<uintptr_t> pandaMethod_;
157     CVector<uintptr_t> stringVector_;
158     /**
159      * In deserialize, RuntimeLock for string table may cause a SharedGC, making strings just created invalid,
160      * so use handle to protect.
161     */
162     CVector<JSHandle<EcmaString>> deserializeStringVector_;
163     std::unordered_map<size_t, Region *> regionIndexMap_;
164     size_t regionIndex_ {0};
165     bool isRootObjRelocate_ {false};
166     JSTaggedValue root_ {JSTaggedValue::Hole()};
167 
168     NO_COPY_SEMANTIC(SnapshotProcessor);
169     NO_MOVE_SEMANTIC(SnapshotProcessor);
170 };
171 
172 class SnapshotHelper {
173 public:
174     // when snapshot serialize, huge obj size is writed to region snapshotData_ high 32 bits
EncodeHugeObjectSize(uint64_t objSize)175     static inline uint64_t EncodeHugeObjectSize(uint64_t objSize)
176     {
177         return objSize << Constants::UINT_32_BITS_COUNT;
178     }
179 
180     // get huge object size which is saved in region snapshotData_ high 32 bits
GetHugeObjectSize(uint64_t snapshotData)181     static inline size_t GetHugeObjectSize(uint64_t snapshotData)
182     {
183         return snapshotData >> Constants::UINT_32_BITS_COUNT;
184     }
185 
186     // get huge object region index which is saved in region snapshotMark_ low 32 bits
GetHugeObjectRegionIndex(uint64_t snapshotData)187     static inline size_t GetHugeObjectRegionIndex(uint64_t snapshotData)
188     {
189         return snapshotData & Constants::MAX_UINT_32;
190     }
191 };
192 }  // namespace panda::ecmascript
193 
194 #endif  // ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H
195