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