• 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/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