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