1/* 2 * Copyright (c) 2021-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/module/js_module_source_text.h" 17 18#include "ecmascript/builtins/builtins_promise.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/jobs/micro_job_queue.h" 21#include "ecmascript/jspandafile/js_pandafile_executor.h" 22#include "ecmascript/jspandafile/js_pandafile_manager.h" 23#include "ecmascript/module/module_logger.h" 24#include "ecmascript/module/js_shared_module_manager.h" 25#include "ecmascript/module/module_path_helper.h" 26#include "ecmascript/object_fast_operator-inl.h" 27#include "ecmascript/runtime_lock.h" 28#include "ecmascript/patch/quick_fix_manager.h" 29 30namespace panda::ecmascript { 31using PathHelper = base::PathHelper; 32using StringHelper = base::StringHelper; 33using GlobalError = containers::ContainerError; 34 35CVector<std::string> SourceTextModule::GetExportedNames(JSThread *thread, const JSHandle<SourceTextModule> &module, 36 const JSHandle<TaggedArray> &exportStarSet) 37{ 38 CVector<std::string> exportedNames; 39 // 1. Let module be this Source Text Module Record. 40 // 2. If exportStarSet contains module, then 41 if (exportStarSet->GetIdx(module.GetTaggedValue()) != TaggedArray::MAX_ARRAY_INDEX) { 42 // a. Assert: We've reached the starting point of an import * circularity. 43 // b. Return a new empty List. 44 return exportedNames; 45 } 46 // 3. Append module to exportStarSet. 47 size_t len = exportStarSet->GetLength(); 48 JSHandle<TaggedArray> newExportStarSet = TaggedArray::SetCapacity(thread, exportStarSet, len + 1); 49 newExportStarSet->Set(thread, len, module.GetTaggedValue()); 50 51 JSTaggedValue entryValue = module->GetLocalExportEntries(); 52 // 5. For each ExportEntry Record e in module.[[LocalExportEntries]], do 53 AddExportName<LocalExportEntry>(thread, entryValue, exportedNames); 54 55 // 6. For each ExportEntry Record e in module.[[IndirectExportEntries]], do 56 entryValue = module->GetIndirectExportEntries(); 57 AddExportName<IndirectExportEntry>(thread, entryValue, exportedNames); 58 59 entryValue = module->GetStarExportEntries(); 60 auto globalConstants = thread->GlobalConstants(); 61 if (!entryValue.IsUndefined()) { 62 JSMutableHandle<StarExportEntry> ee(thread, globalConstants->GetUndefined()); 63 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined()); 64 65 // 7. For each ExportEntry Record e in module.[[StarExportEntries]], do 66 JSHandle<TaggedArray> starExportEntries(thread, entryValue); 67 size_t starExportEntriesLen = starExportEntries->GetLength(); 68 for (size_t idx = 0; idx < starExportEntriesLen; idx++) { 69 ee.Update(starExportEntries->Get(idx)); 70 // a. Let requestedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]). 71 moduleRequest.Update(ee->GetModuleRequest()); 72 SetExportName(thread, moduleRequest, module, exportedNames, newExportStarSet); 73 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exportedNames); 74 } 75 } 76 return exportedNames; 77} 78 79// new way with module 80JSHandle<JSTaggedValue> SourceTextModule::HostResolveImportedModuleWithMerge(JSThread *thread, 81 const JSHandle<SourceTextModule> &module, const JSHandle<JSTaggedValue> &moduleRequest, bool executeFromJob) 82{ 83 CString moduleRequestName = ModulePathHelper::Utf8ConvertToString(moduleRequest.GetTaggedValue()); 84 CString requestStr = ReplaceModuleThroughFeature(thread, moduleRequestName); 85 86 CString baseFilename {}; 87 StageOfHotReload stageOfHotReload = thread->GetCurrentEcmaContext()->GetStageOfHotReload(); 88 if (stageOfHotReload == StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN || 89 stageOfHotReload == StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN) { 90 baseFilename = thread->GetEcmaVM()->GetQuickFixManager()->GetBaseFileName(module); 91 } else { 92 baseFilename = module->GetEcmaModuleFilenameString(); 93 } 94 95 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); 96 auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(requestStr); 97 if (isNative) { 98 if (moduleManager->IsLocalModuleLoaded(requestStr)) { 99 return JSHandle<JSTaggedValue>(moduleManager->HostGetImportedModule(requestStr)); 100 } 101 return moduleManager->ResolveNativeModule(requestStr, baseFilename, moduleType); 102 } 103 CString recordName = module->GetEcmaModuleRecordNameString(); 104 std::shared_ptr<JSPandaFile> jsPandaFile = 105 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFilename, recordName); 106 if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE 107 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << baseFilename; 108 } 109 110 CString outFileName = baseFilename; 111 CString entryPoint = ModulePathHelper::ConcatFileNameWithMerge( 112 thread, jsPandaFile.get(), outFileName, recordName, requestStr); 113 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 114 115#if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS) 116 if (entryPoint == ModulePathHelper::PREVIEW_OF_ACROSS_HAP_FLAG) { 117 THROW_SYNTAX_ERROR_AND_RETURN(thread, "", thread->GlobalConstants()->GetHandledUndefined()); 118 } 119#endif 120 return SharedModuleManager::GetInstance()->ResolveImportedModuleWithMerge(thread, outFileName, entryPoint, 121 executeFromJob); 122} 123 124// old way with bundle 125JSHandle<JSTaggedValue> SourceTextModule::HostResolveImportedModule(JSThread *thread, 126 const JSHandle<SourceTextModule> &module, 127 const JSHandle<JSTaggedValue> &moduleRequest, 128 bool executeFromJob) 129{ 130 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); 131 CString moduleRequestStr = ModulePathHelper::Utf8ConvertToString(moduleRequest.GetTaggedValue()); 132 if (moduleManager->IsLocalModuleLoaded(moduleRequestStr)) { 133 return JSHandle<JSTaggedValue>(moduleManager->HostGetImportedModule(moduleRequestStr)); 134 } 135 136 CString dirname = base::PathHelper::ResolveDirPath(module->GetEcmaModuleFilenameString()); 137 CString moduleFilename = ResolveFilenameFromNative(thread, dirname, moduleRequestStr); 138 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 139 return SharedModuleManager::GetInstance()->ResolveImportedModule(thread, 140 moduleFilename, executeFromJob); 141} 142 143bool SourceTextModule::CheckCircularImport(const JSHandle<SourceTextModule> &module, 144 const JSHandle<JSTaggedValue> &exportName, 145 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveVector) 146{ 147 for (auto rr : resolveVector) { 148 // a. If module and r.[[Module]] are the same Module Record and 149 // SameValue(exportName, r.[[ExportName]]) is true, then 150 if (JSTaggedValue::SameValue(rr.first.GetTaggedValue(), module.GetTaggedValue()) && 151 JSTaggedValue::SameValue(rr.second, exportName)) { 152 // i. Assert: This is a circular import request. 153 // ii. Return true. 154 return true; 155 } 156 } 157 return false; 158} 159 160JSHandle<JSTaggedValue> SourceTextModule::ResolveExportObject(JSThread *thread, 161 const JSHandle<SourceTextModule> &module, 162 const JSHandle<JSTaggedValue> &exports, 163 const JSHandle<JSTaggedValue> &exportName) 164{ 165 // Let module be this Source Text Module Record. 166 auto globalConstants = thread->GlobalConstants(); 167 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 168 // For CJS, if exports is not JSObject, means the CJS module use default output 169 JSHandle<JSTaggedValue> defaultString = globalConstants->GetHandledDefaultString(); 170 if (JSTaggedValue::SameValue(exportName, defaultString)) { 171 // bind with a number 172 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, -1)); 173 } 174 if (exports->IsNativeModuleFailureInfo()) { 175 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, -1)); 176 } 177 if (exports->IsJSObject()) { 178 JSHandle<JSTaggedValue> resolution(thread, JSTaggedValue::Hole()); 179 JSObject *exportObject = JSObject::Cast(exports.GetTaggedValue().GetTaggedObject()); 180 TaggedArray *properties = TaggedArray::Cast(exportObject->GetProperties().GetTaggedObject()); 181 if (!properties->IsDictionaryMode()) { 182 JSHandle<JSHClass> jsHclass(thread, exportObject->GetJSHClass()); 183 // Get layoutInfo and compare the input and output names of files 184 LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject()); 185 if (layoutInfo->NumberOfElements() != 0) { 186 resolution = ResolveElementOfObject(thread, jsHclass, exportName, module); 187 } 188 } else { 189 NameDictionary *dict = NameDictionary::Cast(properties); 190 int entry = dict->FindEntry(exportName.GetTaggedValue()); 191 if (entry != -1) { 192 resolution = JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, entry)); 193 } 194 } 195 if (!resolution->IsUndefined()) { 196 return resolution; 197 } 198 } 199 return globalConstants->GetHandledNull(); 200} 201 202JSHandle<JSTaggedValue> SourceTextModule::ResolveNativeStarExport(JSThread *thread, 203 const JSHandle<SourceTextModule> &nativeModule, 204 const JSHandle<JSTaggedValue> &exportName) 205{ 206 if (nativeModule->GetStatus() != ModuleStatus::EVALUATED) { 207 auto moduleType = nativeModule->GetTypes(); 208 if (!LoadNativeModule(thread, nativeModule, moduleType)) { 209 return thread->GlobalConstants()->GetHandledNull(); 210 } 211 nativeModule->SetStatus(ModuleStatus::EVALUATED); 212 } 213 214 JSHandle<JSTaggedValue> nativeExports(thread, nativeModule->GetModuleValue(thread, 0, false)); 215 return SourceTextModule::ResolveExportObject(thread, nativeModule, nativeExports, exportName); 216} 217 218JSHandle<JSTaggedValue> SourceTextModule::ResolveCjsStarExport(JSThread *thread, 219 const JSHandle<SourceTextModule> &cjsModule, 220 const JSHandle<JSTaggedValue> &exportName) 221{ 222 if (cjsModule->GetStatus() != ModuleStatus::EVALUATED) { 223 SourceTextModule::ModuleExecution(thread, cjsModule); 224 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, thread->GlobalConstants()->GetHandledNull()); 225 cjsModule->SetStatus(ModuleStatus::EVALUATED); 226 } 227 228 CString moduleName = GetModuleName(cjsModule.GetTaggedValue()); 229 JSHandle<JSTaggedValue> cjsModuleName(thread->GetEcmaVM()->GetFactory()->NewFromUtf8(moduleName)); 230 JSHandle<JSTaggedValue> cjsExports = CjsModule::SearchFromModuleCache(thread, cjsModuleName); 231 return SourceTextModule::ResolveExportObject(thread, cjsModule, cjsExports, exportName); 232} 233 234JSHandle<JSTaggedValue> SourceTextModule::ResolveExport(JSThread *thread, const JSHandle<SourceTextModule> &module, 235 const JSHandle<JSTaggedValue> &exportName, 236 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveVector) 237{ 238 // 1. Let module be this Source Text Module Record. 239 auto globalConstants = thread->GlobalConstants(); 240 // Check if circular import request. 241 // 2.For each Record { [[Module]], [[ExportName]] } r in resolveVector, do 242 if (CheckCircularImport(module, exportName, resolveVector)) { 243 return globalConstants->GetHandledNull(); 244 } 245 // 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveVector. 246 resolveVector.emplace_back(std::make_pair(module, exportName)); 247 // 4. For each ExportEntry Record e in module.[[LocalExportEntries]], do 248 JSHandle<JSTaggedValue> localExportEntriesTv(thread, module->GetLocalExportEntries()); 249 if (!localExportEntriesTv->IsUndefined()) { 250 JSHandle<JSTaggedValue> resolution = ResolveLocalExport(thread, localExportEntriesTv, exportName, module); 251 if (!resolution->IsUndefined()) { 252 return resolution; 253 } 254 } 255 // 5. For each ExportEntry Record e in module.[[IndirectExportEntries]], do 256 JSHandle<JSTaggedValue> indirectExportEntriesTv(thread, module->GetIndirectExportEntries()); 257 if (!indirectExportEntriesTv->IsUndefined()) { 258 JSHandle<JSTaggedValue> resolution = ResolveIndirectExport(thread, indirectExportEntriesTv, 259 exportName, module, resolveVector); 260 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 261 if (!resolution->IsUndefined()) { 262 return resolution; 263 } 264 } 265 // 6. If SameValue(exportName, "default") is true, then 266 JSHandle<JSTaggedValue> defaultString = globalConstants->GetHandledDefaultString(); 267 if (JSTaggedValue::SameValue(exportName, defaultString)) { 268 // a. Assert: A default export was not explicitly defined by this module. 269 // b. Return null. 270 // c. NOTE: A default export cannot be provided by an export *. 271 return globalConstants->GetHandledNull(); 272 } 273 // 7. Let starResolution be null. 274 JSMutableHandle<JSTaggedValue> starResolution(thread, globalConstants->GetNull()); 275 // 8. For each ExportEntry Record e in module.[[StarExportEntries]], do 276 JSTaggedValue starExportEntriesTv = module->GetStarExportEntries(); 277 if (starExportEntriesTv.IsUndefined()) { 278 return starResolution; 279 } 280 JSMutableHandle<StarExportEntry> ee(thread, globalConstants->GetUndefined()); 281 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined()); 282 JSHandle<TaggedArray> starExportEntries(thread, starExportEntriesTv); 283 size_t starExportEntriesLen = starExportEntries->GetLength(); 284 for (size_t idx = 0; idx < starExportEntriesLen; idx++) { 285 ee.Update(starExportEntries->Get(idx)); 286 moduleRequest.Update(ee->GetModuleRequest()); 287 JSHandle<JSTaggedValue> result = GetStarResolution(thread, exportName, moduleRequest, 288 module, starResolution, resolveVector); 289 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 290 if (result->IsString() || result->IsException()) { 291 return result; 292 } 293 } 294 // 9. Return starResolution. 295 return starResolution; 296} 297 298std::pair<bool, ModuleTypes> SourceTextModule::CheckNativeModule(const CString &moduleRequestName) 299{ 300 if (moduleRequestName[0] != '@' || 301 StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::PREFIX_BUNDLE) || 302 StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::PREFIX_PACKAGE) || 303 StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::PREFIX_NORMALIZED_NOT_SO) || 304 moduleRequestName.find(':') == CString::npos) { 305 return {false, ModuleTypes::UNKNOWN}; 306 } 307 308 if (StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::REQUIRE_NAPI_OHOS_PREFIX)) { 309 return {true, ModuleTypes::OHOS_MODULE}; 310 } 311 /* 312 * moduleRequestName: @app:xxx/xxx 313 * : @normalized:Y&xxx 314 */ 315 if (StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::REQUIRE_NAPI_APP_PREFIX) || 316 StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::PREFIX_NORMALIZED_SO)) { 317 return {true, ModuleTypes::APP_MODULE}; 318 } 319 if (StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) { 320 return {true, ModuleTypes::NATIVE_MODULE}; 321 } 322 return {true, ModuleTypes::INTERNAL_MODULE}; 323} 324 325Local<JSValueRef> SourceTextModule::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType) 326{ 327 Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm); 328 auto globalConstants = vm->GetJSThread()->GlobalConstants(); 329 auto funcName = (moduleType == ModuleTypes::NATIVE_MODULE) ? 330 globalConstants->GetHandledRequireNativeModuleString() : 331 globalConstants->GetHandledRequireNapiString(); 332 return globalObject->Get(vm, JSNApiHelper::ToLocal<StringRef>(funcName)); 333} 334 335void SourceTextModule::MakeNormalizedAppArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments, 336 const CString &soPath, const CString &moduleName) 337{ 338 CString soName = ModulePathHelper::GetNormalizedPathFromOhmUrl(soPath); 339 CString path = ModulePathHelper::GetBundleNameFromNormalized(vm, soPath) + PathHelper::SLASH_TAG + moduleName; 340 // use module name as so name 341 arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str()); 342 arguments.emplace_back(BooleanRef::New(vm, true)); 343 arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str())); 344} 345 346void SourceTextModule::MakeAppArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments, 347 const CString &soPath, const CString &moduleName, const CString &requestName) 348{ 349 if (!StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAPI_APP_PREFIX)) { 350 return MakeNormalizedAppArgs(vm, arguments, soPath, moduleName); 351 } 352 size_t pos = soPath.find_last_of(PathHelper::SLASH_TAG); 353 if (pos == CString::npos) { // LCOV_EXCL_BR_LINE 354 LOG_FULL(FATAL) << "Invalid native module " << soPath; 355 UNREACHABLE(); 356 } 357 CString soName = soPath.substr(pos + 1); 358 CString path = soPath.substr(0, pos); 359 // use module name as so name 360 arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str()); 361 arguments.emplace_back(BooleanRef::New(vm, true)); 362 arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str())); 363} 364 365void SourceTextModule::MakeInternalArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments, 366 const CString &moduleRequestName) 367{ 368 arguments.emplace_back(BooleanRef::New(vm, false)); 369 arguments.emplace_back(StringRef::NewFromUtf8(vm, "")); 370 CString moduleDir = PathHelper::GetInternalModulePrefix(moduleRequestName); 371 arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleDir.c_str())); 372} 373 374Local<JSValueRef> SourceTextModule::LoadNativeModuleImpl(EcmaVM *vm, JSThread *thread, 375 const JSHandle<SourceTextModule> &requiredModule, ModuleTypes moduleType) 376{ 377 CString moduleRequestName = requiredModule->GetEcmaModuleRecordNameString(); 378 bool enableESMTrace = thread->GetEcmaVM()->GetJSOptions().EnableESMTrace(); 379 if (enableESMTrace) { 380 CString traceInfo = "LoadNativeModule: " + moduleRequestName; 381 ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, traceInfo.c_str()); 382 } 383 ModuleLogger *moduleLogger = thread->GetCurrentEcmaContext()->GetModuleLogger(); 384 if (moduleLogger != nullptr) { 385 moduleLogger->SetStartTime(moduleRequestName); 386 } 387 CString soName = PathHelper::GetStrippedModuleName(moduleRequestName); 388 389 CString fileName = requiredModule->GetEcmaModuleFilenameString(); 390 CString moduleName = ModulePathHelper::GetModuleNameWithBaseFile(fileName); 391 std::vector<Local<JSValueRef>> arguments; 392 LOG_FULL(DEBUG) << "Request module is " << moduleRequestName; 393 394 arguments.emplace_back(StringRef::NewFromUtf8(vm, soName.c_str())); 395 if (moduleType == ModuleTypes::APP_MODULE) { 396 MakeAppArgs(vm, arguments, soName, moduleName, moduleRequestName); 397 } else if (moduleType == ModuleTypes::INTERNAL_MODULE) { 398 MakeInternalArgs(vm, arguments, moduleRequestName); 399 } 400 auto maybeFuncRef = GetRequireNativeModuleFunc(vm, moduleType); 401 // some function(s) may not registered in global object for non-main thread 402 if (!maybeFuncRef->IsFunction(vm)) { 403 LOG_FULL(WARN) << "Not found require func"; 404 if (enableESMTrace) { 405 ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK); 406 } 407 if (moduleLogger != nullptr) { 408 moduleLogger->SetEndTime(moduleRequestName); 409 } 410 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined())); 411 } 412 413 Local<FunctionRef> funcRef = maybeFuncRef; 414 auto exportObject = funcRef->Call(vm, JSValueRef::Undefined(vm), arguments.data(), arguments.size()); 415 if (enableESMTrace) { 416 ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK); 417 } 418 if (moduleLogger != nullptr) { 419 moduleLogger->SetEndTime(moduleRequestName); 420 } 421 return exportObject; 422} 423 424Local<JSValueRef> SourceTextModule::LoadNativeModuleMayThrowError(JSThread *thread, 425 const JSHandle<SourceTextModule> &requiredModule, ModuleTypes moduleType) 426{ 427 EcmaVM *vm = thread->GetEcmaVM(); 428 EscapeLocalScope scope(vm); 429 430 auto exportObject = LoadNativeModuleImpl(vm, thread, requiredModule, moduleType); 431 if (exportObject->IsNativeModuleFailureInfoObject(vm) || exportObject->IsUndefined()) { 432 CString errorMsg = "load native module failed."; 433 LOG_FULL(ERROR) << errorMsg.c_str(); 434 auto error = GlobalError::ReferenceError(thread, errorMsg.c_str()); 435 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, 436 JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()))); 437 } 438 return scope.Escape(exportObject); 439} 440 441bool SourceTextModule::LoadNativeModule(JSThread *thread, const JSHandle<SourceTextModule> &requiredModule, 442 ModuleTypes moduleType) 443{ 444 EcmaVM *vm = thread->GetEcmaVM(); 445 [[maybe_unused]] LocalScope scope(vm); 446 447 auto exportObject = LoadNativeModuleImpl(vm, thread, requiredModule, moduleType); 448 if (UNLIKELY(exportObject->IsUndefined())) { 449 CString fileName = requiredModule->GetEcmaModuleFilenameString(); 450 CString moduleName = ModulePathHelper::GetModuleNameWithBaseFile(fileName); 451 LOG_FULL(ERROR) << "export objects of native so is undefined, so name is " << moduleName; 452 return false; 453 } 454 if (UNLIKELY(exportObject->IsNativeModuleFailureInfoObject(vm))) { 455 requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject)); 456 LOG_FULL(ERROR) << "loading fails, NativeModuleErrorObject is returned"; 457 return false; 458 } 459 ASSERT(!thread->HasPendingException()); 460 requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject)); 461 return true; 462} 463 464void SourceTextModule::EvaluateNativeModule(JSThread *thread, JSHandle<SourceTextModule> nativeModule, 465 ModuleTypes moduleType) 466{ 467 if (nativeModule->GetStatus() == ModuleStatus::EVALUATED) { 468 return; 469 } 470 if (!SourceTextModule::LoadNativeModule(thread, nativeModule, moduleType)) { 471 LOG_FULL(INFO) << "LoadNativeModule " << nativeModule->GetEcmaModuleRecordNameString() << " failed"; 472 return; 473 } 474 nativeModule->SetStatus(ModuleStatus::EVALUATED); 475} 476 477int SourceTextModule::HandleInstantiateException([[maybe_unused]] JSHandle<SourceTextModule> &module, 478 const CVector<JSHandle<SourceTextModule>> &stack, int result) 479{ 480 // a. For each module m in stack, do 481 for (auto mm : stack) { 482 // i. Assert: m.[[Status]] is "instantiating". 483 ASSERT(mm->GetStatus() == ModuleStatus::INSTANTIATING); 484 // ii. Set m.[[Status]] to "uninstantiated". 485 mm->SetStatus(ModuleStatus::UNINSTANTIATED); 486 // iii. Set m.[[Environment]] to undefined. 487 // iv. Set m.[[DFSIndex]] to undefined. 488 mm->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX); 489 // v. Set m.[[DFSAncestorIndex]] to undefined. 490 mm->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX); 491 } 492 // b. Assert: module.[[Status]] is "uninstantiated". 493 ASSERT(module->GetStatus() == ModuleStatus::UNINSTANTIATED); 494 // c. return result 495 return result; 496} 497 498int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl, 499 bool executeFromJob) 500{ 501 STACK_LIMIT_CHECK(thread, SourceTextModule::UNDEFINED_INDEX); 502 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::Instantiate"); 503 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX); 504 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleHdl); 505 // 1. Let module be this Source Text Module Record. 506 // 2. Assert: module.[[Status]] is one of UNLINKED, LINKED, EVALUATING-ASYNC, or EVALUATED. 507 ModuleStatus status = module->GetStatus(); 508 ASSERT(status == ModuleStatus::UNINSTANTIATED || status == ModuleStatus::INSTANTIATED || 509 status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED); 510 // 3. Let stack be a new empty List. 511 CVector<JSHandle<SourceTextModule>> stack; 512 // 4. Let result be InnerModuleInstantiation(module, stack, 0). 513 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module); 514 int result = SourceTextModule::InnerModuleInstantiation(thread, moduleRecord, stack, 0, executeFromJob); 515 // 5. If result is an abrupt completion, then 516 if (thread->HasPendingException()) { 517 return HandleInstantiateException(module, stack, result); 518 } 519 // 6. Assert: module.[[Status]] is one of LINKED, EVALUATING-ASYNC, or EVALUATED. 520 status = module->GetStatus(); 521 ASSERT(status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATING_ASYNC || 522 status == ModuleStatus::EVALUATED); 523 // 7. Assert: stack is empty. 524 ASSERT(stack.empty()); 525 // 8. Return undefined. 526 SharedModuleManager::GetInstance()->TransferSModule(thread); 527 return SourceTextModule::UNDEFINED_INDEX; 528} 529 530std::optional<std::set<uint32_t>> SourceTextModule::GetConcurrentRequestedModules(const JSHandle<Method> &method) 531{ 532 const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); 533 const MethodLiteral *methodLiteral = method->GetMethodLiteral(); 534 ASSERT(methodLiteral != nullptr); 535 return methodLiteral->GetConcurrentRequestedModules(jsPandaFile); 536} 537 538void SourceTextModule::DFSModuleInstantiation(JSHandle<SourceTextModule> &module, 539 CVector<JSHandle<SourceTextModule>> &stack) 540{ 541 // 1. Assert: module occurs exactly once in stack. 542 // 2. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]]. 543 int dfsAncIdx = module->GetDFSAncestorIndex(); 544 int dfsIdx = module->GetDFSIndex(); 545 ASSERT(dfsAncIdx <= dfsIdx); 546 // 3. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then 547 if (dfsAncIdx == dfsIdx) { 548 // a. Let done be false. 549 bool done = false; 550 // b. Repeat, while done is false, 551 while (!done) { 552 // i. Let requiredModule be the last element in stack. 553 JSHandle<SourceTextModule> requiredModule = stack.back(); 554 // ii. Remove the last element of stack. 555 stack.pop_back(); 556 // iii. Set requiredModule.[[Status]] to "instantiated". 557 requiredModule->SetStatus(ModuleStatus::INSTANTIATED); 558 // iv. If requiredModule and module are the same Module Record, set done to true. 559 if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) { 560 done = true; 561 } 562 } 563 } 564} 565 566std::optional<int> SourceTextModule::HandleInnerModuleInstantiation(JSThread *thread, 567 JSHandle<SourceTextModule> &module, 568 JSMutableHandle<JSTaggedValue> &required, 569 CVector<JSHandle<SourceTextModule>> &stack, 570 int &index, bool executeFromJob) 571{ 572 // a. Let requiredModule be ? HostResolveImportedModule(module, required). 573 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined()); 574 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 575 if (moduleRecordName.empty()) { 576 JSHandle<JSTaggedValue> requiredVal = 577 SourceTextModule::HostResolveImportedModule(thread, module, required, executeFromJob); 578 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX); 579 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal)); 580 } else { 581 JSHandle<JSTaggedValue> requiredVal = 582 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required, executeFromJob); 583 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX); 584 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal)); 585 } 586 587 // b. Set index to ? InnerModuleInstantiation(requiredModule, stack, index). 588 JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule); 589 index = SourceTextModule::InnerModuleInstantiation(thread, 590 requiredModuleRecord, stack, index, executeFromJob); 591 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 592 // c. Assert: requiredModule.[[Status]] is one of LINKING, LINKED, EVALUATING-ASYNC, or EVALUATED. 593 ModuleStatus requiredModuleStatus = requiredModule->GetStatus(); 594 ASSERT(requiredModuleStatus == ModuleStatus::INSTANTIATING || 595 requiredModuleStatus == ModuleStatus::INSTANTIATED || 596 requiredModuleStatus == ModuleStatus::EVALUATING_ASYNC || 597 requiredModuleStatus == ModuleStatus::EVALUATED); 598 // d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack. 599 // e. If requiredModule.[[Status]] is "instantiating", then 600 if (requiredModuleStatus == ModuleStatus::INSTANTIATING) { 601 // d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack. 602 ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end()); 603 // i. Assert: requiredModule is a Source Text Module Record. 604 // ii. Set module.[[DFSAncestorIndex]] to min( 605 // module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]). 606 int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex()); 607 module->SetDFSAncestorIndex(dfsAncIdx); 608 } 609 return std::nullopt; 610} 611 612int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord, 613 CVector<JSHandle<SourceTextModule>> &stack, int index, bool executeFromJob) 614{ 615 // Add a safepoint here to check if a suspension is needed. 616 thread->CheckSafepointIfSuspended(); 617 // 1. If module is not a Source Text Module Record, then 618 if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) { 619 STACK_LIMIT_CHECK(thread, SourceTextModule::UNDEFINED_INDEX); 620 SourceTextModule::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord)); 621 // a. Perform ? module.Instantiate(). 622 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 623 // b. Return index. 624 return index; 625 } 626 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord); 627 // 2. If module.[[Status]] is one of LINKING, LINKED, EVALUATING-ASYNC, or EVALUATED, then Return index. 628 ModuleStatus status = module->GetStatus(); 629 if (status == ModuleStatus::INSTANTIATING || 630 status == ModuleStatus::INSTANTIATED || 631 status == ModuleStatus::EVALUATING_ASYNC || 632 status == ModuleStatus::EVALUATED) { 633 return index; 634 } 635 // 3. Assert: module.[[Status]] is "uninstantiated". 636 ASSERT(status == ModuleStatus::UNINSTANTIATED); 637 // 4. Set module.[[Status]] to "instantiating". 638 module->SetStatus(ModuleStatus::INSTANTIATING); 639 // 5. Set module.[[DFSIndex]] to index. 640 module->SetDFSIndex(index); 641 // 6. Set module.[[DFSAncestorIndex]] to index. 642 module->SetDFSAncestorIndex(index); 643 // 7. Set index to index + 1. 644 index++; 645 // 8. Append module to stack. 646 stack.emplace_back(module); 647 // 9. For each String required that is an element of module.[[RequestedModules]], do 648 if (!module->GetRequestedModules().IsUndefined()) { 649 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules()); 650 size_t requestedModulesLen = requestedModules->GetLength(); 651 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined()); 652 for (size_t idx = 0; idx < requestedModulesLen; idx++) { 653 required.Update(requestedModules->Get(idx)); 654 auto result = HandleInnerModuleInstantiation(thread, module, required, stack, index, executeFromJob); 655 if (UNLIKELY(result.has_value())) { // exception occurs 656 return result.value(); 657 } 658 } 659 } 660 // Adapter new opcode 661 // 10. Perform ? ModuleDeclarationEnvironmentSetup(module). 662 if (module->GetIsNewBcVersion()) { 663 SourceTextModule::ModuleDeclarationArrayEnvironmentSetup(thread, module); 664 } else { 665 SourceTextModule::ModuleDeclarationEnvironmentSetup(thread, module); 666 } 667 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 668 DFSModuleInstantiation(module, stack); 669 return index; 670} 671 672void SourceTextModule::ModuleDeclarationEnvironmentSetup(JSThread *thread, 673 const JSHandle<SourceTextModule> &module) 674{ 675 CheckResolvedBinding(thread, module); 676 if (module->GetImportEntries().IsUndefined()) { 677 return; 678 } 679 ASSERT(!SourceTextModule::IsSharedModule(module)); 680 // 2. Assert: All named exports from module are resolvable. 681 // 3. Let realm be module.[[Realm]]. 682 // 4. Assert: realm is not undefined. 683 // 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]). 684 JSHandle<TaggedArray> importEntries(thread, module->GetImportEntries()); 685 size_t importEntriesLen = importEntries->GetLength(); 686 JSHandle<NameDictionary> map(NameDictionary::Create(thread, 687 NameDictionary::ComputeHashTableSize(importEntriesLen))); 688 // 6. Set module.[[Environment]] to env. 689 module->SetEnvironment(thread, map); 690 // 7. Let envRec be env's EnvironmentRecord. 691 JSMutableHandle<JSTaggedValue> envRec(thread, module->GetEnvironment()); 692 ASSERT(!envRec->IsUndefined()); 693 // 8. For each ImportEntry Record in in module.[[ImportEntries]], do 694 auto globalConstants = thread->GlobalConstants(); 695 JSMutableHandle<ImportEntry> in(thread, globalConstants->GetUndefined()); 696 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined()); 697 JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined()); 698 JSMutableHandle<JSTaggedValue> localName(thread, globalConstants->GetUndefined()); 699 for (size_t idx = 0; idx < importEntriesLen; idx++) { 700 in.Update(importEntries->Get(idx)); 701 localName.Update(in->GetLocalName()); 702 importName.Update(in->GetImportName()); 703 moduleRequest.Update(in->GetModuleRequest()); 704 // a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]). 705 JSMutableHandle<SourceTextModule> importedModule(thread, thread->GlobalConstants()->GetUndefined()); 706 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 707 if (moduleRecordName.empty()) { 708 JSHandle<JSTaggedValue> importedVal = 709 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); 710 RETURN_IF_ABRUPT_COMPLETION(thread); 711 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal)); 712 } else { 713 JSHandle<JSTaggedValue> importedVal = 714 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest); 715 RETURN_IF_ABRUPT_COMPLETION(thread); 716 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal)); 717 } 718 // c. If in.[[ImportName]] is "*", then 719 JSHandle<JSTaggedValue> starString = globalConstants->GetHandledStarString(); 720 if (JSTaggedValue::SameValue(importName, starString)) { 721 // i. Let namespace be ? GetModuleNamespace(importedModule). 722 JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, importedModule); 723 // ii. Perform ! envRec.CreateImmutableBinding(in.[[LocalName]], true). 724 // iii. Call envRec.InitializeBinding(in.[[LocalName]], namespace). 725 JSHandle<NameDictionary> mapHandle = JSHandle<NameDictionary>::Cast(envRec); 726 JSHandle<NameDictionary> newMap = NameDictionary::Put(thread, mapHandle, localName, moduleNamespace, 727 PropertyAttributes::Default()); 728 envRec.Update(newMap); 729 } else { 730 // i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »). 731 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector; 732 JSHandle<JSTaggedValue> resolution = 733 SourceTextModule::ResolveExport(thread, importedModule, importName, resolveVector); 734 RETURN_IF_ABRUPT_COMPLETION(thread); 735 // ii. If resolution is null or "ambiguous", throw a SyntaxError exception. 736 if (resolution->IsNull() || resolution->IsString()) { 737 CString requestMod = ModulePathHelper::ReformatPath(ConvertToString(moduleRequest.GetTaggedValue())); 738 CString msg = "the requested module '" + requestMod + GetResolveErrorReason(resolution) + 739 ConvertToString(importName.GetTaggedValue()); 740 if (!module->GetEcmaModuleRecordNameString().empty()) { 741 CString recordStr = ModulePathHelper::ReformatPath(module->GetEcmaModuleRecordNameString()); 742 msg += "' which imported by '" + recordStr + "'"; 743 } else { 744 msg += "' which imported by '" + module->GetEcmaModuleFilenameString() + "'"; 745 } 746 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str()); 747 } 748 // iii. Call envRec.CreateImportBinding( 749 // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]). 750 JSHandle<NameDictionary> mapHandle = JSHandle<NameDictionary>::Cast(envRec); 751 JSHandle<NameDictionary> newMap = NameDictionary::Put(thread, mapHandle, localName, resolution, 752 PropertyAttributes::Default()); 753 envRec.Update(newMap); 754 } 755 } 756 757 module->SetEnvironment(thread, envRec); 758} 759 760void SourceTextModule::ModuleDeclarationArrayEnvironmentSetup(JSThread *thread, 761 const JSHandle<SourceTextModule> &module) 762{ 763 bool enableESMTrace = thread->GetEcmaVM()->GetJSOptions().EnableESMTrace(); 764 if (enableESMTrace) { 765 CString traceInfo = "SourceTextModule::Instantiating: " + 766 module->GetEcmaModuleRecordNameString(); 767 ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, traceInfo.c_str()); 768 } 769 if (IsSharedModule(module) && SharedModuleManager::GetInstance()->IsInstantiatedSModule(thread, module)) { 770 if (enableESMTrace) { 771 ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK); 772 } 773 return; 774 } 775 CheckResolvedIndexBinding(thread, module); 776 if (module->GetImportEntries().IsUndefined()) { 777 if (enableESMTrace) { 778 ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK); 779 } 780 return; 781 } 782 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 783 784 // 2. Assert: All named exports from module are resolvable. 785 // 3. Let realm be module.[[Realm]]. 786 // 4. Assert: realm is not undefined. 787 // 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]). 788 JSHandle<TaggedArray> importEntries(thread, module->GetImportEntries()); 789 size_t importEntriesLen = importEntries->GetLength(); 790 JSHandle<TaggedArray> arr = factory->NewTaggedArray(importEntriesLen); 791 // 7. Let envRec be env's EnvironmentRecord. 792 JSHandle<TaggedArray> envRec = arr; 793 // 8. For each ImportEntry Record in in module.[[ImportEntries]], do 794 auto globalConstants = thread->GlobalConstants(); 795 JSMutableHandle<ImportEntry> in(thread, globalConstants->GetUndefined()); 796 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined()); 797 JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined()); 798 for (size_t idx = 0; idx < importEntriesLen; idx++) { 799 in.Update(importEntries->Get(idx)); 800 importName.Update(in->GetImportName()); 801 moduleRequest.Update(in->GetModuleRequest()); 802 // a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]). 803 JSMutableHandle<SourceTextModule> importedModule(thread, thread->GlobalConstants()->GetUndefined()); 804 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 805 if (moduleRecordName.empty()) { 806 JSHandle<JSTaggedValue> importedVal = 807 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); 808 RETURN_IF_ABRUPT_COMPLETION(thread); 809 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal)); 810 } else { 811 JSHandle<JSTaggedValue> importedVal = 812 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest); 813 RETURN_IF_ABRUPT_COMPLETION(thread); 814 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal)); 815 } 816 // c. If in.[[ImportName]] is "*", then 817 JSHandle<JSTaggedValue> starString = globalConstants->GetHandledStarString(); 818 if (JSTaggedValue::SameValue(importName, starString)) { 819 // need refactor 820 envRec = JSSharedModule::CloneEnvForSModule(thread, module, envRec); 821 module->SetEnvironment(thread, envRec); 822 if (enableESMTrace) { 823 ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK); 824 } 825 return; 826 } 827 // i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »). 828 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector; 829 JSHandle<JSTaggedValue> resolution = 830 SourceTextModule::ResolveExport(thread, importedModule, importName, resolveVector); 831 RETURN_IF_ABRUPT_COMPLETION(thread); 832 // ii. If resolution is null or "ambiguous", throw a SyntaxError exception. 833 if (resolution->IsNull() || resolution->IsString()) { 834 CString requestMod = ModulePathHelper::ReformatPath(ConvertToString(moduleRequest.GetTaggedValue())); 835 CString msg = "the requested module '" + requestMod + GetResolveErrorReason(resolution) + 836 ConvertToString(importName.GetTaggedValue()); 837 if (!module->GetEcmaModuleRecordNameString().empty()) { 838 CString recordStr = ModulePathHelper::ReformatPath( 839 module->GetEcmaModuleRecordNameString()); 840 msg += "' which imported by '" + recordStr + "'"; 841 } else { 842 msg += "' which imported by '" + module->GetEcmaModuleFilenameString() + "'"; 843 } 844 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str()); 845 } 846 // iii. Call envRec.CreateImportBinding( 847 // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]). 848 envRec->Set(thread, idx, resolution); 849 } 850 envRec = JSSharedModule::CloneEnvForSModule(thread, module, envRec); 851 module->SetEnvironment(thread, envRec); 852 if (enableESMTrace) { 853 ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK); 854 } 855} 856 857JSHandle<JSTaggedValue> SourceTextModule::GetModuleNamespace(JSThread *thread, 858 const JSHandle<SourceTextModule> &module) 859{ 860 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 861 // 1. Assert: module is an instance of a concrete subclass of Module Record. 862 // 2. Assert: module.[[Status]] is not "uninstantiated". 863 ASSERT(module->GetStatus() != ModuleStatus::UNINSTANTIATED); 864 // 3. Let namespace be module.[[Namespace]]. 865 JSMutableHandle<JSTaggedValue> moduleNamespace(thread, module->GetNamespace().GetWeakRawValue()); 866 // If namespace is undefined, then 867 if (moduleNamespace->IsUndefined()) { 868 // a. Let exportedNames be ? module.GetExportedNames(« »). 869 JSHandle<TaggedArray> exportStarSet = factory->EmptyArray(); 870 CVector<std::string> exportedNames = SourceTextModule::GetExportedNames(thread, module, exportStarSet); 871 // b. Let unambiguousNames be a new empty List. 872 JSHandle<TaggedArray> unambiguousNames = factory->NewTaggedArray(exportedNames.size()); 873 // c. For each name that is an element of exportedNames, do 874 size_t idx = 0; 875 for (std::string &name : exportedNames) { 876 // i. Let resolution be ? module.ResolveExport(name, « »). 877 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector; 878 JSHandle<JSTaggedValue> nameHandle = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(name)); 879 JSHandle<JSTaggedValue> resolution = 880 SourceTextModule::ResolveExport(thread, module, nameHandle, resolveVector); 881 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 882 // ii. If resolution is a ResolvedBinding Record, append name to unambiguousNames. 883 if (resolution->IsModuleBinding()) { 884 unambiguousNames->Set(thread, idx, nameHandle); 885 idx++; 886 } 887 } 888 JSHandle<TaggedArray> fixUnambiguousNames = TaggedArray::SetCapacity(thread, unambiguousNames, idx); 889 JSHandle<JSTaggedValue> moduleTagged = JSHandle<JSTaggedValue>::Cast(module); 890 JSHandle<ModuleNamespace> np = 891 ModuleNamespace::ModuleNamespaceCreate(thread, moduleTagged, fixUnambiguousNames); 892 moduleNamespace.Update(np.GetTaggedValue()); 893 } 894 return moduleNamespace; 895} 896 897void SourceTextModule::HandleEvaluateResult(JSThread *thread, JSHandle<SourceTextModule> &module, 898 JSHandle<PromiseCapability> &capability, const CVector<JSHandle<SourceTextModule>> &stack, int result) 899{ 900 ModuleStatus status; 901 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 902 // 9. If result is an abrupt completion, then 903 if (thread->HasPendingException()) { 904 // a. For each module m in stack, do 905 for (auto mm : stack) { 906 // i. Assert: m.[[Status]] is "evaluating". 907 ASSERT(mm->GetStatus() == ModuleStatus::EVALUATING); 908 // ii. Set m.[[Status]] to "evaluated". 909 mm->SetStatus(ModuleStatus::EVALUATED); 910 // iii. Set m.[[EvaluationError]] to result. 911 mm->SetEvaluationError(result); 912 } 913 // b. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is result. 914 status = module->GetStatus(); 915 ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == result); 916 //d. Perform ! Call(capability.[[Reject]], undefined, « result.[[Value]] »). 917 JSHandle<JSTaggedValue> reject(thread, capability->GetReject()); 918 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 919 EcmaRuntimeCallInfo *info = 920 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); 921 RETURN_IF_ABRUPT_COMPLETION(thread); 922 info->SetCallArg(JSTaggedValue(result)); 923 [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info); 924 RETURN_IF_ABRUPT_COMPLETION(thread); 925 // 10. Else, 926 } else { 927 // a. Assert: module.[[Status]] is either EVALUATING-ASYNC or EVALUATED. 928 status = module->GetStatus(); 929 ASSERT(status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED); 930 // b. Assert: module.[[EvaluationError]] is EMPTY. 931 ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX); 932 // c. If module.[[AsyncEvaluation]] is false, then 933 // i. Assert: module.[[Status]] is EVALUATED. 934 // ii. Perform ! Call(capability.[[Resolve]], undefined, « undefined »). 935 if (!module->IsAsyncEvaluating()) { 936 ASSERT(status == ModuleStatus::EVALUATED); 937 } 938 // d. Assert: stack is empty. 939 ASSERT(stack.empty()); 940 } 941} 942 943JSTaggedValue SourceTextModule::Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &moduleHdl, 944 const void *buffer, size_t size, bool executeFromJob) 945{ 946 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::Evaluate"); 947 // 1. Let module be this Source Text Module Record. 948 // 2. Assert: module.[[Status]] is one of LINKED, EVALUATING-ASYNC, or EVALUATED. 949 JSMutableHandle<SourceTextModule> module(thread, moduleHdl); 950 ModuleStatus status = module->GetStatus(); 951 ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATING_ASYNC || 952 status == ModuleStatus::EVALUATED)); 953 // 3. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, set module to module.[[CycleRoot]]. 954 if (status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED) { 955 module.Update(module->GetCycleRoot()); 956 } 957 // 4. If module.[[TopLevelCapability]] is not EMPTY, then 958 // a. Return module.[[TopLevelCapability]].[[Promise]]. 959 // 5. Let stack be a new empty List. 960 CVector<JSHandle<SourceTextModule>> stack; 961 // 6. Let capability be ! NewPromiseCapability(%Promise%). 962 auto vm = thread->GetEcmaVM(); 963 JSHandle<GlobalEnv> env = vm->GetGlobalEnv(); 964 JSHandle<PromiseCapability> capability = 965 JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction())); 966 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 967 // 7. Set module.[[TopLevelCapability]] to capability. 968 if (!SourceTextModule::IsSharedModule(module)) { 969 module->SetTopLevelCapability(thread, capability); 970 } 971 972 // 8. Let result be Completion(InnerModuleEvaluation(module, stack, 0)). 973 int result = SourceTextModule::InnerModuleEvaluation(thread, module, stack, 0, buffer, size, executeFromJob); 974 HandleEvaluateResult(thread, module, capability, stack, result); 975 if (!thread->HasPendingException() && !executeFromJob) { 976 job::MicroJobQueue::ExecutePendingJob(thread, thread->GetCurrentEcmaContext()->GetMicroJobQueue()); 977 } 978 ModuleLogger *moduleLogger = thread->GetCurrentEcmaContext()->GetModuleLogger(); 979 if ((moduleLogger != nullptr) && !executeFromJob) { 980 moduleLogger->InsertEntryPointModule(module); 981 } 982 // Return capability.[[Promise]]. 983 return capability->GetPromise(); 984} 985 986int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module, 987 const JSHandle<Method> &method) 988{ 989 // 1. Let module be this Source Text Module Record. 990 // 2. Assert: module.[[Status]] is "instantiated" or "evaluated". 991 [[maybe_unused]] ModuleStatus status = module->GetStatus(); 992 ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED)); 993 // 4. Let result be InnerModuleEvaluation(module, stack, 0) 994 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module); 995 int result = SourceTextModule::ModuleEvaluation(thread, moduleRecord, 0, method); 996 // 5. If result is an abrupt completion, then 997 if (thread->HasPendingException()) { 998 return result; 999 } else { 1000 job::MicroJobQueue::ExecutePendingJob(thread, thread->GetCurrentEcmaContext()->GetMicroJobQueue()); 1001 return SourceTextModule::UNDEFINED_INDEX; 1002 } 1003} 1004 1005int SourceTextModule::InnerModuleEvaluationUnsafe(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord, 1006 CVector<JSHandle<SourceTextModule>> &stack, int index, const void *buffer, size_t size, bool executeFromJob) 1007{ 1008 STACK_LIMIT_CHECK(thread, index); 1009 if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) { 1010 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1011 JSTaggedValue promise = SourceTextModule::Evaluate(thread, JSHandle<SourceTextModule>::Cast(moduleRecord)); 1012 PromiseState state = JSPromise::Cast(moduleRecord.GetTaggedValue().GetTaggedObject())->GetPromiseState(); 1013 ASSERT(state != PromiseState::PENDING); 1014 if (state == PromiseState::REJECTED) { 1015 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1016 JSTaggedValue promiseResult = JSPromise::Cast(promise.GetTaggedObject())->GetPromiseResult(); 1017 JSHandle<JSObject> error = 1018 factory->GetJSError(base::ErrorType::ERROR, nullptr, StackCheck::NO); 1019 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error.GetTaggedValue(), promiseResult.GetInt()); 1020 } 1021 return index; 1022 } 1023 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord); 1024 ModuleStatus status = module->GetStatus(); 1025 if (status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED) { 1026 if (module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX) { 1027 return index; 1028 } 1029 // Otherwise return module.[[EvaluationError]]. 1030 return module->GetEvaluationError(); 1031 } 1032 if (status == ModuleStatus::EVALUATING) { 1033 return index; 1034 } 1035 ASSERT(status == ModuleStatus::INSTANTIATED); 1036 module->SetStatus(ModuleStatus::EVALUATING); 1037 module->SetDFSIndex(index); 1038 module->SetDFSAncestorIndex(index); 1039 module->SetPendingAsyncDependencies(0); 1040 index++; 1041 stack.emplace_back(module); 1042 ModuleLogger *moduleLogger = thread->GetCurrentEcmaContext()->GetModuleLogger(); 1043 if (!module->GetRequestedModules().IsUndefined()) { 1044 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules()); 1045 size_t requestedModulesLen = requestedModules->GetLength(); 1046 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined()); 1047 JSHandle<SourceTextModule> requiredModule; 1048 for (size_t idx = 0; idx < requestedModulesLen; idx++) { 1049 // check if requiredModule is marked lazy 1050 if (module->IsLazyImportModule(idx)) { 1051 continue; 1052 } 1053 required.Update(requestedModules->Get(idx)); 1054 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1055 if (moduleRecordName.empty()) { 1056 requiredModule = JSHandle<SourceTextModule>::Cast( 1057 SourceTextModule::HostResolveImportedModule(thread, module, required)); 1058 } else { 1059 requiredModule = JSHandle<SourceTextModule>::Cast( 1060 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required)); 1061 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1062 } 1063 if (moduleLogger != nullptr) { 1064 moduleLogger->InsertParentModule(module, requiredModule); 1065 } 1066 ModuleTypes moduleType = requiredModule->GetTypes(); 1067 if (SourceTextModule::IsNativeModule(moduleType)) { 1068 EvaluateNativeModule(thread, requiredModule, moduleType); 1069 continue; 1070 } 1071 // if requiredModule is jsonModule, then don't need to execute. 1072 if (moduleType == ModuleTypes::JSON_MODULE) { 1073 requiredModule->SetStatus(ModuleStatus::EVALUATED); 1074 continue; 1075 } 1076 1077 index = SourceTextModule::InnerModuleEvaluation( 1078 thread, requiredModule, stack, index, buffer, size, executeFromJob); 1079 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1080 ModuleStatus requiredModuleStatus = requiredModule->GetStatus(); 1081 ASSERT(requiredModuleStatus == ModuleStatus::EVALUATING || 1082 requiredModuleStatus == ModuleStatus::EVALUATING_ASYNC || 1083 requiredModuleStatus == ModuleStatus::EVALUATED); 1084 if (requiredModuleStatus == ModuleStatus::EVALUATING) { 1085 ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end()); 1086 } 1087 if (std::find(stack.begin(), stack.end(), requiredModule) != stack.end()) { 1088 ASSERT(requiredModuleStatus == ModuleStatus::EVALUATING); 1089 } 1090 1091 if (requiredModuleStatus == ModuleStatus::EVALUATING) { 1092 int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex()); 1093 module->SetDFSAncestorIndex(dfsAncIdx); 1094 } else { 1095 requiredModule = JSHandle<SourceTextModule>(thread, requiredModule->GetCycleRoot()); 1096 requiredModuleStatus = requiredModule->GetStatus(); 1097 ASSERT(requiredModuleStatus == ModuleStatus::EVALUATING_ASYNC || 1098 requiredModuleStatus == ModuleStatus::EVALUATED); 1099 if (requiredModule->GetEvaluationError() != SourceTextModule::UNDEFINED_INDEX) { 1100 return requiredModule->GetEvaluationError(); 1101 } 1102 } 1103 if (requiredModule->IsAsyncEvaluating()) { 1104 module->SetPendingAsyncDependencies(module->GetPendingAsyncDependencies() + 1); 1105 AddAsyncParentModule(thread, requiredModule, module); 1106 } 1107 } 1108 } 1109 int pendingAsyncDependencies = module->GetPendingAsyncDependencies(); 1110 bool hasTLA = module->GetHasTLA(); 1111 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); 1112 // 12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is true, then 1113 if (pendingAsyncDependencies > 0 || hasTLA) { 1114 // a. Assert: module.[[AsyncEvaluation]] is false and was never previously set to true. 1115 ASSERT(module->GetAsyncEvaluatingOrdinal() == NOT_ASYNC_EVALUATED); 1116 // b. Set module.[[AsyncEvaluation]] to true. 1117 module->SetAsyncEvaluatingOrdinal(moduleManager->NextModuleAsyncEvaluatingOrdinal()); 1118 // d. If module.[[PendingAsyncDependencies]] = 0, perform ExecuteAsyncModule(module). 1119 if (pendingAsyncDependencies == 0) { 1120 SourceTextModule::ExecuteAsyncModule(thread, module, buffer, size, executeFromJob); 1121 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1122 } 1123 } else { 1124 // 13. Else, Perform ? module.ExecuteModule(). 1125 SourceTextModule::ModuleExecution(thread, module, buffer, size, executeFromJob); 1126 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1127 } 1128 // 14. Assert: module occurs exactly once in stack. 1129 // 15. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]]. 1130 int dfsAncIdx = module->GetDFSAncestorIndex(); 1131 int dfsIdx = module->GetDFSIndex(); 1132 ASSERT(dfsAncIdx <= dfsIdx); 1133 // 16. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then 1134 if (dfsAncIdx == dfsIdx) { 1135 // a. Let done be false. 1136 bool done = false; 1137 // b. Repeat, while done is false, 1138 while (!done) { 1139 // i. Let requiredModule be the last element in stack. 1140 JSHandle<SourceTextModule> requiredModule = stack.back(); 1141 // ii. Remove the last element of stack. 1142 stack.pop_back(); 1143 // iii. Assert: requiredModule is a Cyclic Module Record. 1144 // iv. If requiredModule.[[AsyncEvaluation]] is false, set requiredModule.[[Status]] to EVALUATED. 1145 // v. Otherwise, set requiredModule.[[Status]] to EVALUATING-ASYNC. 1146 if (!requiredModule->IsAsyncEvaluating()) { 1147 requiredModule->SetStatus(ModuleStatus::EVALUATED); 1148 } else { 1149 requiredModule->SetStatus(ModuleStatus::EVALUATING_ASYNC); 1150 } 1151 // vi. If requiredModule and module are the same Module Record, set done to true. 1152 if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) { 1153 done = true; 1154 } 1155 // vii. Set requiredModule.[[CycleRoot]] to module. 1156 if (!SourceTextModule::IsSharedModule(requiredModule)) { 1157 requiredModule->SetCycleRoot(thread, module); 1158 } 1159 } 1160 } 1161 return index; 1162} 1163bool SourceTextModule::IsEvaluatedModule(JSThread *thread, StateVisit &stateVisit, 1164 const JSHandle<SourceTextModule> &module) 1165{ 1166 return GetModuleEvaluatingType(thread, stateVisit, module) == ModuleStatus::EVALUATED; 1167} 1168 1169ModuleStatus SourceTextModule::GetModuleEvaluatingType(JSThread *thread, StateVisit &stateVisit, 1170 const JSHandle<SourceTextModule> &module) 1171{ 1172 RuntimeLockHolder locker(thread, stateVisit.mutex); 1173 return module->GetStatus(); 1174} 1175 1176int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<SourceTextModule> &module, 1177 CVector<JSHandle<SourceTextModule>> &stack, int index, 1178 const void *buffer, size_t size, bool executeFromJob) 1179{ 1180 bool isShared = IsSharedModule(module); 1181 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module); 1182 if (!isShared) { 1183 return SourceTextModule::InnerModuleEvaluationUnsafe( 1184 thread, moduleRecord, stack, index, buffer, size, executeFromJob); 1185 } else { 1186 StateVisit &stateVisit = SharedModuleManager::GetInstance()->findModuleMutexWithLock(thread, module); 1187 if (module->GetStatus() == ModuleStatus::EVALUATING && 1188 stateVisit.threadId == thread->GetThreadId()) { 1189 return index; 1190 } 1191 RuntimeLockHolder locker(thread, stateVisit.mutex); 1192 if (module->GetStatus() == ModuleStatus::INSTANTIATED) { 1193 stateVisit.threadId = thread->GetThreadId(); 1194 int idx = SourceTextModule::InnerModuleEvaluationUnsafe( 1195 thread, moduleRecord, stack, index, buffer, size, executeFromJob); 1196 return idx; 1197 } 1198 return index; 1199 } 1200 LOG_FULL(FATAL) << "This line is unreachable"; 1201 UNREACHABLE(); 1202} 1203 1204void SourceTextModule::HandleConcurrentEvaluateResult(JSThread *thread, JSHandle<SourceTextModule> &module, 1205 const CVector<JSHandle<SourceTextModule>> &stack, int result) 1206{ 1207 ModuleStatus status; 1208 // 9. If result is an abrupt completion, then 1209 if (thread->HasPendingException()) { 1210 // a. For each module m in stack, do 1211 for (auto mm : stack) { 1212 // i. Assert: m.[[Status]] is "evaluating". 1213 ASSERT(mm->GetStatus() == ModuleStatus::EVALUATING); 1214 // ii. Set m.[[Status]] to "evaluated". 1215 mm->SetStatus(ModuleStatus::EVALUATED); 1216 // iii. Set m.[[EvaluationError]] to result. 1217 mm->SetEvaluationError(result); 1218 } 1219 // b. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is result. 1220 status = module->GetStatus(); 1221 ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == result); 1222 // 10. Else, 1223 } else { 1224 // a. Assert: module.[[Status]] is either EVALUATING-ASYNC or EVALUATED. 1225 status = module->GetStatus(); 1226 ASSERT(status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED); 1227 // b. Assert: module.[[EvaluationError]] is EMPTY. 1228 ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX); 1229 // c. If module.[[AsyncEvaluation]] is false, then 1230 // i. Assert: module.[[Status]] is EVALUATED. 1231 if (!module->IsAsyncEvaluating()) { 1232 ASSERT(status == ModuleStatus::EVALUATED); 1233 } 1234 // d. Assert: stack is empty. 1235 ASSERT(stack.empty()); 1236 } 1237} 1238 1239int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord, 1240 int index, const JSHandle<Method> &method) 1241{ 1242 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord); 1243 if (!module->GetRequestedModules().IsUndefined()) { 1244 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules()); 1245 size_t requestedModulesLen = requestedModules->GetLength(); 1246 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined()); 1247 auto coRequestedModules = GetConcurrentRequestedModules(method); 1248 for (size_t idx = 0; idx < requestedModulesLen; idx++) { 1249 if (coRequestedModules.has_value() && coRequestedModules.value().count(idx) == 0) { 1250 // skip the unused module 1251 continue; 1252 } 1253 required.Update(requestedModules->Get(idx)); 1254 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined()); 1255 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1256 if (moduleRecordName.empty()) { 1257 requiredModule.Update(SourceTextModule::HostResolveImportedModule(thread, module, required)); 1258 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1259 } else { 1260 requiredModule.Update(SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required)); 1261 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1262 } 1263 ModuleTypes moduleType = requiredModule->GetTypes(); 1264 if (SourceTextModule::IsNativeModule(moduleType)) { 1265 EvaluateNativeModule(thread, requiredModule, moduleType); 1266 continue; 1267 } 1268 if (moduleType == ModuleTypes::JSON_MODULE) { 1269 requiredModule->SetStatus(ModuleStatus::EVALUATED); 1270 continue; 1271 } 1272 CVector<JSHandle<SourceTextModule>> stack; 1273 int result = SourceTextModule::InnerModuleEvaluation(thread, requiredModule, stack, 0); 1274 index += result; 1275 HandleConcurrentEvaluateResult(thread, requiredModule, stack, result); 1276 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); 1277 } 1278 } 1279 return index; 1280} 1281 1282Expected<JSTaggedValue, bool> SourceTextModule::ModuleExecution(JSThread *thread, 1283 const JSHandle<SourceTextModule> &module, const void *buffer, size_t size, bool executeFromJob) 1284{ 1285 CString moduleFilenameStr {}; 1286 if (thread->GetCurrentEcmaContext()->GetStageOfHotReload() == StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN) { 1287 moduleFilenameStr = thread->GetEcmaVM()->GetQuickFixManager()->GetBaseFileName(module); 1288 } else { 1289 moduleFilenameStr = module->GetEcmaModuleFilenameString(); 1290 } 1291 std::string entryPoint; 1292 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1293 if (moduleRecordName.empty()) { 1294 entryPoint = JSPandaFile::ENTRY_FUNCTION_NAME; 1295 } else { 1296 entryPoint = moduleRecordName; 1297 } 1298 1299 std::shared_ptr<JSPandaFile> jsPandaFile; 1300 if (buffer != nullptr) { 1301 jsPandaFile = 1302 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint, buffer, size); 1303 } else { 1304 jsPandaFile = 1305 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint); 1306 } 1307 1308 if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE 1309 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << moduleFilenameStr; 1310 } 1311 return JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entryPoint, executeFromJob); 1312} 1313 1314void SourceTextModule::AddImportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module, 1315 const JSHandle<ImportEntry> &importEntry, size_t idx, uint32_t len) 1316{ 1317 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1318 JSTaggedValue importEntries = module->GetImportEntries(); 1319 if (importEntries.IsUndefined()) { 1320 JSHandle<TaggedArray> array = factory->NewTaggedArray(len); 1321 array->Set(thread, idx, importEntry.GetTaggedValue()); 1322 module->SetImportEntries(thread, array); 1323 } else { 1324 JSHandle<TaggedArray> entries(thread, importEntries); 1325 if (len > entries->GetLength()) { 1326 entries = TaggedArray::SetCapacity(thread, entries, len); 1327 entries->Set(thread, idx, importEntry.GetTaggedValue()); 1328 module->SetImportEntries(thread, entries); 1329 return; 1330 } 1331 entries->Set(thread, idx, importEntry.GetTaggedValue()); 1332 } 1333} 1334 1335void SourceTextModule::AddLocalExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module, 1336 const JSHandle<LocalExportEntry> &exportEntry, size_t idx, uint32_t len) 1337{ 1338 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1339 JSTaggedValue localExportEntries = module->GetLocalExportEntries(); 1340 if (localExportEntries.IsUndefined()) { 1341 JSHandle<TaggedArray> array = factory->NewTaggedArray(len); 1342 array->Set(thread, idx, exportEntry.GetTaggedValue()); 1343 module->SetLocalExportEntries(thread, array); 1344 } else { 1345 JSHandle<TaggedArray> entries(thread, localExportEntries); 1346 entries->Set(thread, idx, exportEntry.GetTaggedValue()); 1347 } 1348} 1349 1350void SourceTextModule::AddIndirectExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module, 1351 const JSHandle<IndirectExportEntry> &exportEntry, 1352 size_t idx, uint32_t len) 1353{ 1354 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1355 JSTaggedValue indirectExportEntries = module->GetIndirectExportEntries(); 1356 if (indirectExportEntries.IsUndefined()) { 1357 JSHandle<TaggedArray> array = factory->NewTaggedArray(len); 1358 array->Set(thread, idx, exportEntry.GetTaggedValue()); 1359 module->SetIndirectExportEntries(thread, array); 1360 } else { 1361 JSHandle<TaggedArray> entries(thread, indirectExportEntries); 1362 entries->Set(thread, idx, exportEntry.GetTaggedValue()); 1363 } 1364} 1365 1366void SourceTextModule::AddStarExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module, 1367 const JSHandle<StarExportEntry> &exportEntry, size_t idx, uint32_t len) 1368{ 1369 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1370 JSTaggedValue starExportEntries = module->GetStarExportEntries(); 1371 if (starExportEntries.IsUndefined()) { 1372 JSHandle<TaggedArray> array = factory->NewTaggedArray(len); 1373 array->Set(thread, idx, exportEntry.GetTaggedValue()); 1374 module->SetStarExportEntries(thread, array); 1375 } else { 1376 JSHandle<TaggedArray> entries(thread, starExportEntries); 1377 entries->Set(thread, idx, exportEntry.GetTaggedValue()); 1378 } 1379} 1380 1381JSTaggedValue SourceTextModule::GetModuleValue(JSThread *thread, int32_t index, bool isThrow) 1382{ 1383 DISALLOW_GARBAGE_COLLECTION; 1384 JSTaggedValue dictionary = GetNameDictionary(); 1385 if (dictionary.IsUndefined()) { 1386 if (isThrow) { 1387 THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", JSTaggedValue::Exception()); 1388 } 1389 return JSTaggedValue::Hole(); 1390 } 1391 1392 TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject()); 1393 return array->Get(index); 1394} 1395 1396JSTaggedValue SourceTextModule::GetModuleValue(JSThread *thread, JSTaggedValue key, bool isThrow) 1397{ 1398 DISALLOW_GARBAGE_COLLECTION; 1399 JSTaggedValue dictionary = GetNameDictionary(); 1400 if (dictionary.IsUndefined()) { 1401 if (isThrow) { 1402 THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", JSTaggedValue::Exception()); 1403 } 1404 return JSTaggedValue::Hole(); 1405 } 1406 1407 NameDictionary *dict = NameDictionary::Cast(dictionary.GetTaggedObject()); 1408 int entry = dict->FindEntry(key); 1409 if (entry != -1) { 1410 return dict->GetValue(entry); 1411 } 1412 1413 // when key is exportName, need to get localName 1414 JSTaggedValue exportEntriesTv = GetLocalExportEntries(); 1415 if (!exportEntriesTv.IsUndefined()) { 1416 JSTaggedValue resolution = FindByExport(exportEntriesTv, key, dictionary); 1417 if (!resolution.IsHole()) { 1418 return resolution; 1419 } 1420 } 1421 1422 return JSTaggedValue::Hole(); 1423} 1424 1425JSTaggedValue SourceTextModule::GetValueFromExportObject(JSThread *thread, JSHandle<JSTaggedValue> &exportObject, 1426 int32_t index) 1427{ 1428 if (index == SourceTextModule::UNDEFINED_INDEX) { 1429 return exportObject.GetTaggedValue(); 1430 } 1431 return ObjectFastOperator::FastGetPropertyByPorpsIndex(thread, exportObject.GetTaggedValue(), index); 1432} 1433 1434JSTaggedValue SourceTextModule::FindByExport(const JSTaggedValue &exportEntriesTv, const JSTaggedValue &key, 1435 const JSTaggedValue &dictionary) 1436{ 1437 DISALLOW_GARBAGE_COLLECTION; 1438 NameDictionary *dict = NameDictionary::Cast(dictionary.GetTaggedObject()); 1439 TaggedArray *exportEntries = TaggedArray::Cast(exportEntriesTv.GetTaggedObject()); 1440 size_t exportEntriesLen = exportEntries->GetLength(); 1441 for (size_t idx = 0; idx < exportEntriesLen; idx++) { 1442 LocalExportEntry *ee = LocalExportEntry::Cast(exportEntries->Get(idx).GetTaggedObject()); 1443 if (!JSTaggedValue::SameValue(ee->GetExportName(), key)) { 1444 continue; 1445 } 1446 JSTaggedValue localName = ee->GetLocalName(); 1447 int entry = dict->FindEntry(localName); 1448 if (entry != -1) { 1449 return dict->GetValue(entry); 1450 } 1451 } 1452 1453 return JSTaggedValue::Hole(); 1454} 1455 1456void SourceTextModule::StoreModuleValue(JSThread *thread, int32_t index, const JSHandle<JSTaggedValue> &value) 1457{ 1458 JSHandle<SourceTextModule> module(thread, this); 1459 JSTaggedValue localExportEntries = module->GetLocalExportEntries(); 1460 ASSERT(localExportEntries.IsTaggedArray()); 1461 1462 JSHandle<JSTaggedValue> data(thread, module->GetNameDictionary()); 1463 if (data->IsUndefined()) { 1464 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1465 uint32_t size = TaggedArray::Cast(localExportEntries.GetTaggedObject())->GetLength(); 1466 ASSERT(index < static_cast<int32_t>(size)); 1467 if (SourceTextModule::IsSharedModule(module)) { 1468 data = JSHandle<JSTaggedValue>(factory->NewSTaggedArray(size, 1469 JSTaggedValue::Hole(), MemSpaceType::SHARED_OLD_SPACE)); 1470 } else { 1471 data = JSHandle<JSTaggedValue>(factory->NewTaggedArray(size)); 1472 } 1473 module->SetNameDictionary(thread, data); 1474 } 1475 JSHandle<TaggedArray> arr(data); 1476 arr->Set(thread, index, value); 1477} 1478 1479// discard instructions won't consider shared-module. 1480void SourceTextModule::StoreModuleValue(JSThread *thread, const JSHandle<JSTaggedValue> &key, 1481 const JSHandle<JSTaggedValue> &value) 1482{ 1483 JSHandle<SourceTextModule> module(thread, this); 1484 JSMutableHandle<JSTaggedValue> data(thread, module->GetNameDictionary()); 1485 if (data->IsUndefined()) { 1486 data.Update(NameDictionary::Create(thread, DEFAULT_DICTIONART_CAPACITY)); 1487 } 1488 JSHandle<NameDictionary> dataDict = JSHandle<NameDictionary>::Cast(data); 1489 data.Update(NameDictionary::Put(thread, dataDict, key, value, PropertyAttributes::Default())); 1490 1491 module->SetNameDictionary(thread, data); 1492} 1493 1494void SourceTextModule::SetExportName(JSThread *thread, const JSHandle<JSTaggedValue> &moduleRequest, 1495 const JSHandle<SourceTextModule> &module, 1496 CVector<std::string> &exportedNames, JSHandle<TaggedArray> &newExportStarSet) 1497 1498{ 1499 JSMutableHandle<SourceTextModule> requestedModule(thread, thread->GlobalConstants()->GetUndefined()); 1500 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1501 if (moduleRecordName.empty()) { 1502 JSHandle<JSTaggedValue> requestedVal = 1503 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); 1504 RETURN_IF_ABRUPT_COMPLETION(thread); 1505 requestedModule.Update(JSHandle<SourceTextModule>::Cast(requestedVal)); 1506 } else { 1507 JSHandle<JSTaggedValue> requestedVal = 1508 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest); 1509 RETURN_IF_ABRUPT_COMPLETION(thread); 1510 requestedModule.Update(JSHandle<SourceTextModule>::Cast(requestedVal)); 1511 } 1512 // b. Let starNames be ? requestedModule.GetExportedNames(exportStarSet). 1513 CVector<std::string> starNames = 1514 SourceTextModule::GetExportedNames(thread, requestedModule, newExportStarSet); 1515 // c. For each element n of starNames, do 1516 for (std::string &nn : starNames) { 1517 // i. If SameValue(n, "default") is false, then 1518 if (nn != "default" && std::find(exportedNames.begin(), exportedNames.end(), nn) == exportedNames.end()) { 1519 // 1. If n is not an element of exportedNames, then 1520 // a. Append n to exportedNames. 1521 exportedNames.emplace_back(nn); 1522 } 1523 } 1524} 1525 1526JSHandle<JSTaggedValue> SourceTextModule::GetStarResolution(JSThread *thread, 1527 const JSHandle<JSTaggedValue> &exportName, 1528 const JSHandle<JSTaggedValue> &moduleRequest, 1529 const JSHandle<SourceTextModule> &module, 1530 JSMutableHandle<JSTaggedValue> &starResolution, 1531 CVector<std::pair<JSHandle<SourceTextModule>, 1532 JSHandle<JSTaggedValue>>> &resolveVector) 1533{ 1534 auto globalConstants = thread->GlobalConstants(); 1535 // a. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]). 1536 JSMutableHandle<SourceTextModule> importedModule(thread, thread->GlobalConstants()->GetUndefined()); 1537 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1538 if (moduleRecordName.empty()) { 1539 JSHandle<JSTaggedValue> importedVal = 1540 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); 1541 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 1542 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal)); 1543 } else { 1544 JSHandle<JSTaggedValue> importedVal = 1545 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest); 1546 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 1547 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal)); 1548 } 1549 // b. Let resolution be ? importedModule.ResolveExport(exportName, resolveVector). 1550 auto moduleType = importedModule->GetTypes(); 1551 bool isNativeModule = IsNativeModule(moduleType); 1552 JSHandle<JSTaggedValue> resolution; 1553 if (UNLIKELY(isNativeModule || moduleType == ModuleTypes::CJS_MODULE)) { 1554 resolution = isNativeModule 1555 ? SourceTextModule::ResolveNativeStarExport(thread, importedModule, exportName) 1556 : SourceTextModule::ResolveCjsStarExport(thread, importedModule, exportName); 1557 } else { 1558 resolution = SourceTextModule::ResolveExport(thread, importedModule, exportName, resolveVector); 1559 } 1560 1561 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 1562 // c. If resolution is "ambiguous", return "ambiguous". 1563 if (resolution->IsString()) { // if resolution is string, resolution must be "ambiguous" 1564 return globalConstants->GetHandledAmbiguousString(); 1565 } 1566 // d. If resolution is not null, then 1567 if (resolution->IsNull()) { 1568 return globalConstants->GetHandledNull(); 1569 } 1570 // i. Assert: resolution is a ResolvedBinding Record. 1571 ASSERT(resolution->IsResolvedBinding() || resolution->IsResolvedIndexBinding()); 1572 // ii. If starResolution is null, set starResolution to resolution. 1573 if (starResolution->IsNull()) { 1574 starResolution.Update(resolution.GetTaggedValue()); 1575 } else { 1576 // 1. Assert: There is more than one * import that includes the requested name. 1577 // 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record or 1578 // SameValue( 1579 // resolution.[[BindingName]], starResolution.[[BindingName]]) is false, return "ambiguous". 1580 // Adapter new opcode 1581 if (resolution->IsResolvedBinding()) { 1582 JSHandle<ResolvedBinding> resolutionBd = JSHandle<ResolvedBinding>::Cast(resolution); 1583 JSHandle<ResolvedBinding> starResolutionBd = JSHandle<ResolvedBinding>::Cast(starResolution); 1584 if ((!JSTaggedValue::SameValue(resolutionBd->GetModule(), starResolutionBd->GetModule())) || 1585 (!JSTaggedValue::SameValue( 1586 resolutionBd->GetBindingName(), starResolutionBd->GetBindingName()))) { 1587 return globalConstants->GetHandledAmbiguousString(); 1588 } 1589 } else { 1590 JSHandle<ResolvedIndexBinding> resolutionBd = JSHandle<ResolvedIndexBinding>::Cast(resolution); 1591 JSHandle<ResolvedIndexBinding> starResolutionBd = JSHandle<ResolvedIndexBinding>::Cast(starResolution); 1592 if ((!JSTaggedValue::SameValue(resolutionBd->GetModule(), starResolutionBd->GetModule())) || 1593 resolutionBd->GetIndex() != starResolutionBd->GetIndex()) { 1594 return globalConstants->GetHandledAmbiguousString(); 1595 } 1596 } 1597 } 1598 return resolution; 1599} 1600 1601template <typename T> 1602void SourceTextModule::AddExportName(JSThread *thread, const JSTaggedValue &exportEntry, 1603 CVector<std::string> &exportedNames) 1604{ 1605 if (!exportEntry.IsUndefined()) { 1606 JSMutableHandle<T> ee(thread, thread->GlobalConstants()->GetUndefined()); 1607 JSHandle<TaggedArray> exportEntries(thread, exportEntry); 1608 size_t exportEntriesLen = exportEntries->GetLength(); 1609 for (size_t idx = 0; idx < exportEntriesLen; idx++) { 1610 ee.Update(exportEntries->Get(idx)); 1611 // a. Assert: module provides the direct binding for this export. 1612 // b. Append e.[[ExportName]] to exportedNames. 1613 std::string exportName = EcmaStringAccessor(ee->GetExportName()).ToStdString(); 1614 exportedNames.emplace_back(exportName); 1615 } 1616 } 1617} 1618 1619JSHandle<JSTaggedValue> SourceTextModule::ResolveElementOfObject(JSThread *thread, 1620 const JSHandle<JSHClass> &hclass, 1621 const JSHandle<JSTaggedValue> &exportName, 1622 const JSHandle<SourceTextModule> &module) 1623{ 1624 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1625 int idx = JSHClass::FindPropertyEntry(thread, *hclass, exportName.GetTaggedValue()); 1626 if (idx != -1) { 1627 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, idx)); 1628 } 1629 return thread->GlobalConstants()->GetHandledUndefined(); 1630} 1631 1632JSHandle<JSTaggedValue> SourceTextModule::ResolveLocalExport(JSThread *thread, 1633 const JSHandle<JSTaggedValue> &exportEntry, 1634 const JSHandle<JSTaggedValue> &exportName, 1635 const JSHandle<SourceTextModule> &module) 1636{ 1637 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1638 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); 1639 JSMutableHandle<JSTaggedValue> localName(thread, thread->GlobalConstants()->GetUndefined()); 1640 1641 JSHandle<TaggedArray> localExportEntries(exportEntry); 1642 size_t localExportEntriesLen = localExportEntries->GetLength(); 1643 for (size_t idx = 0; idx < localExportEntriesLen; idx++) { 1644 ee.Update(localExportEntries->Get(idx)); 1645 // a. If SameValue(exportName, e.[[ExportName]]) is true, then 1646 // if module is type of CommonJS or native, export first, check after execution. 1647 auto moduleType = module->GetTypes(); 1648 if (IsNativeModule(moduleType) || moduleType == ModuleTypes::CJS_MODULE) { 1649 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedBindingRecord(module, exportName)); 1650 } 1651 1652 if ((JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue()))) { 1653 // Adapter new module 1654 if (module->GetIsNewBcVersion()) { 1655 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, 1656 ee->GetLocalIndex())); 1657 } 1658 // i. Assert: module provides the direct binding for this export. 1659 // ii. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }. 1660 localName.Update(ee->GetLocalName()); 1661 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedBindingRecord(module, localName)); 1662 } 1663 } 1664 return thread->GlobalConstants()->GetHandledUndefined(); 1665} 1666 1667JSHandle<JSTaggedValue> SourceTextModule::ResolveIndirectExport(JSThread *thread, 1668 const JSHandle<JSTaggedValue> &exportEntry, 1669 const JSHandle<JSTaggedValue> &exportName, 1670 const JSHandle<SourceTextModule> &module, 1671 CVector<std::pair<JSHandle<SourceTextModule>, 1672 JSHandle<JSTaggedValue>>> &resolveVector) 1673{ 1674 auto globalConstants = thread->GlobalConstants(); 1675 JSTaggedValue undefined = globalConstants->GetUndefined(); 1676 JSMutableHandle<IndirectExportEntry> ee(thread, undefined); 1677 JSMutableHandle<JSTaggedValue> moduleRequest(thread, undefined); 1678 JSMutableHandle<JSTaggedValue> importName(thread, undefined); 1679 JSHandle<TaggedArray> indirectExportEntries(exportEntry); 1680 size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); 1681 for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { 1682 ee.Update(indirectExportEntries->Get(idx)); 1683 // a. If SameValue(exportName, e.[[ExportName]]) is true, then 1684 if (JSTaggedValue::SameValue(exportName.GetTaggedValue(), ee->GetExportName())) { 1685 // i. Assert: module imports a specific binding for this export. 1686 // ii. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]). 1687 moduleRequest.Update(ee->GetModuleRequest()); 1688 JSMutableHandle<SourceTextModule> requestedModule(thread, undefined); 1689 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1690 if (moduleRecordName.empty()) { 1691 requestedModule.Update(SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest)); 1692 } else { 1693 requestedModule.Update( 1694 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest)); 1695 } 1696 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); 1697 // iii. Return importedModule.ResolveExport(e.[[ImportName]], resolveVector). 1698 importName.Update(ee->GetImportName()); 1699 return SourceTextModule::ResolveExport(thread, requestedModule, importName, resolveVector); 1700 } 1701 } 1702 return thread->GlobalConstants()->GetHandledUndefined(); 1703} 1704 1705void SourceTextModule::CheckResolvedBinding(JSThread *thread, const JSHandle<SourceTextModule> &module) 1706{ 1707 auto globalConstants = thread->GlobalConstants(); 1708 // 1. For each ExportEntry Record e in module.[[IndirectExportEntries]], do 1709 JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries(); 1710 if (indirectExportEntriesTv.IsUndefined()) { 1711 return; 1712 } 1713 1714 JSMutableHandle<IndirectExportEntry> ee(thread, globalConstants->GetUndefined()); 1715 JSMutableHandle<JSTaggedValue> exportName(thread, globalConstants->GetUndefined()); 1716 JSHandle<TaggedArray> indirectExportEntries(thread, indirectExportEntriesTv); 1717 size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); 1718 for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { 1719 ee.Update(indirectExportEntries->Get(idx)); 1720 // a. Let resolution be ? module.ResolveExport(e.[[ExportName]], « »). 1721 exportName.Update(ee->GetExportName()); 1722 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector; 1723 JSHandle<JSTaggedValue> resolution = 1724 SourceTextModule::ResolveExport(thread, module, exportName, resolveVector); 1725 RETURN_IF_ABRUPT_COMPLETION(thread); 1726 // b. If resolution is null or "ambiguous", throw a SyntaxError exception. 1727 if (resolution->IsNull() || resolution->IsString()) { 1728 CString requestMod = ModulePathHelper::ReformatPath(ConvertToString(ee->GetModuleRequest())); 1729 CString msg = "the requested module '" + requestMod + GetResolveErrorReason(resolution) + 1730 ConvertToString(exportName.GetTaggedValue()); 1731 if (!module->GetEcmaModuleRecordNameString().empty()) { 1732 CString recordStr = ModulePathHelper::ReformatPath(module->GetEcmaModuleRecordNameString()); 1733 msg += "' which exported by '" + recordStr + "'"; 1734 } else { 1735 msg += "' which exported by '" + module->GetEcmaModuleFilenameString() + "'"; 1736 } 1737 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str()); 1738 } 1739 // c. Assert: resolution is a ResolvedBinding Record. 1740 ASSERT(resolution->IsResolvedBinding()); 1741 } 1742} 1743 1744void SourceTextModule::CheckResolvedIndexBinding(JSThread *thread, const JSHandle<SourceTextModule> &module) 1745{ 1746 auto globalConstants = thread->GlobalConstants(); 1747 // 1. For each ExportEntry Record e in module.[[IndirectExportEntries]], do 1748 JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries(); 1749 if (indirectExportEntriesTv.IsUndefined()) { 1750 return; 1751 } 1752 1753 JSMutableHandle<IndirectExportEntry> ee(thread, globalConstants->GetUndefined()); 1754 JSMutableHandle<JSTaggedValue> exportName(thread, globalConstants->GetUndefined()); 1755 JSHandle<TaggedArray> indirectExportEntries(thread, indirectExportEntriesTv); 1756 size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); 1757 for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { 1758 ee.Update(indirectExportEntries->Get(idx)); 1759 // a. Let resolution be ? module.ResolveExport(e.[[ExportName]], « »). 1760 exportName.Update(ee->GetExportName()); 1761 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector; 1762 JSHandle<JSTaggedValue> resolution = 1763 SourceTextModule::ResolveExport(thread, module, exportName, resolveVector); 1764 RETURN_IF_ABRUPT_COMPLETION(thread); 1765 // b. If resolution is null or "ambiguous", throw a SyntaxError exception. 1766 if (resolution->IsNull() || resolution->IsString()) { 1767 CString requestMod = ModulePathHelper::ReformatPath(ConvertToString(ee->GetModuleRequest())); 1768 CString msg = "the requested module '" + requestMod + GetResolveErrorReason(resolution) + 1769 ConvertToString(exportName.GetTaggedValue()); 1770 if (!module->GetEcmaModuleRecordNameString().empty()) { 1771 CString record = ModulePathHelper::ReformatPath(module->GetEcmaModuleRecordNameString()); 1772 msg += "' which exported by '" + record + "'"; 1773 } else { 1774 msg += "' which exported by '" + module->GetEcmaModuleFilenameString() + "'"; 1775 } 1776 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str()); 1777 } 1778 } 1779} 1780 1781CString SourceTextModule::GetModuleName(JSTaggedValue currentModule) 1782{ 1783 SourceTextModule *module = SourceTextModule::Cast(currentModule.GetTaggedObject()); 1784 CString recordName = module->GetEcmaModuleRecordNameString(); 1785 if (recordName.empty()) { 1786 recordName = module->GetEcmaModuleFilenameString(); 1787 } 1788 return recordName; 1789} 1790 1791bool SourceTextModule::IsDynamicModule(LoadingTypes types) 1792{ 1793 return types == LoadingTypes::DYNAMITC_MODULE; 1794} 1795 1796bool SourceTextModule::IsAsyncEvaluating() 1797{ 1798 return GetAsyncEvaluatingOrdinal() >= FIRST_ASYNC_EVALUATING_ORDINAL; 1799} 1800 1801void SourceTextModule::AddAsyncParentModule(JSThread *thread, JSHandle<SourceTextModule> &module, 1802 JSHandle<SourceTextModule> &parent) 1803{ 1804 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1805 JSTaggedValue asyncParentModules = module->GetAsyncParentModules(); 1806 if (asyncParentModules.IsUndefined()) { 1807 JSHandle<TaggedArray> array = factory->NewTaggedArray(1); 1808 array->Set(thread, 0, parent.GetTaggedValue()); 1809 module->SetAsyncParentModules(thread, array); 1810 } else { 1811 JSHandle<TaggedArray> array(thread, asyncParentModules); 1812 ASSERT(array->GetLength() > 0); 1813 array = TaggedArray::SetCapacity(thread, array, array->GetLength() + 1); 1814 array->Set(thread, array->GetLength() - 1, parent.GetTaggedValue()); 1815 module->SetAsyncParentModules(thread, array); 1816 } 1817} 1818 1819void SourceTextModule::ExecuteAsyncModule(JSThread *thread, const JSHandle<SourceTextModule> &module, 1820 const void *buffer, size_t size, bool executeFromJob) 1821{ 1822 // 1. Assert: module.[[Status]] is either EVALUATING or EVALUATING-ASYNC. 1823 ASSERT(module->GetStatus() == ModuleStatus::EVALUATING || module->GetStatus() == ModuleStatus::EVALUATING_ASYNC); 1824 // 2. Assert: module.[[HasTLA]] is true. 1825 ASSERT(module->GetHasTLA()); 1826 CString moduleFilenameStr = module->GetEcmaModuleFilenameString(); 1827 1828 std::string entryPoint; 1829 CString moduleRecordName = module->GetEcmaModuleRecordNameString(); 1830 if (moduleRecordName.empty()) { 1831 entryPoint = JSPandaFile::ENTRY_FUNCTION_NAME; 1832 } else { 1833 entryPoint = moduleRecordName; 1834 } 1835 1836 std::shared_ptr<JSPandaFile> jsPandaFile; 1837 if (buffer != nullptr) { 1838 jsPandaFile = 1839 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint, buffer, size); 1840 } else { 1841 jsPandaFile = 1842 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint); 1843 } 1844 1845 if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE 1846 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << moduleFilenameStr; 1847 } 1848 Expected<JSTaggedValue, bool> result = 1849 JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entryPoint, executeFromJob); 1850 ASSERT(result.Value().IsJSPromise()); 1851 // 3. Let capability be ! NewPromiseCapability(%Promise%). 1852 // 4. Let fulfilledClosure be a new Abstract Closure with no parameters that captures module and performs 1853 // the following steps when called: 1854 // a. Perform AsyncModuleExecutionFulfilled(module). 1855 // b. Return undefined. 1856 // 5. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »). 1857 // 6. Let rejectedClosure be a new Abstract Closure with parameters (error) that captures module and performs 1858 // the following steps when called: 1859 // a. Perform AsyncModuleExecutionRejected(module, error). 1860 // b. Return undefined. 1861 // 7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 0, "", « »). 1862 // 8. Perform PerformPromiseThen(capability.[[Promise]], onFulfilled, onRejected). 1863 JSHandle<JSPromise> promise(thread, result.Value()); 1864 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 1865 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1866 JSHandle<JSAsyncModuleFulfilledFunction> onFulfilled = 1867 factory->CreateJSAsyncModuleFulfilledFunction(); 1868 onFulfilled->SetModule(thread, module); 1869 1870 JSHandle<JSAsyncModuleRejectedFunction> onRejected = 1871 factory->CreateJSAsyncModuleRejectedFunction(); 1872 onRejected->SetModule(thread, module); 1873 JSHandle<PromiseCapability> tcap = 1874 JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction())); 1875 RETURN_IF_ABRUPT_COMPLETION(thread); 1876 builtins::BuiltinsPromise::PerformPromiseThen( 1877 thread, promise, JSHandle<JSTaggedValue>::Cast(onFulfilled), 1878 JSHandle<JSTaggedValue>::Cast(onRejected), tcap); 1879} 1880 1881void SourceTextModule::GatherAvailableAncestors(JSThread *thread, const JSHandle<SourceTextModule> &module, 1882 AsyncParentCompletionSet &execList) 1883{ 1884 auto globalConstants = thread->GlobalConstants(); 1885 JSTaggedValue asyncParentModulesValue = module->GetAsyncParentModules(); 1886 if (asyncParentModulesValue.IsUndefined()) { 1887 return; 1888 } 1889 JSMutableHandle<SourceTextModule> cycleRoot(thread, globalConstants->GetUndefined()); 1890 JSHandle<TaggedArray> asyncParentModules(thread, asyncParentModulesValue); 1891 size_t asyncParentModulesLen = asyncParentModules->GetLength(); 1892 // 1. For each Cyclic Module Record m of module.[[AsyncParentModules]], do 1893 for (size_t idx = 0; idx < asyncParentModulesLen; idx++) { 1894 JSHandle<SourceTextModule> parentModule(thread, asyncParentModules->Get(idx)); 1895 // a. If execList does not contain m and m.[[CycleRoot]].[[EvaluationError]] is EMPTY, then 1896 cycleRoot.Update(parentModule->GetCycleRoot()); 1897 if (execList.find(parentModule) == execList.end() && 1898 cycleRoot->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX) { 1899 // i. Assert: m.[[Status]] is EVALUATING-ASYNC. 1900 ASSERT(parentModule->GetStatus() == ModuleStatus::EVALUATING_ASYNC); 1901 // ii. Assert: m.[[EvaluationError]] is EMPTY. 1902 ASSERT(parentModule->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX); 1903 // iii. Assert: m.[[AsyncEvaluation]] is true. 1904 ASSERT(parentModule->IsAsyncEvaluating()); 1905 // iv. Assert: m.[[PendingAsyncDependencies]] > 0. 1906 ASSERT(parentModule->GetPendingAsyncDependencies() > 0); 1907 // v. Set m.[[PendingAsyncDependencies]] to m.[[PendingAsyncDependencies]] - 1. 1908 parentModule->SetPendingAsyncDependencies(parentModule->GetPendingAsyncDependencies() - 1); 1909 // vi. If m.[[PendingAsyncDependencies]] = 0, then 1910 // 1. Append m to execList. 1911 // 2. If m.[[HasTLA]] is false, perform GatherAvailableAncestors(m, execList). 1912 if (parentModule->GetPendingAsyncDependencies() == 0) { 1913 execList.insert(parentModule); 1914 if (!parentModule->GetHasTLA()) { 1915 GatherAvailableAncestors(thread, parentModule, execList); 1916 } 1917 } 1918 } 1919 } 1920} 1921 1922void SourceTextModule::AsyncModuleExecutionFulfilled(JSThread *thread, const JSHandle<SourceTextModule> &module) 1923{ 1924 // 1. If module.[[Status]] is EVALUATED, then 1925 // a. Assert: module.[[EvaluationError]] is not EMPTY. 1926 // b. Return UNUSED. 1927 if (module->GetStatus() == ModuleStatus::EVALUATED) { 1928 ASSERT(module->GetEvaluationError() != SourceTextModule::UNDEFINED_INDEX); 1929 return; 1930 } 1931 // 2. Assert: module.[[Status]] is EVALUATING-ASYNC. 1932 ASSERT(module->GetStatus() == ModuleStatus::EVALUATING_ASYNC); 1933 // 3. Assert: module.[[AsyncEvaluation]] is true. 1934 ASSERT(module->IsAsyncEvaluating()); 1935 // 4. Assert: module.[[EvaluationError]] is EMPTY. 1936 ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX); 1937 // 5. Set module.[[AsyncEvaluation]] to false. 1938 module->SetAsyncEvaluatingOrdinal(ASYNC_EVALUATE_DID_FINISH); 1939 // 6. Set module.[[Status]] to EVALUATED. 1940 module->SetStatus(ModuleStatus::EVALUATED); 1941 // 7. If module.[[TopLevelCapability]] is not EMPTY, then 1942 // a. Assert: module.[[CycleRoot]] is module. 1943 // b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »). 1944 auto globalConstants = thread->GlobalConstants(); 1945 JSTaggedValue topLevelCapabilityValue = module->GetTopLevelCapability(); 1946 if (!topLevelCapabilityValue.IsUndefined()) { 1947 ASSERT(JSTaggedValue::SameValue(module->GetCycleRoot(), module.GetTaggedValue())); 1948 JSHandle<PromiseCapability> topLevelCapability(thread, topLevelCapabilityValue); 1949 JSHandle<JSTaggedValue> resolve(thread, topLevelCapability->GetResolve()); 1950 JSHandle<JSTaggedValue> undefined = globalConstants->GetHandledUndefined(); 1951 EcmaRuntimeCallInfo *info = 1952 EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1); 1953 RETURN_IF_ABRUPT_COMPLETION(thread); 1954 info->SetCallArg(JSTaggedValue::Undefined()); 1955 [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info); 1956 RETURN_IF_ABRUPT_COMPLETION(thread); 1957 } 1958 // 8. Let execList be a new empty List. 1959 AsyncParentCompletionSet execList; 1960 // 9. Perform GatherAvailableAncestors(module, execList). 1961 // 10. Let sortedExecList be a List whose elements are the elements of execList, 1962 // in the order in which they had their [[AsyncEvaluation]] fields set to true in InnerModuleEvaluation. 1963 GatherAvailableAncestors(thread, module, execList); 1964 // 11. Assert: All elements of sortedExecList have their [[AsyncEvaluation]] field set to true, 1965 // [[PendingAsyncDependencies]] field set to 0, and [[EvaluationError]] field set to EMPTY. 1966 // 12. For each Cyclic Module Record m of sortedExecList, do 1967 for (JSHandle<SourceTextModule> m : execList) { 1968 // a. If m.[[Status]] is EVALUATED, then 1969 // i. Assert: m.[[EvaluationError]] is not EMPTY. 1970 if (m->GetStatus() == ModuleStatus::EVALUATED) { 1971 ASSERT(m->GetEvaluationError() != UNDEFINED_INDEX); 1972 // b. Else if m.[[HasTLA]] is true, then 1973 // i. Perform ExecuteAsyncModule(m). 1974 } else if (m->GetHasTLA()) { 1975 ExecuteAsyncModule(thread, m); 1976 // c. Else, 1977 } else { 1978 // i. Let result be m.ExecuteModule(). 1979 Expected<JSTaggedValue, bool> result = SourceTextModule::ModuleExecution(thread, m); 1980 // ii. If result is an abrupt completion, then 1981 // 1. Perform AsyncModuleExecutionRejected(m, result.[[Value]]). 1982 if (thread->HasPendingException() || !result || result.Value().IsException()) { 1983 AsyncModuleExecutionRejected(thread, m, JSTaggedValue::Exception()); 1984 // iii. Else, 1985 } else { 1986 // 1. Set m.[[Status]] to EVALUATED. 1987 m->SetStatus(ModuleStatus::EVALUATED); 1988 // 2. If m.[[TopLevelCapability]] is not EMPTY, then 1989 // a. Assert: m.[[CycleRoot]] is m. 1990 // b. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »). 1991 JSTaggedValue capabilityValue = m->GetTopLevelCapability(); 1992 if (!capabilityValue.IsUndefined()) { 1993 ASSERT(JSTaggedValue::SameValue(m->GetCycleRoot(), m.GetTaggedValue())); 1994 JSHandle<PromiseCapability> topLevelCapability(thread, capabilityValue); 1995 JSHandle<JSTaggedValue> resolve(thread, topLevelCapability->GetResolve()); 1996 JSHandle<JSTaggedValue> undefined = globalConstants->GetHandledUndefined(); 1997 EcmaRuntimeCallInfo *info = 1998 EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1); 1999 RETURN_IF_ABRUPT_COMPLETION(thread); 2000 info->SetCallArg(JSTaggedValue::Undefined()); 2001 [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info); 2002 RETURN_IF_ABRUPT_COMPLETION(thread); 2003 } 2004 } 2005 } 2006 } 2007} 2008 2009void SourceTextModule::AsyncModuleExecutionRejected(JSThread *thread, const JSHandle<SourceTextModule> &module, 2010 JSTaggedValue error) 2011{ 2012 // 1. If module.[[Status]] is EVALUATED, then 2013 // a. Assert: module.[[EvaluationError]] is not EMPTY. 2014 // b. Return UNUSED. 2015 if (module->GetStatus() == ModuleStatus::EVALUATED) { 2016 ASSERT(module->GetEvaluationError() != SourceTextModule::UNDEFINED_INDEX); 2017 return; 2018 } 2019 // 2. Assert: module.[[Status]] is EVALUATING-ASYNC. 2020 ASSERT(module->GetStatus() == ModuleStatus::EVALUATING_ASYNC); 2021 // 3. Assert: module.[[AsyncEvaluation]] is true. 2022 ASSERT(module->IsAsyncEvaluating()); 2023 // 4. Assert: module.[[EvaluationError]] is EMPTY. 2024 ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX); 2025 // 5. Set module.[[EvaluationError]] to ThrowCompletion(error). 2026 module->SetEvaluationError(MODULE_ERROR); 2027 // 6. Set module.[[Status]] to EVALUATED. 2028 module->SetStatus(ModuleStatus::EVALUATED); 2029 // 7. For each Cyclic Module Record m of module.[[AsyncParentModules]], do 2030 // a. Perform AsyncModuleExecutionRejected(m, error). 2031 auto globalConstants = thread->GlobalConstants(); 2032 JSTaggedValue asyncParentModulesValue = module->GetAsyncParentModules(); 2033 if (!asyncParentModulesValue.IsUndefined()) { 2034 JSMutableHandle<SourceTextModule> parentModule(thread, globalConstants->GetUndefined()); 2035 JSHandle<TaggedArray> asyncParentModules(thread, asyncParentModulesValue); 2036 size_t asyncParentModulesLen = asyncParentModules->GetLength(); 2037 for (size_t idx = 0; idx < asyncParentModulesLen; idx++) { 2038 parentModule.Update(asyncParentModules->Get(idx)); 2039 AsyncModuleExecutionRejected(thread, parentModule, error); 2040 } 2041 } 2042 2043 // 8. If module.[[TopLevelCapability]] is not EMPTY, then 2044 // a. Assert: module.[[CycleRoot]] is module. 2045 // b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], undefined, « error »). 2046 JSTaggedValue topLevelCapabilityValue = module->GetTopLevelCapability(); 2047 if (!topLevelCapabilityValue.IsUndefined()) { 2048 JSHandle<JSTaggedValue> exceptionHandle(thread, error); 2049 // if caught exceptionHandle type is JSError 2050 if (exceptionHandle->IsJSError()) { 2051 thread->GetCurrentEcmaContext()->HandleUncaughtException(error); 2052 } 2053 ASSERT(JSTaggedValue::SameValue(module->GetCycleRoot(), module.GetTaggedValue())); 2054 JSHandle<PromiseCapability> topLevelCapability(thread, topLevelCapabilityValue); 2055 JSHandle<JSTaggedValue> reject(thread, topLevelCapability->GetReject()); 2056 JSHandle<JSTaggedValue> undefined = globalConstants->GetHandledUndefined(); 2057 EcmaRuntimeCallInfo *info = 2058 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); 2059 RETURN_IF_ABRUPT_COMPLETION(thread); 2060 info->SetCallArg(error); 2061 [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info); 2062 RETURN_IF_ABRUPT_COMPLETION(thread); 2063 } 2064} 2065 2066JSTaggedValue SourceTextModule::AsyncModuleFulfilledFunc(EcmaRuntimeCallInfo *argv) 2067{ 2068 ASSERT(argv); 2069 JSThread *thread = argv->GetThread(); 2070 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2071 JSHandle<JSAsyncModuleFulfilledFunction> fulfilledFunc = 2072 JSHandle<JSAsyncModuleFulfilledFunction>::Cast(base::BuiltinsBase::GetConstructor(argv)); 2073 JSHandle<SourceTextModule> module(thread, fulfilledFunc->GetModule()); 2074 AsyncModuleExecutionFulfilled(thread, module); 2075 return JSTaggedValue::Undefined(); 2076} 2077 2078JSTaggedValue SourceTextModule::AsyncModuleRejectedFunc(EcmaRuntimeCallInfo *argv) 2079{ 2080 // 1. Let F be the active function object. 2081 ASSERT(argv); 2082 JSThread *thread = argv->GetThread(); 2083 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2084 JSHandle<JSAsyncModuleRejectedFunction> rejectedFunc = 2085 JSHandle<JSAsyncModuleRejectedFunction>::Cast(base::BuiltinsBase::GetConstructor(argv)); 2086 JSHandle<SourceTextModule> module(thread, rejectedFunc->GetModule()); 2087 [[maybe_unused]] JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0); 2088 AsyncModuleExecutionRejected(thread, module, value.GetTaggedValue()); 2089 return JSTaggedValue::Undefined(); 2090} 2091 2092void SourceTextModule::CheckCircularImportTool(JSThread *thread, const CString &circularModuleRecordName, 2093 CList<CString> &referenceList, bool printOtherCircular) 2094{ 2095 referenceList.push_back(circularModuleRecordName); 2096 JSMutableHandle<SourceTextModule> moduleRecord(thread, thread->GlobalConstants()->GetUndefined()); 2097 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); 2098 if (moduleManager->IsLocalModuleLoaded(circularModuleRecordName)) { 2099 moduleRecord.Update(moduleManager->HostGetImportedModule(circularModuleRecordName)); 2100 } else { 2101 moduleRecord.Update(moduleManager->HostResolveImportedModule(circularModuleRecordName)); 2102 RETURN_IF_ABRUPT_COMPLETION(thread); 2103 } 2104 CString requiredModuleName; 2105 SourceTextModule::SearchCircularImport( 2106 thread, circularModuleRecordName, moduleRecord, referenceList, requiredModuleName, printOtherCircular); 2107} 2108 2109void SourceTextModule::SearchCircularImport(JSThread *thread, const CString &circularModuleRecordName, 2110 const JSHandle<SourceTextModule> &module, 2111 CList<CString> &referenceList, 2112 CString &requiredModuleName, bool printOtherCircular) 2113{ 2114 if (module->GetRequestedModules().IsUndefined()) { 2115 return; 2116 } 2117 auto globalConstants = thread->GlobalConstants(); 2118 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules()); 2119 size_t requestedModulesLen = requestedModules->GetLength(); 2120 JSMutableHandle<JSTaggedValue> required(thread, globalConstants->GetUndefined()); 2121 JSMutableHandle<SourceTextModule> requiredModule(thread, globalConstants->GetUndefined()); 2122 for (size_t idx = 0; idx < requestedModulesLen; idx++) { 2123 required.Update(requestedModules->Get(idx)); 2124 requiredModule.Update(JSHandle<SourceTextModule>::Cast( 2125 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required))); 2126 RETURN_IF_ABRUPT_COMPLETION(thread); 2127 requiredModuleName = requiredModule->GetEcmaModuleRecordNameString(); 2128 referenceList.push_back(requiredModuleName); 2129 if (requiredModuleName == circularModuleRecordName) { 2130 PrintCircular(referenceList, ERROR); 2131 } else if (printOtherCircular && IsCircular(referenceList, requiredModuleName)) { 2132 PrintCircular(referenceList, WARN); 2133 } else { 2134 SourceTextModule::SearchCircularImport(thread, circularModuleRecordName, 2135 requiredModule, referenceList, requiredModuleName, printOtherCircular); 2136 } 2137 referenceList.pop_back(); 2138 } 2139} 2140 2141bool SourceTextModule::IsCircular(const CList<CString> &referenceList, 2142 const CString &requiredModuleName) 2143{ 2144 for (auto iter = referenceList.begin(), end = --referenceList.end(); iter != end; ++iter) { 2145 if (requiredModuleName == *iter) { 2146 return true; 2147 } 2148 } 2149 return false; 2150} 2151 2152void SourceTextModule::PrintCircular(const CList<CString> &referenceList, Level level) 2153{ 2154 LOG_ECMA(INFO) << "checkCircularImport begin ----------------------------------------"; 2155 if (level == Level::ERROR) { 2156 for (auto iter : referenceList) { 2157 LOG_ECMA(ERROR) << "checkCircularImport record: " << iter; 2158 } 2159 } else { 2160 for (auto iter : referenceList) { 2161 LOG_ECMA(WARN) << "checkCircularImport record: " << iter; 2162 } 2163 } 2164 LOG_ECMA(INFO) << "checkCircularImport end ------------------------------------------"; 2165} 2166 2167CString SourceTextModule::ReplaceModuleThroughFeature(JSThread *thread, const CString &requestName) 2168{ 2169 auto vm = thread->GetEcmaVM(); 2170 // check if module need to be mock 2171 if (vm->IsMockModule(requestName)) { 2172 return vm->GetMockModule(requestName); 2173 } 2174 2175 // Load the replaced module, hms -> system hsp 2176 if (vm->IsHmsModule(requestName)) { 2177 return vm->GetHmsModule(requestName); 2178 } 2179 return requestName; 2180} 2181} // namespace panda::ecmascript 2182