1/*
2 * Copyright (c) 2024 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/checkpoint/thread_state_transition.h"
19#include "ecmascript/jspandafile/abc_buffer_cache.h"
20#include "ecmascript/jspandafile/js_pandafile_executor.h"
21#include "ecmascript/module/module_path_helper.h"
22#include "ecmascript/module/module_message_helper.h"
23#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
24
25namespace panda::ecmascript {
26using PGOProfilerManager = pgo::PGOProfilerManager;
27static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options
28
29JSPandaFileManager *JSPandaFileManager::GetInstance()
30{
31    static JSPandaFileManager *jsFileManager = new JSPandaFileManager();
32    return jsFileManager;
33}
34
35JSPandaFileManager::~JSPandaFileManager()
36{
37    LockHolder lock(jsPandaFileLock_);
38    extractors_.clear();
39    oldJSPandaFiles_.clear();
40    loadedJSPandaFiles_.clear();
41}
42
43std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
44    std::string_view entryPoint, bool needUpdate)
45{
46    {
47        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            if (jsPandaFile == nullptr) {
59                jsPandaFile = GenerateJSPandafileFromBufferCache(thread, filename, entryPoint);
60            }
61        }
62        if (jsPandaFile != nullptr) {
63            return jsPandaFile;
64        }
65    }
66
67    EcmaVM *vm = thread->GetEcmaVM();
68    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
69    std::unique_ptr<const panda_file::File> pf;
70    if (!vm->IsBundlePack() && moduleManager->GetExecuteMode() == ModuleExecuteMode::ExecuteBufferMode &&
71        !vm->IsRestrictedWorkerThread()) {
72        ResolveBufferCallback resolveBufferCallback = vm->GetResolveBufferCallback();
73        if (resolveBufferCallback == nullptr) {
74#if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
75            LOG_NO_TAG(ERROR) << "[ArkRuntime Log] Importing shared package is not supported in the Previewer.";
76#endif
77            LOG_FULL(FATAL) << "resolveBufferCallback is nullptr";
78            return nullptr;
79        }
80        std::string hspPath = ModulePathHelper::ParseHapPath(filename);
81        if (hspPath.empty()) {
82            LOG_FULL(ERROR) << ModuleMessageHelper::VmModuleInfoMessage(thread);
83            if (!thread->IsMainThread()) {
84                CString msg = "Invalid input hsp path: " + filename;
85                THROW_TYPE_ERROR_AND_RETURN(thread, msg.c_str(), nullptr);
86            }
87            LOG_FULL(FATAL) << "Invalid input hsp path: " << filename;
88            return nullptr;
89        }
90        uint8_t *data = nullptr;
91        size_t dataSize = 0;
92        std::string errorMsg;
93        bool getBuffer = resolveBufferCallback(hspPath, &data, &dataSize, errorMsg);
94        if (!getBuffer) {
95#if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
96            LOG_NO_TAG(INFO) << "[ArkRuntime Log] Importing shared package in the Previewer.";
97#endif
98            LOG_FULL(FATAL) << "resolveBufferCallback get hsp buffer failed, hsp path:" << filename
99                << ", errorMsg:" << errorMsg;
100            return nullptr;
101        }
102#if defined(PANDA_TARGET_ANDROID) || defined(PANDA_TARGET_IOS)
103        pf = panda_file::OpenPandaFileFromMemory(data, dataSize);
104#else
105        pf = panda_file::OpenPandaFileFromSecureMemory(data, dataSize);
106#endif
107    } else if (vm->IsRestrictedWorkerThread()) {
108        // ReadOnly
109        pf = panda_file::OpenPandaFileOrZip(filename);
110    } else {
111        pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
112    }
113
114    if (pf == nullptr) {
115        LOG_ECMA(ERROR) << "open file " << filename << " error";
116        return nullptr;
117    }
118
119    std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), filename, entryPoint);
120#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
121    if (thread->GetIsProfiling()) {
122        GetJSPtExtractorAndExtract(jsPandaFile.get());
123    }
124#endif
125    return jsPandaFile;
126}
127
128// The security interface needs to be modified accordingly.
129std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
130    std::string_view entryPoint, const void *buffer, size_t size, bool needUpdate)
131{
132    if (buffer == nullptr || size == 0) {
133        LOG_FULL(ERROR) << "Input buffer is empty";
134        return nullptr;
135    }
136    {
137        LockHolder lock(jsPandaFileLock_);
138        std::shared_ptr<JSPandaFile> jsPandaFile;
139        if (needUpdate) {
140            auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
141            if (pf == nullptr) {
142                LOG_ECMA(ERROR) << "open file buffer " << filename << " error";
143                return nullptr;
144            }
145            jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
146        } else {
147            jsPandaFile = FindJSPandaFileUnlocked(filename);
148        }
149        if (jsPandaFile != nullptr) {
150            return jsPandaFile;
151        }
152    }
153#if defined(PANDA_TARGET_PREVIEW)
154    auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
155#else
156    CString tag = ModulePathHelper::ParseFileNameToVMAName(filename);
157    constexpr size_t PR_SET_VMA_ANON_NAME_MAX_LEN = 80;
158    constexpr size_t ANON_FLAG_LEN = 7; // [anon:]
159    if (tag.length() > PR_SET_VMA_ANON_NAME_MAX_LEN - ANON_FLAG_LEN) {
160        tag = CString(ModulePathHelper::VMA_NAME_ARKTS_CODE);
161    }
162    auto pf = panda_file::OpenPandaFileFromMemory(buffer, size, tag.c_str());
163#endif
164    if (pf == nullptr) {
165        LOG_ECMA(ERROR) << "open file " << filename << " error";
166        return nullptr;
167    }
168
169    // JSPandaFile desc cannot be empty, if buffer with empty filename, use pf filename as a descriptor.
170    const CString &desc = filename.empty() ? pf->GetFilename().c_str() : filename;
171
172    std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), desc, entryPoint);
173#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
174    if (thread->GetIsProfiling()) {
175        GetJSPtExtractorAndExtract(jsPandaFile.get());
176    }
177#endif
178    return jsPandaFile;
179}
180
181std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFileSecure(JSThread *thread, const CString &filename,
182    std::string_view entryPoint, uint8_t *buffer, size_t size, bool needUpdate)
183{
184    bool enableESMTrace = thread->GetEcmaVM()->GetJSOptions().EnableESMTrace();
185    if (enableESMTrace) {
186        ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, "JSPandaFileManager::LoadJSPandaFileSecure");
187    }
188    if (buffer == nullptr || size == 0) {
189        LOG_FULL(ERROR) << "Input buffer is empty";
190        return nullptr;
191    }
192    {
193        LockHolder lock(jsPandaFileLock_);
194        std::shared_ptr<JSPandaFile> jsPandaFile;
195        if (needUpdate) {
196            auto pf = panda_file::OpenPandaFileFromSecureMemory(buffer, size);
197            if (pf == nullptr) {
198                LOG_ECMA(ERROR) << "open file buffer " << filename << " error";
199                return nullptr;
200            }
201            jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
202        } else {
203            jsPandaFile = FindJSPandaFileUnlocked(filename);
204        }
205        if (jsPandaFile != nullptr) {
206            return jsPandaFile;
207        }
208    }
209
210    auto pf = panda_file::OpenPandaFileFromSecureMemory(buffer, size);
211    if (pf == nullptr) {
212        LOG_ECMA(ERROR) << "open file " << filename << " error";
213        return nullptr;
214    }
215
216    // JSPandaFile desc cannot be empty, if buffer with empty filename, use pf filename as a descriptor.
217    const CString &desc = filename.empty() ? pf->GetFilename().c_str() : filename;
218
219    std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), desc, entryPoint);
220#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
221    if (thread->GetIsProfiling()) {
222        GetJSPtExtractorAndExtract(jsPandaFile.get());
223    }
224#endif
225    if (enableESMTrace) {
226        ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK);
227    }
228    return jsPandaFile;
229}
230
231JSHandle<Program> JSPandaFileManager::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile,
232                                                      std::string_view entryPoint)
233{
234    ASSERT(GetJSPandaFile(jsPandaFile->GetPandaFile()) != nullptr);
235    return PandaFileTranslator::GenerateProgram(vm, jsPandaFile, entryPoint);
236}
237
238std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileWithChecksum(const CString &filename, uint32_t checksum)
239{
240    std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(filename);
241    if (jsPandaFile == nullptr) {
242        return nullptr;
243    }
244
245    if (checksum == jsPandaFile->GetChecksum()) {
246        return jsPandaFile;
247    }
248
249    LOG_FULL(INFO) << "reload " << filename << " with new checksum";
250    ObsoleteLoadedJSPandaFile(filename);
251    return nullptr;
252}
253
254std::shared_ptr<JSPandaFile> JSPandaFileManager::FindMergedJSPandaFile()
255{
256    LockHolder lock(jsPandaFileLock_);
257    for (const auto &iter : loadedJSPandaFiles_) {
258        const std::shared_ptr<JSPandaFile> &jsPandafile = iter.second;
259        if (jsPandafile->IsFirstMergedAbc()) {
260            return jsPandafile;
261        }
262    }
263    return nullptr;
264}
265
266std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileUnlocked(const CString &filename)
267{
268    if (filename.empty()) {
269        return nullptr;
270    }
271    const auto iter = loadedJSPandaFiles_.find(filename);
272    if (iter == loadedJSPandaFiles_.end()) {
273        return nullptr;
274    }
275    return iter->second;
276}
277
278std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileByNormalizedName(const CString &normalizedName)
279{
280    if (normalizedName.empty()) {
281        return nullptr;
282    }
283    std::shared_ptr<JSPandaFile> result;
284    EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
285        // normalize path inside and outside sandbox
286        if (file->GetNormalizedFileDesc() == normalizedName) {
287            result = file;
288            return false;
289        }
290        return true;
291    });
292    return result;
293}
294
295std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileByMapBase(uintptr_t mapBase)
296{
297    std::shared_ptr<JSPandaFile> result;
298    EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
299        if (reinterpret_cast<uintptr_t>(file->GetHeader()) == mapBase) {
300            result = file;
301            return false;
302        }
303        return true;
304    });
305    return result;
306}
307
308std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFile(const CString &filename)
309{
310    LockHolder lock(jsPandaFileLock_);
311    return FindJSPandaFileUnlocked(filename);
312}
313
314std::shared_ptr<JSPandaFile> JSPandaFileManager::GetJSPandaFile(const panda_file::File *pf)
315{
316    LockHolder lock(jsPandaFileLock_);
317    for (const auto &iter : loadedJSPandaFiles_) {
318        const std::shared_ptr<JSPandaFile> &jsPandafile = iter.second;
319        if (jsPandafile->GetPandaFile() == pf) {
320            return jsPandafile;
321        }
322    }
323    return nullptr;
324}
325
326void JSPandaFileManager::ClearNameMap()
327{
328    LockHolder lock(jsPandaFileLock_);
329    for (const auto &iter : loadedJSPandaFiles_) {
330        iter.second->ClearNameMap();
331    }
332}
333
334void JSPandaFileManager::AddJSPandaFile(const std::shared_ptr<JSPandaFile> &jsPandaFile)
335{
336    const auto &filename = jsPandaFile->GetJSPandaFileDesc();
337    LockHolder lock(jsPandaFileLock_);
338    if (loadedJSPandaFiles_.find(filename) != loadedJSPandaFiles_.end()) {
339        LOG_ECMA(FATAL) << "add failed, file already exist: " << filename;
340        UNREACHABLE();
341    }
342
343    loadedJSPandaFiles_[filename] = std::move(jsPandaFile);
344    JSPandaFileExecutor::BindPandaFileToAot(jsPandaFile.get());
345    LOG_ECMA(DEBUG) << "add file: " << filename;
346}
347
348void JSPandaFileManager::RemoveJSPandaFile(const JSPandaFile *jsPandaFile)
349{
350    if (jsPandaFile == nullptr) {
351        return;
352    }
353
354    LockHolder lock(jsPandaFileLock_);
355    auto iterOld = oldJSPandaFiles_.begin();
356    while (iterOld != oldJSPandaFiles_.end()) {
357        if (iterOld->get() == jsPandaFile) {
358            extractors_.erase(jsPandaFile);
359            oldJSPandaFiles_.erase(iterOld);
360            return;
361        }
362        iterOld++;
363    }
364    const auto &filename = jsPandaFile->GetJSPandaFileDesc();
365    auto iter = loadedJSPandaFiles_.find(filename);
366    if (iter != loadedJSPandaFiles_.end()) {
367        extractors_.erase(jsPandaFile);
368        // erase shared_ptr from map, the ref count -1.
369        loadedJSPandaFiles_.erase(iter);
370    }
371}
372
373void JSPandaFileManager::ObsoleteLoadedJSPandaFile(const CString &filename)
374{
375    auto iter = loadedJSPandaFiles_.find(filename);
376    ASSERT(iter != loadedJSPandaFiles_.end());
377    std::shared_ptr<JSPandaFile> &jsPandaFile = iter->second;
378    if (oldJSPandaFiles_.find(jsPandaFile) == oldJSPandaFiles_.end()) {
379        oldJSPandaFiles_.emplace(jsPandaFile);
380    }
381    loadedJSPandaFiles_.erase(iter);
382}
383
384std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFile(const CString &filename)
385{
386    return OpenJSPandaFile(filename, filename);
387}
388
389std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFile(const CString &filename, const CString &desc)
390{
391    auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
392    if (pf == nullptr) {
393        LOG_ECMA(ERROR) << "open file " << filename << " error";
394        return nullptr;
395    }
396
397    return NewJSPandaFile(pf.release(), desc);
398}
399
400std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFileFromBuffer(uint8_t *buffer,
401                                                                           size_t size,
402                                                                           const CString &filename)
403{
404    auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
405    if (pf == nullptr) {
406        LOG_ECMA(ERROR) << "open file " << filename << " error";
407        return nullptr;
408    }
409
410    return NewJSPandaFile(pf.release(), filename);
411}
412
413std::shared_ptr<JSPandaFile> JSPandaFileManager::NewJSPandaFile(const panda_file::File *pf, const CString &desc)
414{
415    std::shared_ptr<JSPandaFile> jsPandaFile = std::make_shared<JSPandaFile>(pf, desc);
416    PGOProfilerManager::GetInstance()->SamplePandaFileInfo(jsPandaFile->GetChecksum(),
417                                                           jsPandaFile->GetJSPandaFileDesc());
418    return jsPandaFile;
419}
420
421DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *jsPandaFile)
422{
423    LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
424
425    LockHolder lock(jsPandaFileLock_);
426    const auto &filename = jsPandaFile->GetJSPandaFileDesc();
427    if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
428        LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename
429            << " file addr is " << reinterpret_cast<uintptr_t>(jsPandaFile->GetHeader());
430        UNREACHABLE();
431    }
432
433    auto iter = extractors_.find(jsPandaFile);
434    if (iter == extractors_.end()) {
435        auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
436        DebugInfoExtractor *extractor = extractorPtr.get();
437        extractors_[jsPandaFile] = std::move(extractorPtr);
438        return extractor;
439    }
440
441    return iter->second.get();
442}
443
444DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractorAndExtract(const JSPandaFile *jsPandaFile)
445{
446    LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
447
448    LockHolder lock(jsPandaFileLock_);
449    const auto &filename = jsPandaFile->GetJSPandaFileDesc();
450    if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
451        LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
452        UNREACHABLE();
453    }
454
455    auto iter = extractors_.find(jsPandaFile);
456    if (iter == extractors_.end()) {
457        auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
458        DebugInfoExtractor *extractor = extractorPtr.get();
459        extractor->Extract();
460        extractors_[jsPandaFile] = std::move(extractorPtr);
461        return extractor;
462    }
463
464    return iter->second.get();
465}
466
467DebugInfoExtractor *JSPandaFileManager::CpuProfilerGetJSPtExtractor(const JSPandaFile *jsPandaFile)
468{
469    LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
470
471    LockHolder lock(jsPandaFileLock_);
472    const auto &filename = jsPandaFile->GetJSPandaFileDesc();
473    if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
474        LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
475        UNREACHABLE();
476    }
477
478    DebugInfoExtractor *extractor = nullptr;
479    auto iter = extractors_.find(jsPandaFile);
480    if (iter == extractors_.end()) {
481        auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
482        extractor = extractorPtr.get();
483        extractors_[jsPandaFile] = std::move(extractorPtr);
484    } else {
485        extractor = iter->second.get();
486    }
487
488    extractor->Extract();
489    return extractor;
490}
491
492std::string GetModuleNameFromDesc(const std::string &desc)
493{
494    /*
495    handle desc like:
496    case1: /data/storage/el1/bundle/entry/ets/modules.abc -> entry/ets/modules.abc
497    case2: /data/storage/el1/bundle/entry/ets/widgets.abc -> entry/ets/widgets.abc
498    case3: /data/app/el1/bundle/public/com.xx.xx/entry/ets/modules.abc -> entry/ets/modules.abc
499    case4: /data/app/el1/bundle/public/com.xx.xx/entry/ets/widgets.abc -> entry/ets/widgets.abc
500    */
501    auto lastSlash = desc.rfind("/");
502    if (lastSlash == std::string::npos) {
503        LOG_ECMA(DEBUG) << "GetModuleNameFromDesc can't find fisrt /: " << desc;
504        return "";
505    }
506    ASSERT(lastSlash > 0);
507    auto secondLastSlash = desc.rfind("/", lastSlash - 1);
508    if (secondLastSlash == std::string::npos) {
509        LOG_ECMA(DEBUG) << "GetModuleNameFromDesc can't find second /: " << desc;
510        return "";
511    }
512    ASSERT(secondLastSlash > 0);
513    auto thirdLastSlash = desc.rfind("/", secondLastSlash - 1);
514    if (thirdLastSlash == std::string::npos) {
515        LOG_ECMA(DEBUG) << "GetModuleNameFromDesc can't find third /: " << desc;
516        return "";
517    }
518    // get moduleName from thirdLastSlash to secondLastSlash
519    return desc.substr(thirdLastSlash + 1, secondLastSlash - thirdLastSlash - 1);
520}
521
522std::shared_ptr<JSPandaFile> JSPandaFileManager::GenerateJSPandaFile(JSThread *thread, const panda_file::File *pf,
523                                                                     const CString &desc, std::string_view entryPoint)
524{
525    ThreadNativeScope nativeScope(thread);
526    ASSERT(GetJSPandaFile(pf) == nullptr);
527    std::shared_ptr<JSPandaFile> newJsPandaFile = NewJSPandaFile(pf, desc);
528    EcmaVM *vm = thread->GetEcmaVM();
529
530    std::string moduleName = GetModuleNameFromDesc(desc.c_str());
531    std::string hapPath;
532    SearchHapPathCallBack callback = vm->GetSearchHapPathCallBack();
533    if (callback) {
534        callback(moduleName, hapPath);
535        LOG_ECMA(DEBUG) << "SearchHapPathCallBack moduleName: " << moduleName
536                        << ", fileName:" << desc << ", hapPath: " << hapPath;
537        newJsPandaFile->SetHapPath(hapPath.c_str());
538    }
539
540    CString methodName = entryPoint.data();
541    if (newJsPandaFile->IsBundlePack()) {
542        // entryPoint maybe is _GLOBAL::func_main_watch to execute func_main_watch
543        auto pos = entryPoint.find_last_of("::");
544        if (pos != std::string_view::npos) {
545            methodName = entryPoint.substr(pos + 1);
546        } else {
547            // default use func_main_0 as entryPoint
548            methodName = JSPandaFile::ENTRY_FUNCTION_NAME;
549        }
550    }
551    if (newJsPandaFile->IsNewVersion() && vm->IsAsynTranslateClasses()) {
552        newJsPandaFile->TranslateClasses(thread, methodName);
553    } else {
554        PandaFileTranslator::TranslateClasses(thread, newJsPandaFile.get(), methodName);
555    }
556
557    {
558        LockHolder lock(jsPandaFileLock_);
559        std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(desc);
560        if (jsPandaFile != nullptr) {
561            newJsPandaFile.reset();
562            return jsPandaFile;
563        } else {
564            AddJSPandaFile(newJsPandaFile);
565            return newJsPandaFile;
566        }
567    }
568}
569
570/*
571 * Check whether the file path can be loaded into pandafile, excluding bundle packaging and decompression paths
572 */
573bool JSPandaFileManager::CheckFilePath(JSThread *thread, const CString &fileName)
574{
575    std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(fileName);
576    if (jsPandaFile != nullptr) {
577        return true;
578    }
579    EcmaVM *vm = thread->GetEcmaVM();
580    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
581    if (!vm->IsBundlePack() && moduleManager->GetExecuteMode() == ModuleExecuteMode::ExecuteBufferMode) {
582        ResolveBufferCallback resolveBufferCallback = vm->GetResolveBufferCallback();
583        if (resolveBufferCallback == nullptr) {
584            LOG_FULL(ERROR) << "When checking file path, resolveBufferCallback is nullptr";
585            return false;
586        }
587        uint8_t *data = nullptr;
588        size_t dataSize = 0;
589        std::string errorMsg;
590        bool getBuffer = resolveBufferCallback(ModulePathHelper::ParseHapPath(fileName), &data, &dataSize, errorMsg);
591        if (!getBuffer) {
592            LOG_FULL(ERROR)
593                << "When checking file path, resolveBufferCallback get buffer failed, errorMsg = " << errorMsg;
594            return false;
595        }
596    }
597    return true;
598}
599
600std::shared_ptr<JSPandaFile> JSPandaFileManager::GenerateJSPandafileFromBufferCache(
601    JSThread *thread, const CString &filename, std::string_view entryPoint)
602{
603    AbcBufferInfo bufferInfo =
604        thread->GetCurrentEcmaContext()->GetAbcBufferCache()->FindJSPandaFileInAbcBufferCache(filename);
605    if (bufferInfo.buffer_ == nullptr) {
606        return nullptr;
607    }
608    LOG_FULL(INFO) << "fileName was found in bufferFiles_.";
609    JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance();
610    if (bufferInfo.bufferType_ == AbcBufferType::SECURE_BUFFER) {
611        return jsPandaFileManager->LoadJSPandaFileSecure(
612            thread, filename, entryPoint, reinterpret_cast<uint8_t *>(bufferInfo.buffer_), bufferInfo.size_);
613    }
614    return jsPandaFileManager->LoadJSPandaFile(
615        thread, filename, entryPoint, bufferInfo.buffer_, bufferInfo.size_);
616}
617
618void *JSPandaFileManager::AllocateBuffer(size_t size)
619{
620    return JSPandaFileAllocator::AllocateBuffer(size);
621}
622
623void *JSPandaFileManager::JSPandaFileAllocator::AllocateBuffer(size_t size)
624{
625    if (size == 0) {
626        LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
627        UNREACHABLE();
628    }
629    if (size >= MALLOC_SIZE_LIMIT) {
630        LOG_ECMA_MEM(FATAL) << "size must be less than the maximum";
631        UNREACHABLE();
632    }
633    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
634    void *ptr = malloc(size);
635    if (ptr == nullptr) {
636        LOG_ECMA_MEM(FATAL) << "malloc failed";
637        UNREACHABLE();
638    }
639#if ECMASCRIPT_ENABLE_ZAP_MEM
640    if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) {
641        LOG_ECMA_MEM(FATAL) << "memset_s failed";
642        UNREACHABLE();
643    }
644#endif
645    return ptr;
646}
647
648void JSPandaFileManager::FreeBuffer(void *mem)
649{
650    JSPandaFileAllocator::FreeBuffer(mem);
651}
652
653void JSPandaFileManager::JSPandaFileAllocator::FreeBuffer(void *mem)
654{
655    if (mem == nullptr) {
656        return;
657    }
658    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
659    free(mem);
660}
661}  // namespace panda::ecmascript
662