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