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