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