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