• 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/jspandafile/js_pandafile_manager.h"
17 
18 #include "ecmascript/compiler/aot_file/an_file_data_manager.h"
19 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
20 #include "ecmascript/js_file_path.h"
21 #include "ecmascript/jspandafile/program_object.h"
22 #include "ecmascript/module/module_path_helper.h"
23 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
24 #include "file.h"
25 
26 namespace panda::ecmascript {
27 static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options
28 
GetInstance()29 JSPandaFileManager *JSPandaFileManager::GetInstance()
30 {
31     static JSPandaFileManager *jsFileManager = new JSPandaFileManager();
32     return jsFileManager;
33 }
34 
~JSPandaFileManager()35 JSPandaFileManager::~JSPandaFileManager()
36 {
37     os::memory::LockHolder lock(jsPandaFileLock_);
38     extractors_.clear();
39     oldJSPandaFiles_.clear();
40     loadedJSPandaFiles_.clear();
41 }
42 
LoadJSPandaFile(JSThread * thread,const CString & filename,std::string_view entryPoint,bool needUpdate)43 std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
44     std::string_view entryPoint, bool needUpdate)
45 {
46     {
47         os::memory::LockHolder lock(jsPandaFileLock_);
48         std::shared_ptr<JSPandaFile> jsPandaFile;
49         if (needUpdate) {
50             auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
51             if (pf == nullptr) {
52                 LOG_ECMA(ERROR) << "open file " << filename << " error";
53                 return nullptr;
54             }
55             jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
56         } else {
57             jsPandaFile = FindJSPandaFileUnlocked(filename);
58         }
59         if (jsPandaFile != nullptr) {
60             InsertJSPandaFileVmUnlocked(thread->GetEcmaVM(), jsPandaFile);
61             return jsPandaFile;
62         }
63     }
64 
65     EcmaVM *vm = thread->GetEcmaVM();
66     bool mode = thread->GetCurrentEcmaContext()->GetModuleManager()->GetCurrentMode();
67     std::unique_ptr<const panda_file::File> pf;
68     if (!vm->IsBundlePack() && mode) {
69         ResolveBufferCallback resolveBufferCallback = vm->GetResolveBufferCallback();
70         if (resolveBufferCallback == nullptr) {
71             LOG_ECMA(ERROR) << "resolveBufferCallback is nullptr";
72             return nullptr;
73         }
74         uint8_t *data = nullptr;
75         size_t dataSize = 0;
76         bool getBuffer = resolveBufferCallback(ModulePathHelper::ParseHapPath(filename), &data, &dataSize);
77         if (!getBuffer) {
78             LOG_ECMA(ERROR) << "resolveBufferCallback get buffer failed";
79             return nullptr;
80         }
81 #if defined(PANDA_TARGET_ANDROID) || defined(PANDA_TARGET_IOS)
82         pf = panda_file::OpenPandaFileFromMemory(data, dataSize);
83 #else
84         pf = panda_file::OpenPandaFileFromSecureMemory(data, dataSize);
85 #endif
86     } else {
87         pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
88     }
89 
90     if (pf == nullptr) {
91         LOG_ECMA(ERROR) << "open file " << filename << " error";
92         return nullptr;
93     }
94 
95     std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), filename, entryPoint);
96 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
97     if (thread->GetIsProfiling()) {
98         GetJSPtExtractorAndExtract(jsPandaFile.get());
99     }
100 #endif
101     return jsPandaFile;
102 }
103 
104 // The security interface needs to be modified accordingly.
LoadJSPandaFile(JSThread * thread,const CString & filename,std::string_view entryPoint,const void * buffer,size_t size,bool needUpdate)105 std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
106     std::string_view entryPoint, const void *buffer, size_t size, bool needUpdate)
107 {
108     if (buffer == nullptr || size == 0) {
109         LOG_FULL(ERROR) << "Input buffer is empty";
110         return nullptr;
111     }
112     {
113         os::memory::LockHolder lock(jsPandaFileLock_);
114         std::shared_ptr<JSPandaFile> jsPandaFile;
115         if (needUpdate) {
116             auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
117             if (pf == nullptr) {
118                 LOG_ECMA(ERROR) << "open file buffer " << filename << " error";
119                 return nullptr;
120             }
121             jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
122         } else {
123             jsPandaFile = FindJSPandaFileUnlocked(filename);
124         }
125         if (jsPandaFile != nullptr) {
126             InsertJSPandaFileVmUnlocked(thread->GetEcmaVM(), jsPandaFile);
127             return jsPandaFile;
128         }
129     }
130 
131     auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
132     if (pf == nullptr) {
133         LOG_ECMA(ERROR) << "open file " << filename << " error";
134         return nullptr;
135     }
136 
137     // JSPandaFile desc cannot be empty, if buffer with empty filename, use pf filename as a descriptor.
138     const CString &desc = filename.empty() ? pf->GetFilename().c_str() : filename;
139 
140     std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), desc, entryPoint);
141 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
142     if (thread->GetIsProfiling()) {
143         GetJSPtExtractorAndExtract(jsPandaFile.get());
144     }
145 #endif
146     return jsPandaFile;
147 }
148 
LoadJSPandaFileSecure(JSThread * thread,const CString & filename,std::string_view entryPoint,uint8_t * buffer,size_t size,bool needUpdate)149 std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFileSecure(JSThread *thread, const CString &filename,
150     std::string_view entryPoint, uint8_t *buffer, size_t size, bool needUpdate)
151 {
152     if (buffer == nullptr || size == 0) {
153         LOG_FULL(ERROR) << "Input buffer is empty";
154         return nullptr;
155     }
156     {
157         os::memory::LockHolder lock(jsPandaFileLock_);
158         std::shared_ptr<JSPandaFile> jsPandaFile;
159         if (needUpdate) {
160             auto pf = panda_file::OpenPandaFileFromSecureMemory(buffer, size);
161             if (pf == nullptr) {
162                 LOG_ECMA(ERROR) << "open file buffer " << filename << " error";
163                 return nullptr;
164             }
165             jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
166         } else {
167             jsPandaFile = FindJSPandaFileUnlocked(filename);
168         }
169         if (jsPandaFile != nullptr) {
170             InsertJSPandaFileVmUnlocked(thread->GetEcmaVM(), jsPandaFile);
171             return jsPandaFile;
172         }
173     }
174 
175     auto pf = panda_file::OpenPandaFileFromSecureMemory(buffer, size);
176     if (pf == nullptr) {
177         LOG_ECMA(ERROR) << "open file " << filename << " error";
178         return nullptr;
179     }
180 
181     // JSPandaFile desc cannot be empty, if buffer with empty filename, use pf filename as a descriptor.
182     const CString &desc = filename.empty() ? pf->GetFilename().c_str() : filename;
183 
184     std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), desc, entryPoint);
185 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
186     if (thread->GetIsProfiling()) {
187         GetJSPtExtractorAndExtract(jsPandaFile.get());
188     }
189 #endif
190     return jsPandaFile;
191 }
192 
GenerateProgram(EcmaVM * vm,const JSPandaFile * jsPandaFile,std::string_view entryPoint)193 JSHandle<Program> JSPandaFileManager::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile,
194                                                       std::string_view entryPoint)
195 {
196     ASSERT(GetJSPandaFile(jsPandaFile->GetPandaFile()) != nullptr);
197     if (AnFileDataManager::GetInstance()->IsEnable()) {
198         vm->GetJSThread()->GetCurrentEcmaContext()->GetAOTFileManager()->LoadAiFile(jsPandaFile);
199     }
200 
201     return PandaFileTranslator::GenerateProgram(vm, jsPandaFile, entryPoint);
202 }
203 
FindJSPandaFileWithChecksum(const CString & filename,uint32_t checksum)204 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileWithChecksum(const CString &filename, uint32_t checksum)
205 {
206     std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(filename);
207     if (jsPandaFile == nullptr) {
208         return nullptr;
209     }
210 
211     if (checksum == jsPandaFile->GetChecksum()) {
212         return jsPandaFile;
213     }
214 
215     LOG_FULL(INFO) << "reload " << filename << " with new checksum";
216     ObsoleteLoadedJSPandaFile(filename);
217     return nullptr;
218 }
219 
FindMergedJSPandaFile()220 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindMergedJSPandaFile()
221 {
222     os::memory::LockHolder lock(jsPandaFileLock_);
223     for (const auto &iter : loadedJSPandaFiles_) {
224         const std::shared_ptr<JSPandaFile> &jsPandafile = iter.second.first;
225         if (jsPandafile->IsFirstMergedAbc()) {
226             return jsPandafile;
227         }
228     }
229     return nullptr;
230 }
231 
FindJSPandaFileUnlocked(const CString & filename)232 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileUnlocked(const CString &filename)
233 {
234     if (filename.empty()) {
235         return nullptr;
236     }
237     const auto iter = loadedJSPandaFiles_.find(filename);
238     if (iter == loadedJSPandaFiles_.end()) {
239         return nullptr;
240     }
241     return iter->second.first;
242 }
243 
FindJSPandaFile(const CString & filename)244 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFile(const CString &filename)
245 {
246     os::memory::LockHolder lock(jsPandaFileLock_);
247     return FindJSPandaFileUnlocked(filename);
248 }
249 
GetJSPandaFile(const panda_file::File * pf)250 std::shared_ptr<JSPandaFile> JSPandaFileManager::GetJSPandaFile(const panda_file::File *pf)
251 {
252     os::memory::LockHolder lock(jsPandaFileLock_);
253     for (const auto &iter : loadedJSPandaFiles_) {
254         const std::shared_ptr<JSPandaFile> &jsPandafile = iter.second.first;
255         if (jsPandafile->GetPandaFile() == pf) {
256             return jsPandafile;
257         }
258     }
259     return nullptr;
260 }
261 
AddJSPandaFileVm(const EcmaVM * vm,const std::shared_ptr<JSPandaFile> & jsPandaFile)262 void JSPandaFileManager::AddJSPandaFileVm(const EcmaVM *vm, const std::shared_ptr<JSPandaFile> &jsPandaFile)
263 {
264     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
265     os::memory::LockHolder lock(jsPandaFileLock_);
266     if (loadedJSPandaFiles_.find(filename) != loadedJSPandaFiles_.end()) {
267         LOG_ECMA(FATAL) << "add failed, file already exist: " << filename;
268         UNREACHABLE();
269     }
270 
271     std::set<const EcmaVM *> vmSet {vm};
272     JSPandaFileVmsPair pandaFileRecord = std::make_pair(jsPandaFile, std::move(vmSet));
273     loadedJSPandaFiles_[filename] = std::move(pandaFileRecord);
274     LOG_ECMA(DEBUG) << "add file: " << filename;
275 }
276 
InsertJSPandaFileVmUnlocked(const EcmaVM * vm,const std::shared_ptr<JSPandaFile> & jsPandaFile)277 void JSPandaFileManager::InsertJSPandaFileVmUnlocked(const EcmaVM *vm,
278                                                      const std::shared_ptr<JSPandaFile> &jsPandaFile)
279 {
280     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
281     auto iter = loadedJSPandaFiles_.find(filename);
282     if (iter == loadedJSPandaFiles_.end()) {
283         LOG_ECMA(FATAL) << "insert vm failed, file not exist: " << filename;
284         UNREACHABLE();
285     }
286 
287     auto &vmSet = iter->second.second;
288     vmSet.emplace(vm);
289 }
290 
RemoveJSPandaFileVm(const EcmaVM * vm,const JSPandaFile * jsPandaFile)291 void JSPandaFileManager::RemoveJSPandaFileVm(const EcmaVM *vm, const JSPandaFile *jsPandaFile)
292 {
293     if (jsPandaFile == nullptr) {
294         return;
295     }
296 
297     os::memory::LockHolder lock(jsPandaFileLock_);
298     auto iterOld = oldJSPandaFiles_.begin();
299     while (iterOld != oldJSPandaFiles_.end()) {
300         if (iterOld->first.get() == jsPandaFile) {
301             auto &vmSet = iterOld->second;
302             vmSet.erase(vm);
303             if (vmSet.empty()) {
304                 extractors_.erase(jsPandaFile);
305                 oldJSPandaFiles_.erase(iterOld);
306             }
307             return;
308         }
309         iterOld++;
310     }
311     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
312     auto iter = loadedJSPandaFiles_.find(filename);
313     if (iter != loadedJSPandaFiles_.end()) {
314         auto &vmSet = iter->second.second;
315         vmSet.erase(vm);
316         if (vmSet.empty()) {
317             extractors_.erase(jsPandaFile);
318             // erase shared_ptr from map, the ref count -1.
319             loadedJSPandaFiles_.erase(iter);
320         }
321     }
322 }
323 
ObsoleteLoadedJSPandaFile(const CString & filename)324 void JSPandaFileManager::ObsoleteLoadedJSPandaFile(const CString &filename)
325 {
326     auto iter = loadedJSPandaFiles_.find(filename);
327     ASSERT(iter != loadedJSPandaFiles_.end());
328     std::shared_ptr<JSPandaFile> &jsPandaFile = iter->second.first;
329     if (oldJSPandaFiles_.find(jsPandaFile) == oldJSPandaFiles_.end()) {
330         oldJSPandaFiles_.emplace(jsPandaFile, iter->second.second);
331     } else {
332         auto &oldVmSet = oldJSPandaFiles_[jsPandaFile];
333         auto &vmSet = iter->second.second;
334         oldVmSet.insert(vmSet.begin(), vmSet.end());
335     }
336     loadedJSPandaFiles_.erase(iter);
337 }
338 
OpenJSPandaFile(const CString & filename)339 std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFile(const CString &filename)
340 {
341     auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
342     if (pf == nullptr) {
343         LOG_ECMA(ERROR) << "open file " << filename << " error";
344         return nullptr;
345     }
346 
347     return NewJSPandaFile(pf.release(), filename);
348 }
349 
OpenJSPandaFileFromBuffer(uint8_t * buffer,size_t size,const CString & filename)350 std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFileFromBuffer(uint8_t *buffer,
351                                                                            size_t size,
352                                                                            const CString &filename)
353 {
354     auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
355     if (pf == nullptr) {
356         LOG_ECMA(ERROR) << "open file " << filename << " error";
357         return nullptr;
358     }
359 
360     return NewJSPandaFile(pf.release(), filename);
361 }
362 
NewJSPandaFile(const panda_file::File * pf,const CString & desc)363 std::shared_ptr<JSPandaFile> JSPandaFileManager::NewJSPandaFile(const panda_file::File *pf, const CString &desc)
364 {
365     std::shared_ptr<JSPandaFile> jsPandaFile = std::make_shared<JSPandaFile>(pf, desc);
366     PGOProfilerManager::GetInstance()->SamplePandaFileInfo(jsPandaFile->GetChecksum());
367     return jsPandaFile;
368 }
369 
GetJSPtExtractor(const JSPandaFile * jsPandaFile)370 DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *jsPandaFile)
371 {
372     LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
373 
374     os::memory::LockHolder lock(jsPandaFileLock_);
375     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
376     if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
377         LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
378         UNREACHABLE();
379     }
380 
381     auto iter = extractors_.find(jsPandaFile);
382     if (iter == extractors_.end()) {
383         auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
384         DebugInfoExtractor *extractor = extractorPtr.get();
385         extractors_[jsPandaFile] = std::move(extractorPtr);
386         return extractor;
387     }
388 
389     return iter->second.get();
390 }
391 
GetJSPtExtractorAndExtract(const JSPandaFile * jsPandaFile)392 DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractorAndExtract(const JSPandaFile *jsPandaFile)
393 {
394     LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
395 
396     os::memory::LockHolder lock(jsPandaFileLock_);
397     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
398     if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
399         LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
400         UNREACHABLE();
401     }
402 
403     auto iter = extractors_.find(jsPandaFile);
404     if (iter == extractors_.end()) {
405         auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
406         DebugInfoExtractor *extractor = extractorPtr.get();
407         extractor->Extract();
408         extractors_[jsPandaFile] = std::move(extractorPtr);
409         return extractor;
410     }
411 
412     return iter->second.get();
413 }
414 
CpuProfilerGetJSPtExtractor(const JSPandaFile * jsPandaFile)415 DebugInfoExtractor *JSPandaFileManager::CpuProfilerGetJSPtExtractor(const JSPandaFile *jsPandaFile)
416 {
417     LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
418 
419     os::memory::LockHolder lock(jsPandaFileLock_);
420     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
421     if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
422         LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
423         UNREACHABLE();
424     }
425 
426     DebugInfoExtractor *extractor = nullptr;
427     auto iter = extractors_.find(jsPandaFile);
428     if (iter == extractors_.end()) {
429         auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
430         extractor = extractorPtr.get();
431         extractors_[jsPandaFile] = std::move(extractorPtr);
432     } else {
433         extractor = iter->second.get();
434     }
435 
436     extractor->Extract();
437     return extractor;
438 }
439 
GenerateJSPandaFile(JSThread * thread,const panda_file::File * pf,const CString & desc,std::string_view entryPoint)440 std::shared_ptr<JSPandaFile> JSPandaFileManager::GenerateJSPandaFile(JSThread *thread, const panda_file::File *pf,
441                                                                      const CString &desc, std::string_view entryPoint)
442 {
443     ASSERT(GetJSPandaFile(pf) == nullptr);
444     std::shared_ptr<JSPandaFile> newJsPandaFile = NewJSPandaFile(pf, desc);
445     EcmaVM *vm = thread->GetEcmaVM();
446 
447     CString methodName = entryPoint.data();
448     if (newJsPandaFile->IsBundlePack()) {
449         // entryPoint maybe is _GLOBAL::func_main_watch to execute func_main_watch
450         auto pos = entryPoint.find_last_of("::");
451         if (pos != std::string_view::npos) {
452             methodName = entryPoint.substr(pos + 1);
453         } else {
454             // default use func_main_0 as entryPoint
455             methodName = JSPandaFile::ENTRY_FUNCTION_NAME;
456         }
457     }
458     PandaFileTranslator::TranslateClasses(newJsPandaFile.get(), methodName);
459 
460     {
461         // For worker, JSPandaFile may be created by another vm.
462         os::memory::LockHolder lock(jsPandaFileLock_);
463         std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(desc);
464         if (jsPandaFile != nullptr) {
465             InsertJSPandaFileVmUnlocked(vm, jsPandaFile);
466             newJsPandaFile.reset();
467             return jsPandaFile;
468         } else {
469             AddJSPandaFileVm(vm, newJsPandaFile);
470             return newJsPandaFile;
471         }
472     }
473 }
474 
AllocateBuffer(size_t size)475 void *JSPandaFileManager::AllocateBuffer(size_t size)
476 {
477     return JSPandaFileAllocator::AllocateBuffer(size);
478 }
479 
AllocateBuffer(size_t size)480 void *JSPandaFileManager::JSPandaFileAllocator::AllocateBuffer(size_t size)
481 {
482     if (size == 0) {
483         LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
484         UNREACHABLE();
485     }
486     if (size >= MALLOC_SIZE_LIMIT) {
487         LOG_ECMA_MEM(FATAL) << "size must be less than the maximum";
488         UNREACHABLE();
489     }
490     // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
491     void *ptr = malloc(size);
492     if (ptr == nullptr) {
493         LOG_ECMA_MEM(FATAL) << "malloc failed";
494         UNREACHABLE();
495     }
496 #if ECMASCRIPT_ENABLE_ZAP_MEM
497     if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) {
498         LOG_ECMA_MEM(FATAL) << "memset_s failed";
499         UNREACHABLE();
500     }
501 #endif
502     return ptr;
503 }
504 
FreeBuffer(void * mem)505 void JSPandaFileManager::FreeBuffer(void *mem)
506 {
507     JSPandaFileAllocator::FreeBuffer(mem);
508 }
509 
FreeBuffer(void * mem)510 void JSPandaFileManager::JSPandaFileAllocator::FreeBuffer(void *mem)
511 {
512     if (mem == nullptr) {
513         return;
514     }
515     // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
516     free(mem);
517 }
518 }  // namespace panda::ecmascript
519