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
30namespace panda::ecmascript {
31class EcmaVM;
32class JSPandaFile;
33class AOTFileManager;
34
35enum class SnapshotType {
36    VM_ROOT,
37    BUILTINS,
38    AI
39};
40
41struct SnapshotRegionHeadInfo {
42    uint32_t regionIndex_ {0};
43    uint32_t aliveObjectSize_ {0};
44
45    static constexpr size_t RegionHeadInfoSize()
46    {
47        return sizeof(SnapshotRegionHeadInfo);
48    }
49};
50
51using ObjectEncode = std::pair<uint64_t, ecmascript::EncodeBit>;
52
53class SnapshotProcessor final {
54public:
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
84    void SetProgramSerializeStart()
85    {
86        programSerialize_ = true;
87    }
88
89    void SetBuiltinsSerializeStart()
90    {
91        builtinsSerialize_ = true;
92    }
93
94    void SetBuiltinsDeserializeStart()
95    {
96        builtinsDeserialize_ = true;
97    }
98
99    const CVector<uintptr_t> GetStringVector() const
100    {
101        return stringVector_;
102    }
103
104    LocalSpace* GetOldLocalSpace() const
105    {
106        return oldLocalSpace_;
107    }
108
109    size_t GetNativeTableSize() const;
110
111private:
112    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
172class SnapshotHelper {
173public:
174    // when snapshot serialize, huge obj size is writed to region snapshotData_ high 32 bits
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
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
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