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