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