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