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