• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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/module/module_snapshot.h"
17 
18 #include "ecmascript/base/config.h"
19 #include "ecmascript/module/js_module_source_text.h"
20 #include "ecmascript/platform/file.h"
21 #include "ecmascript/serializer/module_deserializer.h"
22 #include "ecmascript/serializer/module_serializer.h"
23 #include "securec.h"
24 #include "zlib.h"
25 
26 namespace panda::ecmascript {
SerializeDataAndPostSavingJob(const EcmaVM * vm,const CString & path,const CString & version)27 void ModuleSnapshot::SerializeDataAndPostSavingJob(const EcmaVM *vm, const CString &path, const CString &version)
28 {
29     LOG_ECMA(INFO) << "ModuleSnapshot::SerializeDataAndPostSavingJob " << path;
30     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "ModuleSnapshot::SerializeDataAndPostSavingJob", "");
31     CString filePath = base::ConcatToCString(path, MODULE_SNAPSHOT_FILE_NAME);
32     if (FileExist(filePath.c_str())) {
33         LOG_ECMA(INFO) << "Module serialize file already exist";
34         return;
35     }
36     JSThread *thread = vm->GetJSThread();
37     std::unique_ptr<SerializeData> fileData = GetSerializeData(thread);
38     if (fileData == nullptr) {
39         return;
40     }
41     common::Taskpool::GetCurrentTaskpool()->PostTask(
42         std::make_unique<ModuleSnapshotTask>(thread->GetThreadId(), thread, fileData, filePath, version));
43 }
44 
DeserializeData(const EcmaVM * vm,const CString & path,const CString & version)45 bool ModuleSnapshot::DeserializeData(const EcmaVM *vm, const CString &path, const CString &version)
46 {
47     LOG_ECMA(INFO) << "ModuleSnapshot::DeserializeData";
48     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "ModuleSnapshot::DeserializeData", "");
49     CString filePath = base::ConcatToCString(path, MODULE_SNAPSHOT_FILE_NAME);
50     if (!FileExist(filePath.c_str())) {
51         LOG_ECMA(INFO) << "ModuleSnapshot::DeserializeData Module serialize file doesn't exist: " << path;
52         return false;
53     }
54     JSThread *thread = vm->GetJSThread();
55     std::unique_ptr<SerializeData> fileData = std::make_unique<SerializeData>(thread);
56     if (!ReadDataFromFile(thread, fileData, path, version)) {
57         LOG_ECMA(ERROR) << "ModuleSnapshot::DeserializeData failed: " << filePath;
58         return false;
59     }
60     ModuleDeserializer deserializer(thread, fileData.release());
61     JSHandle<TaggedArray> deserializedModules = JSHandle<TaggedArray>::Cast(deserializer.ReadValue());
62     uint32_t length = deserializedModules->GetLength();
63     for (uint32_t i = 0; i < length; i++) {
64         JSTaggedValue module = deserializedModules->Get(thread, i);
65         JSHandle<SourceTextModule> moduleHdl(thread, SourceTextModule::Cast(module.GetTaggedObject()));
66         CString moduleName = SourceTextModule::GetModuleName(module);
67         if (SourceTextModule::IsSharedModule(moduleHdl)) {
68             SharedModuleManager::GetInstance()->AddToResolvedModulesAndCreateSharedModuleMutex(
69                 thread, moduleName, module);
70             continue;
71         }
72         thread->GetModuleManager()->AddResolveImportedModule(moduleName, module);
73     }
74     LOG_ECMA(INFO) << "ModuleSnapshot::DeserializeData success";
75     return true;
76 }
77 
GetModuleSerializeArray(JSThread * thread)78 JSHandle<TaggedArray> ModuleSnapshot::GetModuleSerializeArray(JSThread *thread)
79 {
80     ModuleManager *moduleManager = thread->GetModuleManager();
81     uint32_t normalModuleSize = moduleManager->GetResolvedModulesSize();
82     uint32_t sharedModuleSize = SharedModuleManager::GetInstance()->GetResolvedSharedModulesSize();
83     EcmaVM *vm = thread->GetEcmaVM();
84     ObjectFactory *factory = vm->GetFactory();
85     JSHandle<TaggedArray> serializerArray = factory->NewTaggedArray(normalModuleSize + sharedModuleSize);
86     moduleManager->AddNormalSerializeModule(thread, serializerArray, 0); // 0: start index
87     SharedModuleManager::GetInstance()->AddSharedSerializeModule(thread, serializerArray, normalModuleSize);
88     return serializerArray;
89 }
90 
RestoreUpdatedBinding(JSThread * thread,JSHandle<TaggedArray> serializeArray)91 void ModuleSnapshot::RestoreUpdatedBinding(JSThread* thread, JSHandle<TaggedArray> serializeArray)
92 {
93     auto globalConstants = thread->GlobalConstants();
94     JSMutableHandle<SourceTextModule> module(thread, globalConstants->GetUndefined());
95     JSMutableHandle<ResolvedIndexBinding> indexBinding(thread, globalConstants->GetUndefined());
96     JSMutableHandle<TaggedArray> environment(thread, globalConstants->GetUndefined());
97     for (uint32_t moduleIdx = 0; moduleIdx < serializeArray->GetLength(); ++moduleIdx) {
98         module.Update(serializeArray->Get(thread, moduleIdx));
99         JSTaggedValue moduleEnvironment = module->GetEnvironment(thread);
100         if (moduleEnvironment.IsUndefined()) {
101             continue;
102         }
103         environment.Update(moduleEnvironment);
104         bool isShared = SourceTextModule::IsSharedModule(module);
105         // check every binding and transfer from ResolvedIndexBinding to ResolvedBinding if binding updated.
106         for (uint32_t bindingIdx = 0; bindingIdx < environment->GetLength(); bindingIdx++) {
107             JSTaggedValue binding = environment->Get(thread, bindingIdx);
108             if (binding.IsResolvedIndexBinding() &&
109                 ResolvedIndexBinding::Cast(binding)->GetIsUpdatedFromResolvedBinding()) {
110                 indexBinding.Update(binding);
111                 JSHandle<JSTaggedValue> nameBinding =
112                     SourceTextModule::CreateBindingByIndexBinding(thread, indexBinding, isShared);
113                 environment->Set(thread, bindingIdx, nameBinding);
114             }
115         }
116     }
117 }
118 
Run(uint32_t threadIndex)119 bool ModuleSnapshot::ModuleSnapshotTask::Run(uint32_t threadIndex)
120 {
121     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "ModuleSnapshotTask", "");
122     WriteDataToFile(thread_, serializeData_, path_, version_);
123     return true;
124 }
125 
RemoveSnapshotFiles(const CString & path)126 void ModuleSnapshot::RemoveSnapshotFiles(const CString &path)
127 {
128     DeleteFilesWithSuffix(path.c_str(), SNAPSHOT_FILE_SUFFIX.data());
129 }
130 
GetSerializeData(JSThread * thread)131 std::unique_ptr<SerializeData> ModuleSnapshot::GetSerializeData(JSThread *thread)
132 {
133     ModuleSerializer serializer(thread);
134     JSHandle<TaggedArray> serializeArray = GetModuleSerializeArray(thread);
135     RestoreUpdatedBinding(thread, serializeArray);
136     const GlobalEnvConstants *globalConstants = thread->GlobalConstants();
137     if (!serializer.WriteValue(thread, JSHandle<JSTaggedValue>(serializeArray),
138                                globalConstants->GetHandledUndefined(),
139                                globalConstants->GetHandledUndefined())) {
140         LOG_ECMA(ERROR) << "ModuleSnapshot::GetSerializeData serialize failed";
141         return nullptr;
142     }
143     std::unique_ptr<SerializeData> fileData = serializer.Release();
144     return fileData;
145 }
146 
ReadDataFromFile(JSThread * thread,std::unique_ptr<SerializeData> & data,const CString & path,const CString & version)147 bool ModuleSnapshot::ReadDataFromFile(JSThread *thread, std::unique_ptr<SerializeData>& data, const CString& path,
148     const CString &version)
149 {
150     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "ModuleSnapshot::ReadDataFromFile", "");
151     CString filePath = base::ConcatToCString(path, MODULE_SNAPSHOT_FILE_NAME);
152     MemMap fileMapMem = FileMap(filePath.c_str(), FILE_RDONLY, PAGE_PROT_READ);
153     if (fileMapMem.GetOriginAddr() == nullptr) {
154         RemoveSnapshotFiles(path);
155         LOG_ECMA(ERROR) << "ModuleSnapshot::ReadDataFromFile File mmap failed";
156         return false;
157     }
158     LOG_ECMA(INFO) << "ModuleSnapshot::ReadDataFromFile";
159     MemMapScope memMapScope(fileMapMem);
160     FileMemMapReader reader(fileMapMem, std::bind(RemoveSnapshotFiles, path), "ModuleSnapshot::ReadDataFromFile");
161     uint32_t checksumSize = sizeof(uint32_t);
162     uint32_t contentSize = fileMapMem.GetSize() - checksumSize;
163     uint32_t readCheckSum = 0;
164     if (!reader.ReadFromOffset(&readCheckSum, checksumSize, contentSize, "checksum")) {
165         return false;
166     }
167     uint32_t checksum = adler32(0, static_cast<const Bytef*>(fileMapMem.GetOriginAddr()), contentSize);
168     if (checksum != readCheckSum) {
169         LOG_ECMA(ERROR) << "ModuleSnapshot::ReadDataFromFile checksum compare failed, checksum: " << checksum
170             << ", readCheckSum" << readCheckSum;
171         RemoveSnapshotFiles(path);
172         return false;
173     }
174     // read app version
175     uint32_t readAppVersionCode = 0;
176     if (!reader.ReadSingleData(&readAppVersionCode, sizeof(readAppVersionCode), "AppVersionCode")) {
177         return false;
178     }
179     uint32_t appVersionCode = thread->GetEcmaVM()->GetApplicationVersionCode();
180     if (readAppVersionCode != appVersionCode) {
181         LOG_ECMA(ERROR) << "ModuleSnapshot::ReadDataFromFile readAppVersionCode: " << readAppVersionCode <<
182             ", appVersionCode: " << appVersionCode << " doesn't match";
183         RemoveSnapshotFiles(path);
184         return false;
185     }
186     // read version
187     uint32_t readVersionStrLen = 0;
188     if (!reader.ReadSingleData(&readVersionStrLen, sizeof(readVersionStrLen), "readVersionStrLen")) {
189         return false;
190     }
191     CString readVersionStr;
192     if (!reader.ReadString(readVersionStr, readVersionStrLen, "readVersionStr")) {
193         return false;
194     }
195     if (version != readVersionStr) {
196         LOG_ECMA(ERROR) << "ModuleSnapshot::ReadDataFromFile version compare failed, version: " << version
197             << ", readVersion" << readVersionStr;
198         RemoveSnapshotFiles(path);
199         return false;
200     }
201     // read dataIndex
202     if (!reader.ReadSingleData(&data->dataIndex_, sizeof(data->dataIndex_), "dataIndex")) {
203         return false;
204     }
205 
206     // 8-byte alignment
207     reader.Step(GetAlignUpPadding(reader.GetReadPtr(), fileMapMem.GetOriginAddr(), sizeof(uint64_t)));
208 
209     // read uint64_t
210     if (!reader.ReadSingleData(&data->sizeLimit_, sizeof(data->sizeLimit_), "sizeLimit")) {
211         return false;
212     }
213     // 8-byte alignment
214     reader.Step(GetAlignUpPadding(reader.GetReadPtr(), fileMapMem.GetOriginAddr(), sizeof(uint64_t)));
215     // read group size
216     size_t sizeGroup[GROUP_SIZE];
217     if (!reader.ReadSingleData(sizeGroup, GROUP_SIZE * sizeof(size_t), "sizeGroup")) {
218         return false;
219     }
220     data->bufferSize_ = sizeGroup[BUFFER_SIZE_INDEX];
221     data->bufferCapacity_ = sizeGroup[BUFFER_CAPACITY_INDEX];
222     data->regularSpaceSize_ = sizeGroup[REGULAR_SPACE_SIZE_INDEX];
223     data->pinSpaceSize_ = sizeGroup[PIN_SPACE_SIZE_INDEX];
224     data->oldSpaceSize_ = sizeGroup[OLD_SPACE_SIZE_INDEX];
225     data->nonMovableSpaceSize_ = sizeGroup[NONMOVABLE_SPACE_SIZE_INDEX];
226     data->machineCodeSpaceSize_ = sizeGroup[MACHINECODE_SPACE_SIZE_INDEX];
227     data->sharedOldSpaceSize_ = sizeGroup[SHARED_OLD_SPACE_SIZE_INDEX];
228     data->sharedNonMovableSpaceSize_ = sizeGroup[SHARED_NONMOVABLE_SPACE_SIZE_INDEX];
229 
230     // read and check imcompleteData
231     const size_t incompleteData = sizeGroup[INCOMPLETE_DATA_INDEX];
232     if (incompleteData != 0) {
233         LOG_ECMA(ERROR) << "ModuleSnapshot::ReadDataFromFile has incompleteData: " << incompleteData;
234         RemoveSnapshotFiles(path);
235         return false;
236     }
237     data->incompleteData_ = (incompleteData != 0);
238 
239     if (g_isEnableCMCGC) {
240         // read regularRemainSizeVectorSize
241         size_t regularRemainSizeVectorSize;
242         if (!reader.ReadSingleData(&regularRemainSizeVectorSize, sizeof(regularRemainSizeVectorSize),
243             "regularRemainSizeVectorSize")) {
244             return false;
245         }
246         // read regularRemainSizeVector
247         size_t vecSize = regularRemainSizeVectorSize * sizeof(size_t);
248         if (vecSize > 0) {
249             data->regularRemainSizeVector_.resize(regularRemainSizeVectorSize);
250             if (!reader.ReadSingleData(data->regularRemainSizeVector_.data(), vecSize,
251                 "regularRemainSizeVector")) {
252                 return false;
253             }
254         }
255         // read pinRemainSizeVectorSize
256         size_t pinRemainSizeVectorSize = 0;
257         if (!reader.ReadSingleData(&pinRemainSizeVectorSize, sizeof(pinRemainSizeVectorSize),
258             "pinRemainSizeVectorSize")) {
259             return false;
260         }
261         // read pinRemainSizeVector
262         vecSize = pinRemainSizeVectorSize * sizeof(size_t);
263         if (vecSize > 0) {
264             data->pinRemainSizeVector_.resize(pinRemainSizeVectorSize);
265             if (!reader.ReadSingleData(data->pinRemainSizeVector_.data(), vecSize, "pinRemainSizeVector")) {
266                 return false;
267             }
268         }
269     } else {
270         // read vector size
271         std::array<size_t, SERIALIZE_SPACE_NUM> vecSizes {};
272         uint32_t vecSize = SERIALIZE_SPACE_NUM * sizeof(size_t);
273         if (!reader.ReadSingleData(vecSizes.data(), vecSize, "vecSizes")) {
274             return false;
275         }
276         // read each vector data
277         for (int i = 0; i < SERIALIZE_SPACE_NUM; ++i) {
278             auto& vec = data->regionRemainSizeVectors_[i];
279             const size_t curVectorSize = vecSizes[i];
280             const uint32_t curVectorDataSize = curVectorSize * sizeof(size_t);
281             if (curVectorSize > 0) {
282                 vec.resize(curVectorSize);
283                 if (!reader.ReadSingleData(vec.data(), curVectorDataSize, "vec")) {
284                     return false;
285                 }
286             } else {
287                 vec.clear();
288             }
289         }
290     }
291 
292     // read buffer data
293     if (data->bufferSize_ > 0) {
294         data->buffer_ = static_cast<uint8_t*>(malloc(data->bufferSize_));
295         if (!data->buffer_) {
296             RemoveSnapshotFiles(path);
297             return false;
298         }
299         if (!reader.ReadSingleData(data->buffer_, data->bufferSize_, "buffer")) {
300             return false;
301         }
302     } else {
303         data->buffer_ = nullptr;
304     }
305 
306     LOG_ECMA(INFO) << "ModuleSnapshot::ReadDataFromFile success";
307     return true;
308 }
309 
WriteDataToFile(JSThread * thread,const std::unique_ptr<SerializeData> & data,const CString & filePath,const CString & version)310 bool ModuleSnapshot::WriteDataToFile(
311     JSThread *thread, const std::unique_ptr<SerializeData>& data, const CString& filePath, const CString &version)
312 {
313     LOG_ECMA(INFO) << "ModuleSnapshot::WriteDataToFile";
314     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "ModuleSnapshot::WriteDataToFile", "");
315     // calculate file total size
316     // versionCode
317     uint32_t appVersionCode = thread->GetEcmaVM()->GetApplicationVersionCode();
318     uint32_t totalSize = sizeof(appVersionCode);
319     uint32_t versionStrLenSize = sizeof(uint32_t);
320     uint32_t versionStrLen = version.size();
321     totalSize += versionStrLenSize;
322     totalSize += versionStrLen;
323 
324     totalSize += sizeof(data->dataIndex_);
325     const size_t alignUp = AlignUp(totalSize, sizeof(uint64_t));
326     totalSize = alignUp + sizeof(data->sizeLimit_);
327 
328     // alignment to size_t
329     totalSize = AlignUp(totalSize, sizeof(size_t));
330     // GROUP_SIZE
331     totalSize += GROUP_SIZE * sizeof(size_t);
332 
333     if (g_isEnableCMCGC) {
334         totalSize += CMC_GC_REGION_SIZE * sizeof(size_t);
335         totalSize += data->regularRemainSizeVector_.size() * sizeof(size_t);
336         totalSize += data->pinRemainSizeVector_.size() * sizeof(size_t);
337     } else {
338         // vector each element in vector's length
339         totalSize += SERIALIZE_SPACE_NUM * sizeof(size_t);
340 
341         // vector data
342         size_t totalVecBytes = 0;
343         for (const auto& vec : data->regionRemainSizeVectors_) {
344             totalVecBytes += vec.size() * sizeof(size_t);
345         }
346         totalSize += totalVecBytes;
347     }
348     // buffer data
349     totalSize += data->bufferSize_;
350     uint32_t checksumSize = sizeof(uint32_t);
351     totalSize += checksumSize;
352     MemMap fileMapMem =
353         CreateFileMap(filePath.c_str(), totalSize, FILE_RDWR | FILE_CREAT | FILE_TRUNC, PAGE_PROT_READWRITE);
354     if (fileMapMem.GetOriginAddr() == nullptr) {
355         LOG_ECMA(ERROR) << "ModuleSnapshot::WriteDataToFile File mmap failed";
356         return false;
357     }
358     MemMapScope memMapScope(fileMapMem);
359     FileMemMapWriter writer(fileMapMem, "ModuleSnapshot::WriteDataToFile");
360 
361     // write app versionCode
362     if (!writer.WriteSingleData(&appVersionCode, sizeof(appVersionCode), "appVersionCode")) {
363         return false;
364     }
365     // write version
366     if (!writer.WriteSingleData(&versionStrLen, versionStrLenSize, "versionStrLen")) {
367         return false;
368     }
369     if (!writer.WriteSingleData(version.c_str(), versionStrLen, "versionStr")) {
370         return false;
371     }
372     // write dataIndex
373     if (!writer.WriteSingleData(&data->dataIndex_, sizeof(data->dataIndex_), "dataIndex")) {
374         return false;
375     }
376 
377     // padding
378     if (!writer.WriteAlignUpPadding(GetAlignUpPadding(writer.GetWritePtr(),
379         fileMapMem.GetOriginAddr(), sizeof(uint64_t)))) {
380         return false;
381     }
382     // write uint64_t
383     if (!writer.WriteSingleData(&data->sizeLimit_, sizeof(data->sizeLimit_), "sizeLimit")) {
384         return false;
385     }
386 
387     // alignment to size_t
388     if (!writer.WriteAlignUpPadding(GetAlignUpPadding(writer.GetWritePtr(),
389         fileMapMem.GetOriginAddr(), sizeof(uint64_t)))) {
390         return false;
391     }
392     // constructor and write GROUP data(size_t)
393     size_t sizeGroup[GROUP_SIZE] = {
394         data->bufferSize_,
395         data->bufferCapacity_,
396         data->regularSpaceSize_,
397         data->pinSpaceSize_,
398         data->oldSpaceSize_,
399         data->nonMovableSpaceSize_,
400         data->machineCodeSpaceSize_,
401         data->sharedOldSpaceSize_,
402         data->sharedNonMovableSpaceSize_,
403         static_cast<size_t>(data->incompleteData_)
404     };
405     if (!writer.WriteSingleData(sizeGroup, GROUP_SIZE * sizeof(size_t), "sizeGroup")) {
406         return false;
407     }
408 
409     if (g_isEnableCMCGC) {
410         totalSize += data->regularRemainSizeVector_.size() * sizeof(size_t);
411         totalSize += data->pinRemainSizeVector_.size() * sizeof(size_t);
412         size_t regularRemainSize = data->regularRemainSizeVector_.size();
413         // regularRemainSizeVector size
414         if (!writer.WriteSingleData(&regularRemainSize, sizeof(regularRemainSize), "regularRemainSize")) {
415             return false;
416         }
417         // regularRemainSizeVector
418         size_t regularRemainLen = regularRemainSize * sizeof(size_t);
419         if (regularRemainLen > 0) {
420             if (!writer.WriteSingleData(data->regularRemainSizeVector_.data(), regularRemainLen,
421                 "regularRemainSizeVector")) {
422                 return false;
423             }
424         }
425         // pinRemainSizeVector size
426         size_t pinRemainSize = data->pinRemainSizeVector_.size();
427         if (!writer.WriteSingleData(&pinRemainSize, sizeof(pinRemainSize), "pinRemainSize")) {
428             return false;
429         }
430         // pinRemainSizeVector
431         size_t pinRemainLen = pinRemainSize * sizeof(size_t);
432         if (pinRemainLen > 0) {
433             if (!writer.WriteSingleData(data->pinRemainSizeVector_.data(), pinRemainLen, "pinRemainSizeVector")) {
434                 return false;
435             }
436         }
437     } else {
438         // write vector's size
439         std::array<size_t, SERIALIZE_SPACE_NUM> vecSizes;
440         for (int i = 0; i < SERIALIZE_SPACE_NUM; ++i) {
441             vecSizes[i] = data->regionRemainSizeVectors_[i].size();
442         }
443         uint32_t vecSize = SERIALIZE_SPACE_NUM * sizeof(size_t);
444         if (!writer.WriteSingleData(vecSizes.data(), vecSize, "vecSizes")) {
445             return false;
446         }
447 
448         // write vector's data
449         for (const auto& vec : data->regionRemainSizeVectors_) {
450             if (!vec.empty()) {
451                 uint32_t curVectorDataSize = vec.size() * sizeof(size_t);
452                 if (!writer.WriteSingleData(vec.data(), curVectorDataSize, "vec")) {
453                     return false;
454                 }
455             }
456         }
457     }
458     // write buffer data
459     if (data->bufferSize_ > 0) {
460         if (!data->buffer_) {
461             return false;
462         }
463         if (!writer.WriteSingleData(data->buffer_, data->bufferSize_, "buffer")) {
464             return false;
465         }
466     }
467     uint32_t contentSize = fileMapMem.GetSize() - checksumSize;
468     uint32_t checksum = adler32(0, static_cast<const Bytef*>(fileMapMem.GetOriginAddr()), contentSize);
469     if (!writer.WriteSingleData(&checksum, checksumSize, "checksum")) {
470         return false;
471     }
472     FileSync(fileMapMem, FILE_MS_SYNC);
473     LOG_ECMA(INFO) << "ModuleSnapshot::WriteDataToFile success";
474     return true;
475 }
476 } // namespace panda::ecmascript
477