• 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_->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     if (hdr.rootObjectSize == 0) {
162         LOG_ECMA(ERROR) << "Snapshot rootObjectSize is 0";
163     }
164     [[maybe_unused]] EcmaHandleScope stringHandleScope(vm_->GetJSThread());
165     if (g_isEnableCMCGC) {
166         uintptr_t regularObjBegin = readFile + sizeof(SnapShotHeader);
167         uintptr_t stringBegin = regularObjBegin + hdr.regularObjSize + hdr.pinnedObjSize + hdr.largeObjSize;
168         uintptr_t stringEnd = stringBegin + hdr.stringSize;
169         processor.DeserializeString(stringBegin, stringEnd);
170         processor.DeserializeObjectExcludeString(regularObjBegin, hdr.regularObjSize, hdr.pinnedObjSize,
171                                                  hdr.largeObjSize);
172     } else {
173         uintptr_t oldSpaceBegin = readFile + sizeof(SnapShotHeader);
174         uintptr_t stringBegin = oldSpaceBegin + hdr.oldSpaceObjSize + hdr.nonMovableObjSize +
175             hdr.machineCodeObjSize + hdr.snapshotObjSize + hdr.hugeObjSize;
176         uintptr_t stringEnd = stringBegin + hdr.stringSize;
177         processor.DeserializeString(stringBegin, stringEnd);
178         processor.DeserializeObjectExcludeString(oldSpaceBegin, hdr.oldSpaceObjSize, hdr.nonMovableObjSize,
179                                                  hdr.machineCodeObjSize, hdr.snapshotObjSize, hdr.hugeObjSize);
180     }
181 
182 #if !defined(CROSS_PLATFORM)
183     FileUnMap(MemMap(fileMap.GetOriginAddr(), hdr.pandaFileBegin));
184 #endif
185     std::shared_ptr<JSPandaFile> jsPandaFile;
186     if (fileMap.GetSize() > hdr.pandaFileBegin) {
187         uintptr_t pandaFileMem = readFile + hdr.pandaFileBegin;
188         auto pf = panda_file::File::OpenFromMemory(os::mem::ConstBytePtr(ToNativePtr<std::byte>(pandaFileMem),
189             fileMap.GetSize() - hdr.pandaFileBegin, os::mem::MmapDeleter));
190         jsPandaFile = JSPandaFileManager::GetInstance()->NewJSPandaFile(pf.release(), "");
191     }
192     // relocate object field
193     processor.Relocate(type, jsPandaFile.get(), hdr.rootObjectSize);
194     processor.AddRootObjectToAOTFileManager(type, snapshotFile);
195     // ONLY used in UT to get the deserialize value result
196     result_ = processor.GetDeserializeResultForUT();
197     LOG_COMPILER(INFO) << "loaded ai file: " << snapshotFile.c_str();
198     return true;
199 }
200 
Deserialize(SnapshotType type,const CString & snapshotFile,bool isBuiltins)201 bool Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, bool isBuiltins)
202 {
203     std::string realPath;
204     if (!RealPath(std::string(snapshotFile), realPath, false)) {
205         LOG_FULL(FATAL) << "snapshot file path error";
206         UNREACHABLE();
207     }
208 
209     if (!FileExist(realPath.c_str())) {
210         return false;
211     }
212 
213     SnapshotProcessor processor(vm_);
214     if (isBuiltins) {
215         processor.SetBuiltinsDeserializeStart();
216     }
217 
218     MemMap fileMap = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READWRITE);
219     return DeserializeInternal(type, snapshotFile, processor, fileMap);
220 }
221 
222 #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)223 bool Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, [[maybe_unused]] std::function<bool
224     (std::string fileName, uint8_t **buff, size_t *buffSize)> ReadAOTCallBack, bool isBuiltins)
225 {
226     SnapshotProcessor processor(vm_);
227     if (isBuiltins) {
228         processor.SetBuiltinsDeserializeStart();
229     }
230 
231     std::string fileName = std::string(snapshotFile);
232     uint8_t *buff = nullptr;
233     size_t buffSize = 0;
234     MemMap fileMap = {};
235     size_t found = fileName.find_last_of("/");
236     if (found != std::string::npos) {
237         fileName = fileName.substr(found + 1);
238     }
239 
240     LOG_ECMA(INFO) << "Call JsAotReader to load: " << fileName;
241     if (ReadAOTCallBack(fileName, &buff, &buffSize)) {
242         fileMap = MemMap(buff, buffSize);
243     }
244 
245     return DeserializeInternal(type, snapshotFile, processor, fileMap);
246 }
247 #endif
248 
AlignUpPageSize(size_t spaceSize)249 size_t Snapshot::AlignUpPageSize(size_t spaceSize)
250 {
251     if (spaceSize % Constants::PAGE_SIZE_ALIGN_UP == 0) {
252         return spaceSize;
253     }
254     return Constants::PAGE_SIZE_ALIGN_UP * (spaceSize / Constants::PAGE_SIZE_ALIGN_UP + 1);
255 }
256 
WriteToFile(std::fstream & writer,const JSPandaFile * jsPandaFile,size_t size,SnapshotProcessor & processor)257 void Snapshot::WriteToFile(std::fstream &writer, const JSPandaFile *jsPandaFile,
258                            size_t size, SnapshotProcessor &processor)
259 {
260     size_t totalStringSize = 0U;
261     CVector<uintptr_t> stringVector = processor.GetStringVector();
262     for (size_t i = 0; i < stringVector.size(); ++i) {
263         auto str = reinterpret_cast<EcmaString *>(stringVector[i]);
264         size_t objectSize = AlignUp(EcmaStringAccessor(str).ObjectSize(),
265             static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
266         totalStringSize += objectSize;
267     }
268 
269     std::vector<size_t> objSizeVector = processor.StatisticsObjectSize();
270     size_t totalObjSize = totalStringSize;
271     for (size_t objSize : objSizeVector) {
272         totalObjSize += objSize;
273     }
274     size_t pandaFileBegin = RoundUp(totalObjSize + sizeof(SnapShotHeader), Constants::PAGE_SIZE_ALIGN_UP);
275     SnapShotHeader hdr(GetLastVersion());
276     if (g_isEnableCMCGC) {
277         hdr.regularObjSize = objSizeVector[0];  // 0: regularObj
278         hdr.pinnedObjSize = objSizeVector[1];   // 1: pinnedObj
279         hdr.largeObjSize = objSizeVector[2];     // 2: largeObj
280     } else {
281         hdr.oldSpaceObjSize = objSizeVector[0]; // 0: oldSpaceObj
282         hdr.nonMovableObjSize = objSizeVector[1]; // 1: nonMovableObj
283         hdr.machineCodeObjSize = objSizeVector[2]; // 2: machineCodeObj
284         hdr.snapshotObjSize = objSizeVector[3]; // 3: snapshotObj
285         hdr.hugeObjSize = objSizeVector[4]; // 4: hugeObj
286     }
287     hdr.stringSize = totalStringSize;
288     hdr.pandaFileBegin = pandaFileBegin;
289     hdr.rootObjectSize = size;
290     writer.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
291     processor.WriteObjectToFile(writer);
292 
293     for (size_t i = 0; i < stringVector.size(); ++i) {
294         auto str = reinterpret_cast<EcmaString *>(stringVector[i]);
295         size_t strSize = AlignUp(EcmaStringAccessor(str).ObjectSize(),
296             static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
297         int index = 0; // 0 represents the line string.
298         // Write the index in the head of string.
299         uint8_t headerSize = JSTaggedValue::TaggedTypeSize();
300         JSTaggedType indexHeader = JSTaggedValue(index).GetRawData();
301         writer.write(reinterpret_cast<char *>(&indexHeader), headerSize);
302         writer.write(reinterpret_cast<char *>(str) + headerSize, strSize - headerSize);
303         writer.flush();
304     }
305 
306     ASSERT(static_cast<size_t>(writer.tellp()) == totalObjSize + sizeof(SnapShotHeader));
307     if (jsPandaFile) {
308         writer.seekp(pandaFileBegin);
309         writer.write(static_cast<const char *>(jsPandaFile->GetHeader()), jsPandaFile->GetFileSize());
310     }
311     writer.close();
312 }
313 }  // namespace panda::ecmascript
314