1 /*
2 * Copyright (c) 2022 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 #include "ecmascript/snapshot/mem/snapshot.h"
17
18 #include <cerrno>
19
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/jobs/micro_job_queue.h"
23 #include "ecmascript/jspandafile/program_object.h"
24 #include "ecmascript/js_hclass.h"
25 #include "ecmascript/js_thread.h"
26 #include "ecmascript/aot_file_manager.h"
27 #include "ecmascript/jspandafile/js_pandafile_manager.h"
28 #include "ecmascript/mem/c_containers.h"
29 #include "ecmascript/mem/heap.h"
30 #include "ecmascript/object_factory.h"
31 #include "ecmascript/platform/file.h"
32 #include "ecmascript/snapshot/mem/snapshot_env.h"
33 #include "ecmascript/ts_types/ts_manager.h"
34
35 namespace panda::ecmascript {
Serialize(const CString & fileName)36 void Snapshot::Serialize(const CString &fileName)
37 {
38 TSManager *tsManager = vm_->GetTSManager();
39 JSTaggedValue root = tsManager->GetSnapshotCPList();
40 Serialize(root.GetTaggedObject(), nullptr, fileName);
41 }
42
Serialize(TaggedObject * objectHeader,const panda_file::File * pf,const CString & fileName)43 void Snapshot::Serialize(TaggedObject *objectHeader, const panda_file::File *pf, const CString &fileName)
44 {
45 std::string realPath;
46 if (!RealPath(std::string(fileName), realPath, false)) {
47 LOG_FULL(FATAL) << "snapshot file path error";
48 }
49 std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
50 if (!writer.good()) {
51 writer.close();
52 LOG_FULL(FATAL) << "snapshot open file failed";
53 }
54
55 SnapshotProcessor processor(vm_);
56 processor.Initialize();
57
58 std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data;
59 CQueue<TaggedObject *> objectQueue;
60
61 if (objectHeader->GetClass()->GetObjectType() == JSType::PROGRAM) {
62 processor.SetProgramSerializeStart();
63 }
64
65 processor.EncodeTaggedObject(objectHeader, &objectQueue, &data);
66 size_t rootObjSize = objectQueue.size();
67 processor.ProcessObjectQueue(&objectQueue, &data);
68 WriteToFile(writer, pf, rootObjSize, processor);
69 }
70
Serialize(uintptr_t startAddr,size_t size,const CString & fileName)71 void Snapshot::Serialize(uintptr_t startAddr, size_t size, const CString &fileName)
72 {
73 std::string realPath;
74 if (!RealPath(std::string(fileName), realPath, false)) {
75 LOG_FULL(FATAL) << "snapshot file path error";
76 }
77 std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
78 if (!writer.good()) {
79 writer.close();
80 LOG_FULL(FATAL) << "snapshot open file failed";
81 }
82
83 SnapshotProcessor processor(vm_);
84 processor.Initialize();
85
86 std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data;
87 CQueue<TaggedObject *> objectQueue;
88
89 ObjectSlot start(startAddr);
90 ObjectSlot end(startAddr + size * sizeof(JSTaggedType));
91 processor.EncodeTaggedObjectRange(start, end, &objectQueue, &data);
92
93 size_t rootObjSize = objectQueue.size();
94 processor.ProcessObjectQueue(&objectQueue, &data);
95 WriteToFile(writer, nullptr, rootObjSize, processor);
96 }
97
SerializeBuiltins(const CString & fileName)98 void Snapshot::SerializeBuiltins(const CString &fileName)
99 {
100 std::string realPath;
101 if (!RealPath(std::string(fileName), realPath, false)) {
102 LOG_FULL(FATAL) << "snapshot file path error";
103 }
104 std::fstream write(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::app);
105 if (!write.good()) {
106 write.close();
107 LOG_FULL(FATAL) << "snapshot open file failed";
108 }
109 // if builtins.snapshot file has exist, return directly
110 if (write.tellg()) {
111 LOG_FULL(DEBUG) << "snapshot already exist";
112 write.close();
113 return;
114 }
115
116 SnapshotProcessor processor(vm_);
117 processor.Initialize();
118 processor.SetBuiltinsSerializeStart();
119
120 std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data;
121 CQueue<TaggedObject *> objectQueue;
122
123 auto globalEnvHandle = vm_->GetGlobalEnv();
124 auto constant = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants());
125 constant->VisitRangeSlot([&objectQueue, &data, &processor]([[maybe_unused]]Root type,
126 ObjectSlot start, ObjectSlot end) {
127 processor.EncodeTaggedObjectRange(start, end, &objectQueue, &data);
128 });
129 processor.EncodeTaggedObject(*globalEnvHandle, &objectQueue, &data);
130 size_t rootObjSize = objectQueue.size();
131 processor.ProcessObjectQueue(&objectQueue, &data);
132 WriteToFile(write, nullptr, rootObjSize, processor);
133 }
134
Deserialize(SnapshotType type,const CString & snapshotFile,bool isBuiltins)135 const JSPandaFile *Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, bool isBuiltins)
136 {
137 std::string realPath;
138 if (!RealPath(std::string(snapshotFile), realPath, false)) {
139 LOG_FULL(FATAL) << "snapshot file path error";
140 UNREACHABLE();
141 }
142
143 SnapshotProcessor processor(vm_, snapshotFile);
144 if (isBuiltins) {
145 processor.SetBuiltinsDeserializeStart();
146 }
147
148 MemMap fileMap = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READWRITE);
149 if (fileMap.GetOriginAddr() == nullptr) {
150 LOG_FULL(FATAL) << "file mmap failed";
151 UNREACHABLE();
152 }
153 auto readFile = ToUintPtr(fileMap.GetOriginAddr());
154 auto hdr = *ToNativePtr<const SnapShotHeader>(readFile);
155 if (!hdr.Verify()) {
156 FileUnMap(fileMap);
157 LOG_FULL(FATAL) << "file verify failed";
158 UNREACHABLE();
159 }
160 uintptr_t oldSpaceBegin = readFile + sizeof(SnapShotHeader);
161 processor.DeserializeObjectExcludeString(oldSpaceBegin, hdr.oldSpaceObjSize, hdr.nonMovableObjSize,
162 hdr.machineCodeObjSize, hdr.snapshotObjSize, hdr.hugeObjSize);
163 uintptr_t stringBegin = oldSpaceBegin + hdr.oldSpaceObjSize + hdr.nonMovableObjSize +
164 hdr.machineCodeObjSize + hdr.snapshotObjSize + hdr.hugeObjSize;
165 uintptr_t stringEnd = stringBegin + hdr.stringSize;
166 processor.DeserializeString(stringBegin, stringEnd);
167
168 FileUnMap(MemMap(fileMap.GetOriginAddr(), hdr.pandaFileBegin));
169 const JSPandaFile *jsPandaFile = nullptr;
170 if (static_cast<uint32_t>(fileMap.GetSize()) > hdr.pandaFileBegin) {
171 uintptr_t panda_file_mem = readFile + hdr.pandaFileBegin;
172 auto pf = panda_file::File::OpenFromMemory(os::mem::ConstBytePtr(ToNativePtr<std::byte>(panda_file_mem),
173 static_cast<uint32_t>(fileMap.GetSize()) - hdr.pandaFileBegin, os::mem::MmapDeleter));
174 jsPandaFile = JSPandaFileManager::GetInstance()->NewJSPandaFile(pf.release(), "");
175 }
176 // relocate object field
177 processor.Relocate(type, jsPandaFile, hdr.rootObjectSize);
178 LOG_COMPILER(INFO) << "loaded ai file: " << snapshotFile.c_str();
179 return jsPandaFile;
180 }
181
AlignUpPageSize(size_t spaceSize)182 size_t Snapshot::AlignUpPageSize(size_t spaceSize)
183 {
184 if (spaceSize % Constants::PAGE_SIZE_ALIGN_UP == 0) {
185 return spaceSize;
186 }
187 return Constants::PAGE_SIZE_ALIGN_UP * (spaceSize / Constants::PAGE_SIZE_ALIGN_UP + 1);
188 }
189
WriteToFile(std::fstream & writer,const panda_file::File * pf,size_t size,SnapshotProcessor & processor)190 void Snapshot::WriteToFile(std::fstream &writer, const panda_file::File *pf, size_t size, SnapshotProcessor &processor)
191 {
192 uint32_t totalStringSize = 0U;
193 CVector<uintptr_t> stringVector = processor.GetStringVector();
194 for (size_t i = 0; i < stringVector.size(); ++i) {
195 auto str = reinterpret_cast<EcmaString *>(stringVector[i]);
196 size_t objectSize = AlignUp(EcmaStringAccessor(str).ObjectSize(),
197 static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
198 totalStringSize += objectSize;
199 }
200
201 std::vector<uint32_t> objSizeVector = processor.StatisticsObjectSize();
202 size_t totalObjSize = totalStringSize;
203 for (uint32_t objSize : objSizeVector) {
204 totalObjSize += objSize;
205 }
206 uint32_t pandaFileBegin = RoundUp(totalObjSize + sizeof(SnapShotHeader), Constants::PAGE_SIZE_ALIGN_UP);
207 SnapShotHeader hdr;
208 hdr.oldSpaceObjSize = objSizeVector[0]; // 0:oldSpaceObj
209 hdr.nonMovableObjSize = objSizeVector[1]; // 1:nonMovableObj
210 hdr.machineCodeObjSize = objSizeVector[2]; // 2:machineCodeObj
211 hdr.snapshotObjSize = objSizeVector[3]; // 3:snapshotObj
212 hdr.hugeObjSize = objSizeVector[4]; // 4:hugeObj
213 hdr.stringSize = totalStringSize;
214 hdr.pandaFileBegin = pandaFileBegin;
215 hdr.rootObjectSize = static_cast<uint32_t>(size);
216 writer.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
217
218 processor.WriteObjectToFile(writer);
219
220 for (size_t i = 0; i < stringVector.size(); ++i) {
221 auto str = reinterpret_cast<EcmaString *>(stringVector[i]);
222 size_t strSize = AlignUp(EcmaStringAccessor(str).ObjectSize(),
223 static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
224 writer.write(reinterpret_cast<char *>(str), strSize);
225 writer.flush();
226 }
227 ASSERT(static_cast<size_t>(writer.tellp()) == totalObjSize + sizeof(SnapShotHeader));
228 if (pf) {
229 writer.seekp(pandaFileBegin);
230 writer.write(reinterpret_cast<const char *>(pf->GetBase()), pf->GetHeader()->file_size);
231 }
232 writer.close();
233 }
234 } // namespace panda::ecmascript
235