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_executor.h"
17
18#include "ecmascript/js_file_path.h"
19#include "ecmascript/jspandafile/abc_buffer_cache.h"
20#include "ecmascript/jspandafile/program_object.h"
21#include "ecmascript/module/module_path_helper.h"
22#include "ecmascript/checkpoint/thread_state_transition.h"
23
24namespace panda::ecmascript {
25using PathHelper = base::PathHelper;
26
27// use "@bundle" as ohmurl's rules, will be abandon later
28std::pair<CString, CString> JSPandaFileExecutor::ParseAbcEntryPoint(JSThread *thread, const CString &filename,
29    [[maybe_unused]] std::string_view entryPoint)
30{
31    CString name;
32    CString entry;
33    [[maybe_unused]] EcmaVM *vm = thread->GetEcmaVM();
34#if defined(PANDA_TARGET_LINUX) || defined(OHOS_UNIT_TEST) || defined(PANDA_TARGET_MACOS)
35    return {filename, entryPoint.data()};
36#else
37    CString normalName = PathHelper::NormalizePath(filename);
38    ModulePathHelper::ParseAbcPathAndOhmUrl(vm, normalName, name, entry);
39#if !defined(PANDA_TARGET_WINDOWS)
40    if (name.empty()) {
41        name = vm->GetAssetPath();
42    }
43#elif defined(PANDA_TARGET_WINDOWS)
44    CString assetPath = vm->GetAssetPath();
45    name = assetPath + "\\" + JSPandaFile::MERGE_ABC_NAME;
46#else
47    CString assetPath = vm->GetAssetPath();
48    name = assetPath + "/" + JSPandaFile::MERGE_ABC_NAME;
49#endif
50#endif
51    return std::make_pair(name, entry);
52}
53
54Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromFile(JSThread *thread, const CString &name,
55    CString entry, bool needUpdate, bool executeFromJob)
56{
57    EcmaVM *vm = thread->GetEcmaVM();
58
59    std::shared_ptr<JSPandaFile> jsPandaFile =
60        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry, needUpdate);
61    if (jsPandaFile == nullptr) {
62#ifdef FUZZ_TEST
63        CString msg = "jsPandaFile is nullptr";
64        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
65#else
66        LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << name;
67#endif
68    }
69    // If it is an old record, delete the bundleName and moduleName
70    if (!jsPandaFile->IsBundlePack() && !vm->IsNormalizedOhmUrlPack() && !executeFromJob &&
71        !vm->GetBundleName().empty()) {
72        jsPandaFile->CheckIsRecordWithBundleName(entry);
73        if (!jsPandaFile->IsRecordWithBundleName()) {
74            PathHelper::AdaptOldIsaRecord(entry);
75        }
76    }
77
78    JSRecordInfo *recordInfo = nullptr;
79    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, &recordInfo);
80    if (!hasRecord) {
81        CString msg = "Cannot find module '" + entry + "' , which is application Entry Point";
82        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
83    }
84    if (jsPandaFile->IsModule(recordInfo)) {
85        ThreadManagedScope managedScope(thread);
86        SharedModuleManager* sharedModuleManager = SharedModuleManager::GetInstance();
87        JSHandle<JSTaggedValue> moduleRecord(thread->GlobalConstants()->GetHandledUndefined());
88        if (jsPandaFile->IsBundlePack()) {
89            moduleRecord = sharedModuleManager->ResolveImportedModule(thread, name, executeFromJob);
90        } else {
91            moduleRecord = sharedModuleManager->ResolveImportedModuleWithMerge(thread, name, entry, executeFromJob);
92        }
93
94        SourceTextModule::Instantiate(thread, moduleRecord, executeFromJob);
95        if (thread->HasPendingException()) {
96            return Unexpected(false);
97        }
98        JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
99        module->SetStatus(ModuleStatus::INSTANTIATED);
100        SourceTextModule::Evaluate(thread, module, nullptr, 0, executeFromJob);
101        if (thread->HasPendingException()) {
102            return Unexpected(false);
103        }
104        return JSTaggedValue::Undefined();
105    }
106    return JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entry.c_str(), executeFromJob);
107}
108
109Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromAbsolutePathAbcFile(JSThread *thread,
110    const CString &filename, std::string_view entryPoint, bool needUpdate, bool executeFromJob)
111{
112    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteFromAbsolutePathAbcFile filename " << filename;
113    CString traceInfo = "JSPandaFileExecutor::ExecuteFromAbsolutePathAbcFile " + filename;
114    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
115    CString entry = entryPoint.data();
116    CString name = filename;
117
118    return ExecuteFromFile(thread, name, entry, needUpdate, executeFromJob);
119}
120
121Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromAbcFile(JSThread *thread, const CString &filename,
122    std::string_view entryPoint, bool needUpdate, bool executeFromJob)
123{
124    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteFromAbcFile filename " << filename;
125    CString traceInfo = "JSPandaFileExecutor::ExecuteFromAbcFile " + filename;
126    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
127    CString entry;
128    CString name;
129    EcmaVM *vm = thread->GetEcmaVM();
130    if (!vm->IsBundlePack() && !executeFromJob) {
131        std::tie(name, entry) = ParseAbcEntryPoint(thread, filename, entryPoint);
132    } else {
133        name = filename;
134        entry = entryPoint.data();
135    }
136
137    return ExecuteFromFile(thread, name, entry, needUpdate, executeFromJob);
138}
139
140// The security interface needs to be modified accordingly.
141Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromBuffer(JSThread *thread,
142    const void *buffer, size_t size, std::string_view entryPoint, const CString &filename, bool needUpdate,
143    bool executeFromJob)
144{
145    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteFromBuffer filename " << filename;
146    CString traceInfo = "JSPandaFileExecutor::ExecuteFromBuffer " + filename;
147    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
148    CString normalName = PathHelper::NormalizePath(filename);
149    std::shared_ptr<JSPandaFile> jsPandaFile =
150        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, normalName, entryPoint, buffer, size, needUpdate);
151    if (jsPandaFile == nullptr) {
152#ifdef FUZZ_TEST
153        CString msg = "jsPandaFile is nullptr";
154        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
155#else
156        LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << normalName;
157#endif
158    }
159    AbcBufferCacheScope bufferScope(thread, normalName, buffer, size, AbcBufferType::NORMAL_BUFFER);
160    auto vm = thread->GetEcmaVM();
161
162    CString entry = entryPoint.data();
163    if (vm->IsNormalizedOhmUrlPack()) {
164        entry = ModulePathHelper::TransformToNormalizedOhmUrl(vm, filename, normalName, entry);
165    }
166    JSRecordInfo *recordInfo = nullptr;
167    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, &recordInfo);
168    if (!hasRecord) {
169        CString msg = "Cannot find module '" + entry + "' , which is application Entry Point";
170        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
171    }
172    if (jsPandaFile->IsModule(recordInfo)) {
173        bool isBundle = jsPandaFile->IsBundlePack();
174        return CommonExecuteBuffer(thread, isBundle, normalName, entry, buffer, size, executeFromJob);
175    }
176    return JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entry, executeFromJob);
177}
178
179// The security interface needs to be modified accordingly.
180Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteModuleBuffer(
181    JSThread *thread, const void *buffer, size_t size, const CString &filename, bool needUpdate)
182{
183    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteModuleBuffer filename " << filename;
184    CString traceInfo = "JSPandaFileExecutor::ExecuteModuleBuffer " + filename;
185    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
186    CString name;
187    CString entry;
188    EcmaVM *vm = thread->GetEcmaVM();
189#if !defined(PANDA_TARGET_WINDOWS)
190    name = vm->GetAssetPath();
191#elif defined(PANDA_TARGET_WINDOWS)
192    CString assetPath = vm->GetAssetPath();
193    name = assetPath + "\\" + JSPandaFile::MERGE_ABC_NAME;
194#else
195    CString assetPath = vm->GetAssetPath();
196    name = assetPath + "/" + JSPandaFile::MERGE_ABC_NAME;
197#endif
198    CString normalName = PathHelper::NormalizePath(filename);
199    ModulePathHelper::ParseAbcPathAndOhmUrl(vm, normalName, name, entry);
200    std::shared_ptr<JSPandaFile> jsPandaFile =
201        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry, buffer, size, needUpdate);
202    if (jsPandaFile == nullptr) {
203#ifdef FUZZ_TEST
204        CString msg = "jsPandaFile is nullptr";
205        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
206#else
207        LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << name;
208#endif
209    }
210    AbcBufferCacheScope bufferScope(thread, name, buffer, size, AbcBufferType::NORMAL_BUFFER);
211    bool isBundle = jsPandaFile->IsBundlePack();
212
213    // realEntry is used to record the original record, which is easy to throw when there are exceptions
214    const CString realEntry = entry;
215    if (vm->IsNormalizedOhmUrlPack()) {
216        entry = ModulePathHelper::TransformToNormalizedOhmUrl(vm, filename, name, entry);
217    } else if (!isBundle) {
218        jsPandaFile->CheckIsRecordWithBundleName(entry);
219        if (!jsPandaFile->IsRecordWithBundleName()) {
220            PathHelper::AdaptOldIsaRecord(entry);
221        }
222    }
223    JSRecordInfo *recordInfo = nullptr;
224    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, &recordInfo);
225    if (!hasRecord) {
226        CString msg = "Cannot find module '" + realEntry + "' , which is application Entry Point";
227        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
228    }
229    if (!jsPandaFile->IsModule(recordInfo)) {
230        LOG_ECMA(FATAL) << "Input file is not esmodule";
231    }
232    return CommonExecuteBuffer(thread, isBundle, name, entry, buffer, size);
233}
234
235// The security interface needs to be modified accordingly.
236Expected<JSTaggedValue, bool> JSPandaFileExecutor::CommonExecuteBuffer(JSThread *thread,
237    bool isBundle, const CString &filename, const CString &entry, const void *buffer, size_t size, bool executeFromJob)
238{
239    [[maybe_unused]] EcmaHandleScope scope(thread);
240    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
241    moduleManager->SetExecuteMode(ModuleExecuteMode::ExecuteBufferMode);
242    JSMutableHandle<JSTaggedValue> moduleRecord(thread, thread->GlobalConstants()->GetUndefined());
243    if (isBundle) {
244        moduleRecord.Update(moduleManager->HostResolveImportedModule(buffer, size, filename));
245    } else {
246        moduleRecord.Update(moduleManager->HostResolveImportedModuleWithMerge(filename, entry, executeFromJob));
247    }
248
249    SourceTextModule::Instantiate(thread, moduleRecord, executeFromJob);
250    if (thread->HasPendingException()) {
251        return Unexpected(false);
252    }
253
254    JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
255    module->SetStatus(ModuleStatus::INSTANTIATED);
256    SourceTextModule::Evaluate(thread, module, buffer, size, executeFromJob);
257    if (thread->HasPendingException()) {
258        return Unexpected(false);
259    }
260    return JSTaggedValue::Undefined();
261}
262
263Expected<JSTaggedValue, bool> JSPandaFileExecutor::Execute(JSThread *thread, const JSPandaFile *jsPandaFile,
264                                                           std::string_view entryPoint, bool executeFromJob)
265{
266    ThreadManagedScope managedScope(thread);
267    bool enableESMTrace = thread->GetEcmaVM()->GetJSOptions().EnableESMTrace();
268    if (enableESMTrace) {
269        CString traceInfo = "FileExecute: " + CString(entryPoint);
270        ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, traceInfo.c_str());
271    }
272    // For Ark application startup
273    EcmaContext *context = thread->GetCurrentEcmaContext();
274
275    Expected<JSTaggedValue, bool> result;
276
277    if (context->GetStageOfHotReload() == StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN) {
278        result = context->InvokeEcmaEntrypointForHotReload(jsPandaFile, entryPoint, executeFromJob);
279    } else {
280        QuickFixManager *quickFixManager = thread->GetEcmaVM()->GetQuickFixManager();
281        quickFixManager->LoadPatchIfNeeded(thread, jsPandaFile);
282
283        result = context->InvokeEcmaEntrypoint(jsPandaFile, entryPoint, executeFromJob);
284    }
285    if (enableESMTrace) {
286        ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK);
287    }
288    return result;
289}
290
291void JSPandaFileExecutor::BindPreloadedPandaFilesToAOT(EcmaVM *vm, const std::string &moduleName)
292{
293    ASSERT(vm->GetJSThread()->IsMainThread());
294    if (!vm->GetJSOptions().GetEnableAsmInterpreter()) {
295        return;
296    }
297    // run not via command line
298    if (vm->GetJSOptions().WasAOTOutputFileSet()) {
299        return;
300    }
301    ASSERT(!moduleName.empty());
302    // bind pandafiles loaded in appspawn
303    vm->GetAOTFileManager()->BindPreloadedPandaFilesInAotFile(moduleName);
304}
305
306void JSPandaFileExecutor::BindPandaFileToAot(JSPandaFile *jsPandaFile)
307{
308    EcmaVM *vm = Runtime::GetInstance()->GetMainThread()->GetEcmaVM();
309    if (vm->GetJSOptions().GetEnableAsmInterpreter()) {
310        std::string aotFileBaseName(vm->GetModuleName());
311        auto *aotFM = vm->GetAOTFileManager();
312        if (vm->GetJSOptions().WasAOTOutputFileSet()) {
313            std::string aotFilename = vm->GetJSOptions().GetAOTOutputFile();
314            aotFileBaseName = JSFilePath::GetBaseName(aotFilename);
315        }
316        aotFM->BindPandaFileInAotFile(aotFileBaseName, jsPandaFile);
317    }
318}
319
320Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromBufferSecure(JSThread *thread, uint8_t *buffer,
321    size_t size, std::string_view entryPoint, const CString &filename, bool needUpdate)
322{
323    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteFromBufferSecure with secure buffer filename " << filename;
324    CString traceInfo = "JSPandaFileExecutor::ExecuteFromBufferSecure " + filename;
325    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
326    CString normalName = PathHelper::NormalizePath(filename);
327    std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->
328        LoadJSPandaFileSecure(thread, normalName, entryPoint, buffer, size, needUpdate);
329    if (jsPandaFile == nullptr) {
330#ifdef FUZZ_TEST
331        CString msg = "jsPandaFile is nullptr";
332        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
333#else
334        LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << normalName;
335#endif
336    }
337    AbcBufferCacheScope bufferScope(thread, normalName, buffer, size, AbcBufferType::SECURE_BUFFER);
338    auto vm = thread->GetEcmaVM();
339
340    CString entry = entryPoint.data();
341    if (vm->IsNormalizedOhmUrlPack()) {
342        entry = ModulePathHelper::TransformToNormalizedOhmUrl(vm, filename, normalName, entry);
343    }
344    JSRecordInfo *recordInfo = nullptr;
345    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, &recordInfo);
346    if (!hasRecord) {
347        CString msg = "Cannot find module '" + entry + "' , which is application Entry Point";
348        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
349    }
350    if (jsPandaFile->IsModule(recordInfo)) {
351        return CommonExecuteBuffer(thread, normalName, entry, jsPandaFile.get());
352    }
353    return JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entry);
354}
355
356Expected<JSTaggedValue, bool> JSPandaFileExecutor::CommonExecuteBuffer(JSThread *thread, const CString &filename,
357    const CString &entry, const JSPandaFile *jsPandaFile)
358{
359    [[maybe_unused]] EcmaHandleScope scope(thread);
360    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
361    moduleManager->SetExecuteMode(ModuleExecuteMode::ExecuteBufferMode);
362    JSMutableHandle<JSTaggedValue> moduleRecord(thread, thread->GlobalConstants()->GetUndefined());
363    if (jsPandaFile->IsBundlePack()) {
364        moduleRecord.Update(moduleManager->HostResolveImportedModule(jsPandaFile, filename));
365    } else {
366        moduleRecord.Update(moduleManager->HostResolveImportedModuleWithMerge(filename, entry));
367    }
368
369    SourceTextModule::Instantiate(thread, moduleRecord);
370    if (thread->HasPendingException()) {
371        return Unexpected(false);
372    }
373
374    JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
375    module->SetStatus(ModuleStatus::INSTANTIATED);
376    SourceTextModule::Evaluate(thread, module, nullptr, 0);
377    if (thread->HasPendingException()) {
378        return Unexpected(false);
379    }
380    return JSTaggedValue::Undefined();
381}
382
383Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteModuleBufferSecure(JSThread *thread, uint8_t *buffer,
384    size_t size, const CString &filename, bool needUpdate)
385{
386    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteModuleBufferSecure with secure buffer filename " << filename;
387    CString traceInfo = "JSPandaFileExecutor::ExecuteModuleBufferSecure " + filename;
388    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
389    CString name;
390    EcmaVM *vm = thread->GetEcmaVM();
391#if !defined(PANDA_TARGET_WINDOWS)
392    name = vm->GetAssetPath();
393#elif defined(PANDA_TARGET_WINDOWS)
394    CString assetPath = vm->GetAssetPath();
395    name = assetPath + "\\" + JSPandaFile::MERGE_ABC_NAME;
396#else
397    CString assetPath = vm->GetAssetPath();
398    name = assetPath + "/" + JSPandaFile::MERGE_ABC_NAME;
399#endif
400    CString entry;
401    CString normalName = PathHelper::NormalizePath(filename);
402    ModulePathHelper::ParseAbcPathAndOhmUrl(vm, normalName, name, entry);
403    std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->
404        LoadJSPandaFileSecure(thread, name, entry, buffer, size, needUpdate);
405    if (jsPandaFile == nullptr) {
406#ifdef FUZZ_TEST
407        CString msg = "jsPandaFile is nullptr";
408        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
409#else
410        LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << name;
411#endif
412    }
413    AbcBufferCacheScope bufferScope(thread, name, buffer, size, AbcBufferType::SECURE_BUFFER);
414    // realEntry is used to record the original record, which is easy to throw when there are exceptions
415    const CString realEntry = entry;
416    if (vm->IsNormalizedOhmUrlPack()) {
417        entry = ModulePathHelper::TransformToNormalizedOhmUrl(vm, filename, name, entry);
418    } else if (!jsPandaFile->IsBundlePack()) {
419        jsPandaFile->CheckIsRecordWithBundleName(entry);
420        if (!jsPandaFile->IsRecordWithBundleName()) {
421            PathHelper::AdaptOldIsaRecord(entry);
422        }
423    }
424
425    // will be refactored, temporarily use the function IsModule to verify realEntry
426    JSRecordInfo *recordInfo = nullptr;
427    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, &recordInfo);
428    if (!hasRecord) {
429        CString msg = "Cannot find module '" + realEntry + "' , which is application Entry Point";
430        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
431    }
432    if (!jsPandaFile->IsModule(recordInfo)) {
433        LOG_ECMA(FATAL) << "Input file is not esmodule";
434    }
435    return CommonExecuteBuffer(thread, name, entry, jsPandaFile.get());
436}
437
438/*
439 * filename: data/storage/el1/bundle/moduleName/ets/modules.abc
440 * Ohmurl:   1. @bundle:bundleName/moduleName@namespace/ets/pages/Index
441 *           2. @package:pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx
442 *           3. @normalized:N&moduleName&bundleName&entryPath&version
443 *           4. @normalized:N&moduleName&bundleName&entryPath&
444 */
445Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteSecureWithOhmUrl(JSThread *thread, uint8_t *buffer,
446    size_t size, const CString &filename, const CString &entryPoint)
447{
448    LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteSecureWithOhmUrl with secure buffer filename:" << filename <<
449                        ", entryPoint:" << entryPoint;
450    CString traceInfo = "JSPandaFileExecutor::ExecuteSecureWithOhmUrl " + filename;
451    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
452
453    std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->
454        LoadJSPandaFileSecure(thread, filename, entryPoint, buffer, size);
455    if (jsPandaFile == nullptr) {
456#ifdef FUZZ_TEST
457        CString msg = "jsPandaFile is nullptr";
458        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
459#else
460        LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << filename <<
461                           ", entrypoint is:" << entryPoint;
462#endif
463    }
464    AbcBufferCacheScope bufferScope(thread, filename, buffer, size, AbcBufferType::SECURE_BUFFER);
465    JSRecordInfo *recordInfo = nullptr;
466    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entryPoint, &recordInfo);
467    if (!hasRecord) {
468        CString msg = "Cannot find module '" + entryPoint + "' , which is application Entry Point";
469        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
470    }
471    return CommonExecuteBuffer(thread, filename, entryPoint, jsPandaFile.get());
472}
473
474Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteSpecialModule(JSThread *thread, const CString &recordName,
475    const CString &filename, const JSPandaFile *jsPandaFile, const JSRecordInfo* recordInfo)
476{
477    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
478
479    if (jsPandaFile->IsCjs(recordInfo)) {
480        moduleManager->ExecuteCjsModule(thread, recordName, jsPandaFile);
481        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false));
482        return JSTaggedValue::Undefined();
483    }
484    if (jsPandaFile->IsJson(recordInfo)) {
485        moduleManager->ExecuteJsonModule(thread, recordName, filename, jsPandaFile);
486        return JSTaggedValue::Undefined();
487    }
488    UNREACHABLE();
489    LOG_FULL(FATAL) << "this branch is unreachable";
490}
491
492// RecordName is the ohmurl-path of js files.
493// The first js file executed could be json, cjs, native so or esm.
494Expected<JSTaggedValue, bool> JSPandaFileExecutor::LazyExecuteModule(
495    JSThread *thread, CString &recordName, const CString &filename, bool isMergedAbc)
496{
497    LOG_FULL(INFO) << "recordName : " << recordName << ", in abc : " << filename;
498    CString traceInfo = "JSPandaFileExecutor::LazyExecuteModule " + filename;
499    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
500    CString newFileName = filename;
501    if (newFileName.empty()) {
502        newFileName = filename;
503    }
504    std::shared_ptr<JSPandaFile> jsPandaFile =
505        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, newFileName, recordName);
506    if (jsPandaFile == nullptr) {
507#ifdef FUZZ_TEST
508        CString msg = "jsPandaFile is nullptr";
509        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
510#else
511        LOG_FULL(FATAL) << "Load file with filename '" << newFileName << "' failed, ";
512#endif
513    }
514
515    // resolve native module
516    auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(recordName);
517    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
518    if (isNative) {
519        moduleManager->ExecuteNativeModule(thread, recordName);
520        return JSTaggedValue::Undefined();
521    }
522
523    if (isMergedAbc && !jsPandaFile->HasRecord(recordName)) {
524        CString msg = "cannot find record '" + recordName + "', in lazy load abc: " + newFileName;
525        THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
526    }
527
528    const JSRecordInfo* recordInfo = jsPandaFile->GetRecordInfo(recordName);
529    if (!jsPandaFile->IsModule(recordInfo)) {
530        return JSPandaFileExecutor::ExecuteSpecialModule(thread, recordName, newFileName, jsPandaFile.get(),
531            recordInfo);
532    }
533    [[maybe_unused]] EcmaHandleScope scope(thread);
534    // The first js file should execute at current vm.
535    JSHandle<JSTaggedValue> moduleRecord(thread->GlobalConstants()->GetHandledUndefined());
536    if (isMergedAbc) {
537        moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(newFileName, recordName);
538    } else {
539        moduleRecord = moduleManager->HostResolveImportedModule(newFileName);
540    }
541    SourceTextModule::Instantiate(thread, moduleRecord);
542    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false));
543    JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
544    SourceTextModule::Evaluate(thread, module, nullptr, 0);
545    return JSTaggedValue::Undefined();
546}
547
548int JSPandaFileExecutor::ExecuteAbcFileWithSingletonPatternFlag(JSThread *thread,
549    [[maybe_unused]] const CString &bundleName, const CString &moduleName, const CString &entry,
550    bool isSingletonPattern)
551{
552    CString abcFilePath = ModulePathHelper::ConcatPandaFilePath(moduleName);
553    std::shared_ptr<JSPandaFile> jsPandaFile =
554        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, abcFilePath, entry);
555    if (jsPandaFile == nullptr) {
556        LOG_ECMA(ERROR) << "When the route jump, loading panda file failed. Current file is " << abcFilePath;
557        return ROUTE_URI_ERROR;
558    }
559    CString entryPoint = ModulePathHelper::ConcatFileNameWithMerge(thread, jsPandaFile.get(),
560        abcFilePath, "", entry);
561    JSRecordInfo *recordInfo = nullptr;
562    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entryPoint, &recordInfo);
563    if (!hasRecord) {
564        LOG_ECMA(ERROR) << "When the route jump, Cannot find module '" << entryPoint << "'";
565        return ROUTE_URI_ERROR;
566    }
567    ASSERT(jsPandaFile->IsModule(recordInfo));
568    [[maybe_unused]] EcmaHandleScope scope(thread);
569    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
570    JSHandle<JSTaggedValue> moduleRecord(thread->GlobalConstants()->GetHandledUndefined());
571    ASSERT(!jsPandaFile->IsBundlePack());
572    moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(abcFilePath, entryPoint);
573    SourceTextModule::Instantiate(thread, moduleRecord);
574    if (thread->HasPendingException()) {
575        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ROUTE_INTERNAL_ERROR);
576    }
577    JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
578    if (!isSingletonPattern) {
579        LOG_ECMA(INFO) << "Route jump to non-singleton page: " << entryPoint;
580        module->SetStatus(ModuleStatus::INSTANTIATED);
581    } else {
582        LOG_ECMA(INFO) << "Route jump to singleton page: " << entryPoint;
583    }
584    SourceTextModule::Evaluate(thread, module, nullptr, 0);
585    if (thread->HasPendingException()) {
586        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ROUTE_INTERNAL_ERROR);
587    }
588    return ROUTE_SUCCESS;
589}
590
591bool JSPandaFileExecutor::IsExecuteModuleInAbcFile(JSThread *thread, [[maybe_unused]] const CString &bundleName,
592    const CString &moduleName, const CString &entry)
593{
594    CString abcFilePath = ModulePathHelper::ConcatPandaFilePath(moduleName);
595    bool isValid = JSPandaFileManager::GetInstance()->CheckFilePath(thread, abcFilePath);
596    if (!isValid) {
597        return false;
598    }
599    std::shared_ptr<JSPandaFile> jsPandaFile =
600        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, abcFilePath, entry);
601    if (jsPandaFile == nullptr) {
602        LOG_ECMA(ERROR) << "When checking if module is in abc file, loading panda file failed. Current file is " <<
603            abcFilePath;
604        return false;
605    }
606    CString entryPoint = ModulePathHelper::ConcatFileNameWithMerge(thread, jsPandaFile.get(),
607        abcFilePath, "", entry);
608    JSRecordInfo *recordInfo = nullptr;
609    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entryPoint, &recordInfo);
610    if (!hasRecord) {
611        LOG_ECMA(ERROR) << "When checking if module is in abc file, Cannot find module '" << entryPoint << "'";
612        return false;
613    }
614    return true;
615}
616}  // namespace panda::ecmascript
617