• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/compiler/pgo_type/pgo_type_manager.h"
21 
22 namespace panda::ecmascript {
Serialize(const CString & fileName)23 void Snapshot::Serialize(const CString &fileName)
24 {
25     kungfu::AOTSnapshot &aotSnapshot = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager()->GetAOTSnapshot();
26     JSTaggedValue root = aotSnapshot.GetSnapshotData();
27     if (root == JSTaggedValue::Hole()) {
28         // root equals hole means no data stored.
29         LOG_COMPILER(ERROR) << "error: no data for ai file generation!";
30         return;
31     }
32     Serialize(root.GetTaggedObject(), nullptr, fileName);
33 }
34 
Serialize(TaggedObject * objectHeader,const JSPandaFile * jsPandaFile,const CString & fileName)35 void Snapshot::Serialize(TaggedObject *objectHeader, const JSPandaFile *jsPandaFile, const CString &fileName)
36 {
37     std::string realPath;
38     if (!RealPath(std::string(fileName), realPath, false)) {
39         LOG_FULL(FATAL) << "snapshot file path error";
40     }
41     std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
42     if (!writer.good()) {
43         writer.close();
44         LOG_FULL(ERROR) << "snapshot open file failed";
45         return;
46     }
47 
48     SnapshotProcessor processor(vm_);
49     processor.Initialize();
50 
51     std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data;
52     CQueue<TaggedObject *> objectQueue;
53 
54     if (objectHeader->GetClass()->GetObjectType() == JSType::PROGRAM) {
55         processor.SetProgramSerializeStart();
56     }
57 
58     processor.EncodeTaggedObject(objectHeader, &objectQueue, &data);
59     size_t rootObjSize = objectQueue.size();
60     processor.ProcessObjectQueue(&objectQueue, &data);
61     WriteToFile(writer, jsPandaFile, rootObjSize, processor);
62 }
63 
Serialize(uintptr_t startAddr,size_t size,const CString & fileName)64 void Snapshot::Serialize(uintptr_t startAddr, size_t size, const CString &fileName)
65 {
66     std::string realPath;
67     if (!RealPath(std::string(fileName), realPath, false)) {
68         LOG_FULL(FATAL) << "snapshot file path error";
69     }
70     std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
71     if (!writer.good()) {
72         writer.close();
73         LOG_FULL(ERROR) << "snapshot open file failed";
74         return;
75     }
76 
77     SnapshotProcessor processor(vm_);
78     processor.Initialize();
79 
80     std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data;
81     CQueue<TaggedObject *> objectQueue;
82 
83     ObjectSlot start(startAddr);
84     ObjectSlot end(startAddr + size * sizeof(JSTaggedType));
85     processor.EncodeTaggedObjectRange(start, end, &objectQueue, &data);
86 
87     size_t rootObjSize = objectQueue.size();
88     processor.ProcessObjectQueue(&objectQueue, &data);
89     WriteToFile(writer, nullptr, rootObjSize, processor);
90 }
91 
SerializeBuiltins(const CString & fileName)92 void Snapshot::SerializeBuiltins(const CString &fileName)
93 {
94     std::string realPath;
95     if (!RealPath(std::string(fileName), realPath, false)) {
96         LOG_FULL(FATAL) << "snapshot file path error";
97     }
98     std::fstream write(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::app);
99     if (!write.good()) {
100         write.close();
101         LOG_FULL(ERROR) << "snapshot open file failed";
102         return;
103     }
104     // if builtins.snapshot file has exist, return directly
105     if (write.tellg()) {
106         LOG_FULL(DEBUG) << "snapshot already exist";
107         write.close();
108         return;
109     }
110 
111     SnapshotProcessor processor(vm_);
112     processor.Initialize();
113     processor.SetBuiltinsSerializeStart();
114 
115     std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data;
116     CQueue<TaggedObject *> objectQueue;
117 
118     auto globalEnvHandle = vm_->GetGlobalEnv();
119     auto constant = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants());
120     constant->VisitRangeSlot([&objectQueue, &data, &processor]([[maybe_unused]] Root type,
121                                                                ObjectSlot start, ObjectSlot end) {
122         processor.EncodeTaggedObjectRange(start, end, &objectQueue, &data);
123     });
124     processor.EncodeTaggedObject(*globalEnvHandle, &objectQueue, &data);
125     size_t rootObjSize = objectQueue.size();
126     processor.ProcessObjectQueue(&objectQueue, &data);
127     WriteToFile(write, nullptr, rootObjSize, processor);
128 }
129 
DeserializeInternal(SnapshotType type,const CString & snapshotFile,SnapshotProcessor & processor,MemMap & fileMap)130 bool Snapshot::DeserializeInternal(SnapshotType type, const CString &snapshotFile, SnapshotProcessor &processor,
131                                    MemMap &fileMap)
132 {
133     if (fileMap.GetOriginAddr() == nullptr) {
134         LOG_FULL(FATAL) << "file mmap failed";
135         UNREACHABLE();
136     }
137     auto readFile = ToUintPtr(fileMap.GetOriginAddr());
138     auto hdr = *ToNativePtr<const SnapShotHeader>(readFile);
139     if (!hdr.Verify(GetLastVersion())) {
140         FileUnMap(fileMap);
141         LOG_ECMA(ERROR) << "file verify failed.";
142         return false;
143     }
144     uintptr_t oldSpaceBegin = readFile + sizeof(SnapShotHeader);
145     uintptr_t stringBegin = oldSpaceBegin + hdr.oldSpaceObjSize + hdr.nonMovableObjSize +
146         hdr.machineCodeObjSize + hdr.snapshotObjSize + hdr.hugeObjSize;
147     uintptr_t stringEnd = stringBegin + hdr.stringSize;
148     [[maybe_unused]] EcmaHandleScope stringHandleScope(vm_->GetJSThread());
149     processor.DeserializeString(stringBegin, stringEnd);
150 
151     processor.DeserializeObjectExcludeString(oldSpaceBegin, hdr.oldSpaceObjSize, hdr.nonMovableObjSize,
152                                              hdr.machineCodeObjSize, hdr.snapshotObjSize, hdr.hugeObjSize);
153 
154 #if !defined(CROSS_PLATFORM)
155     FileUnMap(MemMap(fileMap.GetOriginAddr(), hdr.pandaFileBegin));
156 #endif
157     std::shared_ptr<JSPandaFile> jsPandaFile;
158     if (static_cast<uint32_t>(fileMap.GetSize()) > hdr.pandaFileBegin) {
159         uintptr_t pandaFileMem = readFile + hdr.pandaFileBegin;
160         auto pf = panda_file::File::OpenFromMemory(os::mem::ConstBytePtr(ToNativePtr<std::byte>(pandaFileMem),
161             static_cast<uint32_t>(fileMap.GetSize()) - hdr.pandaFileBegin, os::mem::MmapDeleter));
162         jsPandaFile = JSPandaFileManager::GetInstance()->NewJSPandaFile(pf.release(), "");
163     }
164     // relocate object field
165     processor.Relocate(type, jsPandaFile.get(), hdr.rootObjectSize);
166     processor.AddRootObjectToAOTFileManager(type, snapshotFile);
167     LOG_COMPILER(INFO) << "loaded ai file: " << snapshotFile.c_str();
168     return true;
169 }
170 
Deserialize(SnapshotType type,const CString & snapshotFile,bool isBuiltins)171 bool Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, bool isBuiltins)
172 {
173     std::string realPath;
174     if (!RealPath(std::string(snapshotFile), realPath, false)) {
175         LOG_FULL(FATAL) << "snapshot file path error";
176         UNREACHABLE();
177     }
178 
179     if (!FileExist(realPath.c_str())) {
180         return false;
181     }
182 
183     SnapshotProcessor processor(vm_);
184     if (isBuiltins) {
185         processor.SetBuiltinsDeserializeStart();
186     }
187 
188     MemMap fileMap = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READWRITE);
189     return DeserializeInternal(type, snapshotFile, processor, fileMap);
190 }
191 
192 #if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM)
Deserialize(SnapshotType type,const CString & snapshotFile,std::function<bool (std::string fileName,uint8_t ** buff,size_t * buffSize)> ReadAOTCallBack,bool isBuiltins)193 bool Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, [[maybe_unused]] std::function<bool
194     (std::string fileName, uint8_t **buff, size_t *buffSize)> ReadAOTCallBack, bool isBuiltins)
195 {
196     SnapshotProcessor processor(vm_);
197     if (isBuiltins) {
198         processor.SetBuiltinsDeserializeStart();
199     }
200 
201     std::string fileName = std::string(snapshotFile);
202     uint8_t *buff = nullptr;
203     size_t buffSize = 0;
204     MemMap fileMap = {};
205     size_t found = fileName.find_last_of("/");
206     if (found != std::string::npos) {
207         fileName = fileName.substr(found + 1);
208     }
209 
210     LOG_ECMA(INFO) << "Call JsAotReader to load: " << fileName;
211     if (ReadAOTCallBack(fileName, &buff, &buffSize)) {
212         fileMap = MemMap(buff, buffSize);
213     }
214 
215     return DeserializeInternal(type, snapshotFile, processor, fileMap);
216 }
217 #endif
218 
AlignUpPageSize(size_t spaceSize)219 size_t Snapshot::AlignUpPageSize(size_t spaceSize)
220 {
221     if (spaceSize % Constants::PAGE_SIZE_ALIGN_UP == 0) {
222         return spaceSize;
223     }
224     return Constants::PAGE_SIZE_ALIGN_UP * (spaceSize / Constants::PAGE_SIZE_ALIGN_UP + 1);
225 }
226 
WriteToFile(std::fstream & writer,const JSPandaFile * jsPandaFile,size_t size,SnapshotProcessor & processor)227 void Snapshot::WriteToFile(std::fstream &writer, const JSPandaFile *jsPandaFile,
228                            size_t size, SnapshotProcessor &processor)
229 {
230     uint32_t totalStringSize = 0U;
231     CVector<uintptr_t> stringVector = processor.GetStringVector();
232     for (size_t i = 0; i < stringVector.size(); ++i) {
233         auto str = reinterpret_cast<EcmaString *>(stringVector[i]);
234         size_t objectSize = AlignUp(EcmaStringAccessor(str).ObjectSize(),
235             static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
236         totalStringSize += objectSize;
237     }
238 
239     std::vector<uint32_t> objSizeVector = processor.StatisticsObjectSize();
240     size_t totalObjSize = totalStringSize;
241     for (uint32_t objSize : objSizeVector) {
242         totalObjSize += objSize;
243     }
244     uint32_t pandaFileBegin = RoundUp(totalObjSize + sizeof(SnapShotHeader), Constants::PAGE_SIZE_ALIGN_UP);
245     SnapShotHeader hdr(GetLastVersion());
246     hdr.oldSpaceObjSize = objSizeVector[0]; // 0: oldSpaceObj
247     hdr.nonMovableObjSize = objSizeVector[1]; // 1: nonMovableObj
248     hdr.machineCodeObjSize = objSizeVector[2]; // 2: machineCodeObj
249     hdr.snapshotObjSize = objSizeVector[3]; // 3: snapshotObj
250     hdr.hugeObjSize = objSizeVector[4]; // 4: hugeObj
251     hdr.stringSize = totalStringSize;
252     hdr.pandaFileBegin = pandaFileBegin;
253     hdr.rootObjectSize = static_cast<uint32_t>(size);
254     writer.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
255     processor.WriteObjectToFile(writer);
256 
257     for (size_t i = 0; i < stringVector.size(); ++i) {
258         auto str = reinterpret_cast<EcmaString *>(stringVector[i]);
259         size_t strSize = AlignUp(EcmaStringAccessor(str).ObjectSize(),
260             static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
261         int index = 0; // 0 represents the line string. Natural number 1 represents the constant string.
262         if (EcmaStringAccessor(str).IsConstantString()) {
263             index = 1;
264         }
265         // Write the index in the head of string.
266         uint8_t headerSize = JSTaggedValue::TaggedTypeSize();
267         JSTaggedType indexHeader = JSTaggedValue(index).GetRawData();
268         writer.write(reinterpret_cast<char *>(&indexHeader), headerSize);
269         writer.write(reinterpret_cast<char *>(str) + headerSize, strSize - headerSize);
270         writer.flush();
271     }
272 
273     ASSERT(static_cast<size_t>(writer.tellp()) == totalObjSize + sizeof(SnapShotHeader));
274     if (jsPandaFile) {
275         writer.seekp(pandaFileBegin);
276         writer.write(static_cast<const char *>(jsPandaFile->GetHeader()), jsPandaFile->GetFileSize());
277     }
278     writer.close();
279 }
280 }  // namespace panda::ecmascript
281