1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/module/js_module_source_text.h"
17
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/base/path_helper.h"
20 #include "ecmascript/base/string_helper.h"
21 #include "ecmascript/jspandafile/js_pandafile_executor.h"
22 #include "ecmascript/jspandafile/js_pandafile_manager.h"
23 #include "ecmascript/linked_hash_table.h"
24 #include "ecmascript/module/js_module_deregister.h"
25 #include "ecmascript/module/js_module_manager.h"
26 #include "ecmascript/module/js_module_namespace.h"
27 #include "ecmascript/module/module_data_extractor.h"
28 #include "ecmascript/module/module_path_helper.h"
29 #include "ecmascript/platform/file.h"
30 #include "ecmascript/tagged_dictionary.h"
31
32 namespace panda::ecmascript {
33 using PathHelper = base::PathHelper;
34 using StringHelper = base::StringHelper;
35
GetExportedNames(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<TaggedArray> & exportStarSet)36 CVector<std::string> SourceTextModule::GetExportedNames(JSThread *thread, const JSHandle<SourceTextModule> &module,
37 const JSHandle<TaggedArray> &exportStarSet)
38 {
39 CVector<std::string> exportedNames;
40 // 1. Let module be this Source Text Module Record.
41 // 2. If exportStarSet contains module, then
42 if (exportStarSet->GetIdx(module.GetTaggedValue()) != TaggedArray::MAX_ARRAY_INDEX) {
43 // a. Assert: We've reached the starting point of an import * circularity.
44 // b. Return a new empty List.
45 return exportedNames;
46 }
47 // 3. Append module to exportStarSet.
48 size_t len = exportStarSet->GetLength();
49 JSHandle<TaggedArray> newExportStarSet = TaggedArray::SetCapacity(thread, exportStarSet, len + 1);
50 newExportStarSet->Set(thread, len, module.GetTaggedValue());
51
52 JSTaggedValue entryValue = module->GetLocalExportEntries();
53 // 5. For each ExportEntry Record e in module.[[LocalExportEntries]], do
54 AddExportName<LocalExportEntry>(thread, entryValue, exportedNames);
55
56 // 6. For each ExportEntry Record e in module.[[IndirectExportEntries]], do
57 entryValue = module->GetIndirectExportEntries();
58 AddExportName<IndirectExportEntry>(thread, entryValue, exportedNames);
59
60 entryValue = module->GetStarExportEntries();
61 auto globalConstants = thread->GlobalConstants();
62 if (!entryValue.IsUndefined()) {
63 JSMutableHandle<StarExportEntry> ee(thread, globalConstants->GetUndefined());
64 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
65
66 // 7. For each ExportEntry Record e in module.[[StarExportEntries]], do
67 JSHandle<TaggedArray> starExportEntries(thread, entryValue);
68 size_t starExportEntriesLen = starExportEntries->GetLength();
69 for (size_t idx = 0; idx < starExportEntriesLen; idx++) {
70 ee.Update(starExportEntries->Get(idx));
71 // a. Let requestedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
72 moduleRequest.Update(ee->GetModuleRequest());
73 SetExportName(thread, moduleRequest, module, exportedNames, newExportStarSet);
74 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exportedNames);
75 }
76 }
77 return exportedNames;
78 }
79
80 // new way with module
HostResolveImportedModuleWithMerge(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & moduleRequest)81 JSHandle<JSTaggedValue> SourceTextModule::HostResolveImportedModuleWithMerge(
82 JSThread *thread, const JSHandle<SourceTextModule> &module, const JSHandle<JSTaggedValue> &moduleRequest)
83 {
84 DISALLOW_GARBAGE_COLLECTION;
85 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
86 if (moduleManager->IsImportedModuleLoaded(moduleRequest.GetTaggedValue())) {
87 return JSHandle<JSTaggedValue>(moduleManager->HostGetImportedModule(moduleRequest.GetTaggedValue()));
88 }
89
90 CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject()));
91 auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(moduleRequestName);
92 if (isNative) {
93 return moduleManager->ResolveNativeModule(moduleRequestName, moduleType);
94 }
95
96 ASSERT(module->GetEcmaModuleFilename().IsHeapObject());
97 CString baseFilename = ConvertToString(module->GetEcmaModuleFilename());
98 ASSERT(module->GetEcmaModuleRecordName().IsHeapObject());
99 CString moduleRecordName = ConvertToString(module->GetEcmaModuleRecordName());
100 std::shared_ptr<JSPandaFile> jsPandaFile =
101 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFilename, moduleRecordName);
102 if (jsPandaFile == nullptr) {
103 CString msg = "Load file with filename '" + baseFilename + "' failed, recordName '" + moduleRecordName + "'";
104 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
105 }
106
107 CString outFileName = baseFilename;
108 CString entryPoint = ModulePathHelper::ConcatFileNameWithMerge(
109 thread, jsPandaFile.get(), outFileName, moduleRecordName, moduleRequestName);
110 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
111
112 #if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
113 if (entryPoint == ModulePathHelper::PREVIEW_OF_ACROSS_HAP_FLAG &&
114 thread->GetEcmaVM()->EnableReportModuleResolvingFailure()) {
115 THROW_SYNTAX_ERROR_AND_RETURN(thread, "", thread->GlobalConstants()->GetHandledUndefined());
116 }
117 #endif
118 return moduleManager->HostResolveImportedModuleWithMerge(outFileName, entryPoint);
119 }
120
121 // old way with bundle
HostResolveImportedModule(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & moduleRequest)122 JSHandle<JSTaggedValue> SourceTextModule::HostResolveImportedModule(JSThread *thread,
123 const JSHandle<SourceTextModule> &module,
124 const JSHandle<JSTaggedValue> &moduleRequest)
125 {
126 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
127 if (moduleManager->IsImportedModuleLoaded(moduleRequest.GetTaggedValue())) {
128 return JSHandle<JSTaggedValue>(moduleManager->HostGetImportedModule(moduleRequest.GetTaggedValue()));
129 }
130
131 JSHandle<EcmaString> dirname = base::PathHelper::ResolveDirPath(thread,
132 ConvertToString(module->GetEcmaModuleFilename()));
133 JSHandle<EcmaString> moduleFilename = ResolveFilenameFromNative(thread, dirname.GetTaggedValue(),
134 moduleRequest.GetTaggedValue());
135 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
136 return thread->GetCurrentEcmaContext()->GetModuleManager()->
137 HostResolveImportedModule(ConvertToString(moduleFilename.GetTaggedValue()));
138 }
139
CheckCircularImport(const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & exportName,CVector<std::pair<JSHandle<SourceTextModule>,JSHandle<JSTaggedValue>>> & resolveVector)140 bool SourceTextModule::CheckCircularImport(const JSHandle<SourceTextModule> &module,
141 const JSHandle<JSTaggedValue> &exportName,
142 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveVector)
143 {
144 for (auto rr : resolveVector) {
145 // a. If module and r.[[Module]] are the same Module Record and
146 // SameValue(exportName, r.[[ExportName]]) is true, then
147 if (JSTaggedValue::SameValue(rr.first.GetTaggedValue(), module.GetTaggedValue()) &&
148 JSTaggedValue::SameValue(rr.second, exportName)) {
149 // i. Assert: This is a circular import request.
150 // ii. Return true.
151 return true;
152 }
153 }
154 return false;
155 }
156
ResolveExportObject(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & exports,const JSHandle<JSTaggedValue> & exportName)157 JSHandle<JSTaggedValue> SourceTextModule::ResolveExportObject(JSThread *thread,
158 const JSHandle<SourceTextModule> &module,
159 const JSHandle<JSTaggedValue> &exports,
160 const JSHandle<JSTaggedValue> &exportName)
161 {
162 // Let module be this Source Text Module Record.
163 auto globalConstants = thread->GlobalConstants();
164 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
165 // For CJS, if exports is not JSObject, means the CJS module use default output
166 JSHandle<JSTaggedValue> defaultString = globalConstants->GetHandledDefaultString();
167 if (JSTaggedValue::SameValue(exportName, defaultString)) {
168 // bind with a number
169 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, -1));
170 }
171 if (exports->IsJSObject()) {
172 JSHandle<JSTaggedValue> resolution(thread, JSTaggedValue::Hole());
173 JSObject *exportObject = JSObject::Cast(exports.GetTaggedValue().GetTaggedObject());
174 TaggedArray *properties = TaggedArray::Cast(exportObject->GetProperties().GetTaggedObject());
175 if (!properties->IsDictionaryMode()) {
176 JSHandle<JSHClass> jsHclass(thread, exportObject->GetJSHClass());
177 // Get layoutInfo and compare the input and output names of files
178 LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
179 if (layoutInfo->NumberOfElements() != 0) {
180 resolution = ResolveElementOfObject(thread, jsHclass, exportName, module);
181 }
182 } else {
183 NameDictionary *dict = NameDictionary::Cast(properties);
184 int entry = dict->FindEntry(exportName.GetTaggedValue());
185 if (entry != -1) {
186 resolution = JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, entry));
187 }
188 }
189 if (!resolution->IsUndefined()) {
190 return resolution;
191 }
192 }
193 return globalConstants->GetHandledNull();
194 }
195
ResolveExport(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & exportName,CVector<std::pair<JSHandle<SourceTextModule>,JSHandle<JSTaggedValue>>> & resolveVector)196 JSHandle<JSTaggedValue> SourceTextModule::ResolveExport(JSThread *thread, const JSHandle<SourceTextModule> &module,
197 const JSHandle<JSTaggedValue> &exportName,
198 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveVector)
199 {
200 // 1. Let module be this Source Text Module Record.
201 auto globalConstants = thread->GlobalConstants();
202 // Check if circular import request.
203 // 2.For each Record { [[Module]], [[ExportName]] } r in resolveVector, do
204 if (CheckCircularImport(module, exportName, resolveVector)) {
205 return globalConstants->GetHandledNull();
206 }
207 // 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveVector.
208 resolveVector.emplace_back(std::make_pair(module, exportName));
209 // 4. For each ExportEntry Record e in module.[[LocalExportEntries]], do
210 JSHandle<JSTaggedValue> localExportEntriesTv(thread, module->GetLocalExportEntries());
211 if (!localExportEntriesTv->IsUndefined()) {
212 JSHandle<JSTaggedValue> resolution = ResolveLocalExport(thread, localExportEntriesTv, exportName, module);
213 if (!resolution->IsUndefined()) {
214 return resolution;
215 }
216 }
217 // 5. For each ExportEntry Record e in module.[[IndirectExportEntries]], do
218 JSHandle<JSTaggedValue> indirectExportEntriesTv(thread, module->GetIndirectExportEntries());
219 if (!indirectExportEntriesTv->IsUndefined()) {
220 JSHandle<JSTaggedValue> resolution = ResolveIndirectExport(thread, indirectExportEntriesTv,
221 exportName, module, resolveVector);
222 if (!resolution->IsUndefined()) {
223 return resolution;
224 }
225 }
226 // 6. If SameValue(exportName, "default") is true, then
227 JSHandle<JSTaggedValue> defaultString = globalConstants->GetHandledDefaultString();
228 // In Aot static parse phase, some importModule maybe empty aot module, all elements will be undefined, it will
229 // return hole for resolve index binding at the end to skip error.
230 if (JSTaggedValue::SameValue(exportName, defaultString) &&
231 thread->GetEcmaVM()->EnableReportModuleResolvingFailure()) {
232 // a. Assert: A default export was not explicitly defined by this module.
233 // b. Return null.
234 // c. NOTE: A default export cannot be provided by an export *.
235 return globalConstants->GetHandledNull();
236 }
237 // 7. Let starResolution be null.
238 JSMutableHandle<JSTaggedValue> starResolution(thread, globalConstants->GetNull());
239 // 8. For each ExportEntry Record e in module.[[StarExportEntries]], do
240 JSTaggedValue starExportEntriesTv = module->GetStarExportEntries();
241 if (starExportEntriesTv.IsUndefined()) {
242 // return Hole in Aot static parse phase to skip error.
243 if (!thread->GetEcmaVM()->EnableReportModuleResolvingFailure()) {
244 starResolution.Update(JSTaggedValue::Hole());
245 }
246 return starResolution;
247 }
248 JSMutableHandle<StarExportEntry> ee(thread, globalConstants->GetUndefined());
249 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
250 JSHandle<TaggedArray> starExportEntries(thread, starExportEntriesTv);
251 size_t starExportEntriesLen = starExportEntries->GetLength();
252 for (size_t idx = 0; idx < starExportEntriesLen; idx++) {
253 ee.Update(starExportEntries->Get(idx));
254 moduleRequest.Update(ee->GetModuleRequest());
255 JSHandle<JSTaggedValue> result = GetStarResolution(thread, exportName, moduleRequest,
256 module, starResolution, resolveVector);
257 if (result->IsString() || result->IsException()) {
258 return result;
259 }
260 }
261 // 9. Return starResolution.
262 return starResolution;
263 }
264
InstantiateCJS(JSThread * thread,const JSHandle<SourceTextModule> & currentModule,const JSHandle<SourceTextModule> & requiredModule)265 void SourceTextModule::InstantiateCJS(JSThread *thread, const JSHandle<SourceTextModule> ¤tModule,
266 const JSHandle<SourceTextModule> &requiredModule)
267 {
268 JSTaggedValue cjsFileName(requiredModule->GetEcmaModuleFilename());
269 JSTaggedValue cjsRecordName(requiredModule->GetEcmaModuleRecordName());
270 JSMutableHandle<JSTaggedValue> cjsModuleName(thread, JSTaggedValue::Undefined());
271 // Get exported cjs module
272 bool isBundle;
273 if (cjsRecordName.IsUndefined()) {
274 cjsModuleName.Update(cjsFileName);
275 isBundle = true;
276 } else {
277 cjsModuleName.Update(cjsRecordName);
278 isBundle = false;
279 }
280 JSHandle<JSTaggedValue> cjsExports = CjsModule::SearchFromModuleCache(thread, cjsModuleName);
281 InitializeEnvironment(thread, currentModule, cjsModuleName, cjsExports, isBundle);
282 }
283
CheckNativeModule(const CString & moduleRequestName)284 std::pair<bool, ModuleTypes> SourceTextModule::CheckNativeModule(const CString &moduleRequestName)
285 {
286 if (moduleRequestName[0] != '@' ||
287 StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::PREFIX_BUNDLE) ||
288 StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::PREFIX_PACKAGE)||
289 moduleRequestName.find(':') == CString::npos) {
290 return {false, ModuleTypes::UNKNOWN};
291 }
292
293 if (StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::REQUIRE_NAPI_OHOS_PREFIX)) {
294 return {true, ModuleTypes::OHOS_MODULE};
295 }
296 if (StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::REQUIRE_NAPI_APP_PREFIX)) {
297 return {true, ModuleTypes::APP_MODULE};
298 }
299 if (StringHelper::StringStartWith(moduleRequestName, ModulePathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) {
300 return {true, ModuleTypes::NATIVE_MODULE};
301 }
302 return {true, ModuleTypes::INTERNAL_MODULE};
303 }
304
GetRequireNativeModuleFunc(EcmaVM * vm,ModuleTypes moduleType)305 Local<JSValueRef> SourceTextModule::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType)
306 {
307 Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm);
308 auto globalConstants = vm->GetJSThread()->GlobalConstants();
309 auto funcName = (moduleType == ModuleTypes::NATIVE_MODULE) ?
310 globalConstants->GetHandledRequireNativeModuleString() :
311 globalConstants->GetHandledRequireNapiString();
312 return globalObject->Get(vm, JSNApiHelper::ToLocal<StringRef>(funcName));
313 }
314
MakeAppArgs(const EcmaVM * vm,std::vector<Local<JSValueRef>> & arguments,const CString & moduleName)315 void SourceTextModule::MakeAppArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments,
316 const CString &moduleName)
317 {
318 size_t pos = moduleName.find_last_of('/');
319 if (pos == CString::npos) {
320 LOG_FULL(FATAL) << "Invalid native module " << moduleName;
321 UNREACHABLE();
322 }
323 CString soName = moduleName.substr(pos + 1);
324 CString path = moduleName.substr(0, pos);
325 // use module name as so name
326 arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str());
327 arguments.emplace_back(BooleanRef::New(vm, true));
328 arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str()));
329 }
330
MakeInternalArgs(const EcmaVM * vm,std::vector<Local<JSValueRef>> & arguments,const CString & moduleRequestName)331 void SourceTextModule::MakeInternalArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments,
332 const CString &moduleRequestName)
333 {
334 arguments.emplace_back(BooleanRef::New(vm, false));
335 arguments.emplace_back(StringRef::NewFromUtf8(vm, ""));
336 CString moduleDir = PathHelper::GetInternalModulePrefix(moduleRequestName);
337 arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleDir.c_str()));
338 }
339
LoadNativeModule(JSThread * thread,JSHandle<SourceTextModule> & requiredModule,const JSHandle<JSTaggedValue> & moduleRequest,ModuleTypes moduleType)340 bool SourceTextModule::LoadNativeModule(JSThread *thread, JSHandle<SourceTextModule> &requiredModule,
341 const JSHandle<JSTaggedValue> &moduleRequest, ModuleTypes moduleType)
342 {
343 EcmaVM *vm = thread->GetEcmaVM();
344 [[maybe_unused]] LocalScope scope(vm);
345
346 CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject()));
347 CString moduleName = PathHelper::GetStrippedModuleName(moduleRequestName);
348 std::vector<Local<JSValueRef>> arguments;
349 LOG_FULL(DEBUG) << "Request module is " << moduleRequestName;
350
351 arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleName.c_str()));
352 if (moduleType == ModuleTypes::APP_MODULE) {
353 MakeAppArgs(vm, arguments, moduleName);
354 } else if (moduleType == ModuleTypes::INTERNAL_MODULE) {
355 MakeInternalArgs(vm, arguments, moduleRequestName);
356 }
357 auto maybeFuncRef = GetRequireNativeModuleFunc(vm, moduleType);
358 // some function(s) may not registered in global object for non-main thread
359 if (!maybeFuncRef->IsFunction()) {
360 LOG_FULL(WARN) << "Not found require func";
361 return false;
362 }
363
364 Local<FunctionRef> funcRef = maybeFuncRef;
365 auto exportObject = funcRef->Call(vm, JSValueRef::Undefined(vm), arguments.data(), arguments.size());
366 if (UNLIKELY(thread->HasPendingException())) {
367 thread->ClearException();
368 LOG_FULL(ERROR) << "LoadNativeModule has exception";
369 return false;
370 }
371 requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject));
372 return true;
373 }
374
InstantiateNativeModule(JSThread * thread,JSHandle<SourceTextModule> & currentModule,JSHandle<SourceTextModule> & requiredModule,const JSHandle<JSTaggedValue> & moduleRequest,ModuleTypes moduleType)375 void SourceTextModule::InstantiateNativeModule(JSThread *thread, JSHandle<SourceTextModule> ¤tModule,
376 JSHandle<SourceTextModule> &requiredModule, const JSHandle<JSTaggedValue> &moduleRequest,
377 ModuleTypes moduleType)
378 {
379 if (requiredModule->GetStatus() != ModuleStatus::EVALUATED) {
380 if (!SourceTextModule::LoadNativeModule(thread, requiredModule, moduleRequest, moduleType)) {
381 LOG_FULL(WARN) << "LoadNativeModule " << ConvertToString(
382 EcmaString::Cast(moduleRequest->GetTaggedObject())) << " failed";
383 return;
384 }
385 }
386
387 JSHandle<JSTaggedValue> nativeModuleName(thread, requiredModule->GetEcmaModuleRecordName());
388 JSHandle<JSTaggedValue> nativeExports(thread, requiredModule->GetModuleValue(thread, 0, false));
389 InitializeEnvironment(thread, currentModule, nativeModuleName, nativeExports, false);
390 }
391
InitializeEnvironment(JSThread * thread,const JSHandle<SourceTextModule> & currentModule,JSHandle<JSTaggedValue> & moduleName,JSHandle<JSTaggedValue> & exports,bool isBundle)392 void SourceTextModule::InitializeEnvironment(JSThread *thread, const JSHandle<SourceTextModule> ¤tModule,
393 JSHandle<JSTaggedValue> &moduleName, JSHandle<JSTaggedValue> &exports, bool isBundle)
394 {
395 // Get esm environment
396 JSHandle<JSTaggedValue> moduleEnvironment(thread, currentModule->GetEnvironment());
397 auto globalConstants = thread->GlobalConstants();
398 if (moduleEnvironment->IsUndefined()) {
399 return;
400 }
401 JSHandle<TaggedArray> environment = JSHandle<TaggedArray>::Cast(moduleEnvironment);
402 size_t length = environment->GetLength();
403 JSHandle<TaggedArray> importEntries(thread, currentModule->GetImportEntries());
404 JSMutableHandle<ImportEntry> host(thread, globalConstants->GetUndefined());
405 JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined());
406 // update required module
407 for (size_t idx = 0; idx < length; idx++) {
408 JSTaggedValue resolvedBinding = environment->Get(idx);
409 // if resolvedBinding.IsHole(), means that importname is * .
410 if (resolvedBinding.IsHole()) {
411 continue;
412 }
413 JSHandle<SourceTextModule> requestedModule = GetModuleFromBinding(thread, resolvedBinding);
414 JSMutableHandle<JSTaggedValue> requestedName(thread, JSTaggedValue::Undefined());
415 if (isBundle) {
416 requestedName.Update(requestedModule->GetEcmaModuleFilename());
417 } else {
418 requestedName.Update(requestedModule->GetEcmaModuleRecordName());
419 }
420 // if not the same module, then don't have to update
421 if (!JSTaggedValue::SameValue(requestedName, moduleName)) {
422 continue;
423 }
424 // rebinding here
425 host.Update(importEntries->Get(idx));
426 importName.Update(host->GetImportName());
427 JSHandle<JSTaggedValue> resolution =
428 SourceTextModule::ResolveExportObject(thread, requestedModule, exports, importName);
429 // ii. If resolution is null or "ambiguous", throw a SyntaxError exception.
430 if (resolution->IsNull() || resolution->IsString()) {
431 CString msg = "the requested module '" +
432 ConvertToString(host->GetModuleRequest()) +
433 "' does not provide an export named '" +
434 ConvertToString(importName.GetTaggedValue()) +
435 "' which imported by '" +
436 ConvertToString(currentModule->GetEcmaModuleRecordName()) + "'";
437 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str());
438 }
439 // iii. Call envRec.CreateImportBinding(
440 // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
441 environment->Set(thread, idx, resolution);
442 }
443 }
444
GetModuleFromBinding(JSThread * thread,const JSTaggedValue & resolvedBinding)445 JSHandle<SourceTextModule> SourceTextModule::GetModuleFromBinding(JSThread *thread,
446 const JSTaggedValue &resolvedBinding)
447 {
448 if (resolvedBinding.IsResolvedIndexBinding()) {
449 ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
450 return JSHandle<SourceTextModule>(thread, binding->GetModule());
451 }
452 ResolvedBinding *binding = ResolvedBinding::Cast(resolvedBinding.GetTaggedObject());
453 return JSHandle<SourceTextModule>(thread, binding->GetModule());
454 }
455
Instantiate(JSThread * thread,const JSHandle<JSTaggedValue> & moduleHdl,bool excuteFromJob)456 int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
457 bool excuteFromJob)
458 {
459 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
460 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleHdl);
461 // 1. Let module be this Source Text Module Record.
462 // 2. Assert: module.[[Status]] is not "instantiating" or "evaluating".
463 ASSERT(module->GetStatus() != ModuleStatus::INSTANTIATING && module->GetStatus() != ModuleStatus::EVALUATING);
464 // 3. Let stack be a new empty List.
465 CVector<JSHandle<SourceTextModule>> stack;
466 // 4. Let result be InnerModuleInstantiation(module, stack, 0).
467 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
468 int result = SourceTextModule::InnerModuleInstantiation(thread, moduleRecord, stack, 0, excuteFromJob);
469 // 5. If result is an abrupt completion, then
470 if (thread->HasPendingException()) {
471 // a. For each module m in stack, do
472 for (auto mm : stack) {
473 // i. Assert: m.[[Status]] is "instantiating".
474 ASSERT(mm->GetStatus() == ModuleStatus::INSTANTIATING);
475 // ii. Set m.[[Status]] to "uninstantiated".
476 mm->SetStatus(ModuleStatus::UNINSTANTIATED);
477 // iii. Set m.[[Environment]] to undefined.
478 // iv. Set m.[[DFSIndex]] to undefined.
479 mm->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX);
480 // v. Set m.[[DFSAncestorIndex]] to undefined.
481 mm->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX);
482 }
483 // b. Assert: module.[[Status]] is "uninstantiated".
484 ASSERT(module->GetStatus() == ModuleStatus::UNINSTANTIATED);
485 // c. return result
486 return result;
487 }
488 // 6. Assert: module.[[Status]] is "instantiated" or "evaluated".
489 ASSERT(module->GetStatus() == ModuleStatus::INSTANTIATED || module->GetStatus() == ModuleStatus::EVALUATED);
490 // 7. Assert: stack is empty.
491 ASSERT(stack.empty());
492 // 8. Return undefined.
493 return SourceTextModule::UNDEFINED_INDEX;
494 }
495
InnerModuleInstantiation(JSThread * thread,const JSHandle<ModuleRecord> & moduleRecord,CVector<JSHandle<SourceTextModule>> & stack,int index,bool excuteFromJob)496 int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
497 CVector<JSHandle<SourceTextModule>> &stack, int index, bool excuteFromJob)
498 {
499 // 1. If module is not a Source Text Module Record, then
500 if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) {
501 // a. Perform ? module.Instantiate().
502 ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
503 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
504 // b. Return index.
505 return index;
506 }
507 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
508 // 2. If module.[[Status]] is "instantiating", "instantiated", or "evaluated", then Return index.
509 ModuleStatus status = module->GetStatus();
510 if (status == ModuleStatus::INSTANTIATING ||
511 status == ModuleStatus::INSTANTIATED ||
512 status == ModuleStatus::EVALUATED) {
513 return index;
514 }
515 // 3. Assert: module.[[Status]] is "uninstantiated".
516 ASSERT(status == ModuleStatus::UNINSTANTIATED);
517 // 4. Set module.[[Status]] to "instantiating".
518 module->SetStatus(ModuleStatus::INSTANTIATING);
519 // 5. Set module.[[DFSIndex]] to index.
520 module->SetDFSIndex(index);
521 // 6. Set module.[[DFSAncestorIndex]] to index.
522 module->SetDFSAncestorIndex(index);
523 // 7. Set index to index + 1.
524 index++;
525 // 8. Append module to stack.
526 stack.emplace_back(module);
527 // 9. For each String required that is an element of module.[[RequestedModules]], do
528 if (!module->GetRequestedModules().IsUndefined()) {
529 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
530 size_t requestedModulesLen = requestedModules->GetLength();
531 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
532 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
533 required.Update(requestedModules->Get(idx));
534 // a. Let requiredModule be ? HostResolveImportedModule(module, required).
535 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
536 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
537 if (moduleRecordName.IsUndefined()) {
538 JSHandle<JSTaggedValue> requiredVal =
539 SourceTextModule::HostResolveImportedModule(thread, module, required);
540 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
541 ModuleDeregister::InitForDeregisterModule(requiredVal, excuteFromJob);
542 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
543 } else {
544 ASSERT(moduleRecordName.IsString());
545 JSHandle<JSTaggedValue> requiredVal =
546 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
547 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
548 ModuleDeregister::InitForDeregisterModule(requiredVal, excuteFromJob);
549 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
550 }
551
552 // b. Set index to ? InnerModuleInstantiation(requiredModule, stack, index).
553 JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
554 index = SourceTextModule::InnerModuleInstantiation(thread,
555 requiredModuleRecord, stack, index, excuteFromJob);
556 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
557 // c. Assert: requiredModule.[[Status]] is either "instantiating", "instantiated", or "evaluated".
558 ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
559 ASSERT((requiredModuleStatus == ModuleStatus::INSTANTIATING ||
560 requiredModuleStatus == ModuleStatus::INSTANTIATED || requiredModuleStatus == ModuleStatus::EVALUATED));
561 // d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
562 // e. If requiredModule.[[Status]] is "instantiating", then
563 if (requiredModuleStatus == ModuleStatus::INSTANTIATING) {
564 // d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
565 ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end());
566 // i. Assert: requiredModule is a Source Text Module Record.
567 // ii. Set module.[[DFSAncestorIndex]] to min(
568 // module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
569 int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex());
570 module->SetDFSAncestorIndex(dfsAncIdx);
571 }
572 }
573 }
574 // Adapter new opcode
575 // 10. Perform ? ModuleDeclarationEnvironmentSetup(module).
576 if (module->GetIsNewBcVersion()) {
577 SourceTextModule::ModuleDeclarationArrayEnvironmentSetup(thread, module);
578 } else {
579 SourceTextModule::ModuleDeclarationEnvironmentSetup(thread, module);
580 }
581 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
582 // 11. Assert: module occurs exactly once in stack.
583 // 12. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]].
584 int dfsAncIdx = module->GetDFSAncestorIndex();
585 int dfsIdx = module->GetDFSIndex();
586 ASSERT(dfsAncIdx <= dfsIdx);
587 // 13. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then
588 if (dfsAncIdx == dfsIdx) {
589 // a. Let done be false.
590 bool done = false;
591 // b. Repeat, while done is false,
592 while (!done) {
593 // i. Let requiredModule be the last element in stack.
594 JSHandle<SourceTextModule> requiredModule = stack.back();
595 // ii. Remove the last element of stack.
596 stack.pop_back();
597 // iii. Set requiredModule.[[Status]] to "instantiated".
598 requiredModule->SetStatus(ModuleStatus::INSTANTIATED);
599 // iv. If requiredModule and module are the same Module Record, set done to true.
600 if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) {
601 done = true;
602 }
603 }
604 }
605 return index;
606 }
607
ModuleDeclarationEnvironmentSetup(JSThread * thread,const JSHandle<SourceTextModule> & module)608 void SourceTextModule::ModuleDeclarationEnvironmentSetup(JSThread *thread,
609 const JSHandle<SourceTextModule> &module)
610 {
611 CheckResolvedBinding(thread, module);
612 if (module->GetImportEntries().IsUndefined()) {
613 return;
614 }
615
616 // 2. Assert: All named exports from module are resolvable.
617 // 3. Let realm be module.[[Realm]].
618 // 4. Assert: realm is not undefined.
619 // 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
620 JSHandle<TaggedArray> importEntries(thread, module->GetImportEntries());
621 size_t importEntriesLen = importEntries->GetLength();
622 JSHandle<NameDictionary> map(NameDictionary::Create(thread,
623 NameDictionary::ComputeHashTableSize(importEntriesLen)));
624 // 6. Set module.[[Environment]] to env.
625 module->SetEnvironment(thread, map);
626 // 7. Let envRec be env's EnvironmentRecord.
627 JSMutableHandle<JSTaggedValue> envRec(thread, module->GetEnvironment());
628 ASSERT(!envRec->IsUndefined());
629 // 8. For each ImportEntry Record in in module.[[ImportEntries]], do
630 auto globalConstants = thread->GlobalConstants();
631 JSMutableHandle<ImportEntry> in(thread, globalConstants->GetUndefined());
632 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
633 JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined());
634 JSMutableHandle<JSTaggedValue> localName(thread, globalConstants->GetUndefined());
635 for (size_t idx = 0; idx < importEntriesLen; idx++) {
636 in.Update(importEntries->Get(idx));
637 localName.Update(in->GetLocalName());
638 importName.Update(in->GetImportName());
639 moduleRequest.Update(in->GetModuleRequest());
640 // a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]).
641 JSMutableHandle<SourceTextModule> importedModule(thread, thread->GlobalConstants()->GetUndefined());
642 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
643 if (moduleRecordName.IsUndefined()) {
644 JSHandle<JSTaggedValue> importedVal =
645 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest);
646 RETURN_IF_ABRUPT_COMPLETION(thread);
647 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal));
648 } else {
649 ASSERT(moduleRecordName.IsString());
650 JSHandle<JSTaggedValue> importedVal =
651 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest);
652 RETURN_IF_ABRUPT_COMPLETION(thread);
653 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal));
654 }
655 // c. If in.[[ImportName]] is "*", then
656 JSHandle<JSTaggedValue> starString = globalConstants->GetHandledStarString();
657 if (JSTaggedValue::SameValue(importName, starString)) {
658 // i. Let namespace be ? GetModuleNamespace(importedModule).
659 JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, importedModule);
660 // ii. Perform ! envRec.CreateImmutableBinding(in.[[LocalName]], true).
661 // iii. Call envRec.InitializeBinding(in.[[LocalName]], namespace).
662 JSHandle<NameDictionary> mapHandle = JSHandle<NameDictionary>::Cast(envRec);
663 JSHandle<NameDictionary> newMap = NameDictionary::Put(thread, mapHandle, localName, moduleNamespace,
664 PropertyAttributes::Default());
665 envRec.Update(newMap);
666 } else {
667 // i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »).
668 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector;
669 JSHandle<JSTaggedValue> resolution =
670 SourceTextModule::ResolveExport(thread, importedModule, importName, resolveVector);
671 // ii. If resolution is null or "ambiguous", throw a SyntaxError exception.
672 if (resolution->IsNull() || resolution->IsString()) {
673 CString msg = "the requested module '" +
674 ConvertToString(moduleRequest.GetTaggedValue()) +
675 "' does not provide an export named '" +
676 ConvertToString(importName.GetTaggedValue());
677 if (!module->GetEcmaModuleRecordName().IsUndefined()) {
678 msg += "' which imported by '" + ConvertToString(module->GetEcmaModuleRecordName()) + "'";
679 } else {
680 msg += "' which imported by '" + ConvertToString(module->GetEcmaModuleFilename()) + "'";
681 }
682 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str());
683 }
684 // iii. Call envRec.CreateImportBinding(
685 // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
686 JSHandle<NameDictionary> mapHandle = JSHandle<NameDictionary>::Cast(envRec);
687 JSHandle<NameDictionary> newMap = NameDictionary::Put(thread, mapHandle, localName, resolution,
688 PropertyAttributes::Default());
689 envRec.Update(newMap);
690 }
691 }
692
693 module->SetEnvironment(thread, envRec);
694 }
695
ModuleDeclarationArrayEnvironmentSetup(JSThread * thread,const JSHandle<SourceTextModule> & module)696 void SourceTextModule::ModuleDeclarationArrayEnvironmentSetup(JSThread *thread,
697 const JSHandle<SourceTextModule> &module)
698 {
699 CheckResolvedIndexBinding(thread, module);
700 if (module->GetImportEntries().IsUndefined()) {
701 return;
702 }
703 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
704
705 // 2. Assert: All named exports from module are resolvable.
706 // 3. Let realm be module.[[Realm]].
707 // 4. Assert: realm is not undefined.
708 // 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
709 JSHandle<TaggedArray> importEntries(thread, module->GetImportEntries());
710 size_t importEntriesLen = importEntries->GetLength();
711 JSHandle<TaggedArray> arr = factory->NewTaggedArray(importEntriesLen);
712 // 6. Set module.[[Environment]] to env.
713 module->SetEnvironment(thread, arr);
714 // 7. Let envRec be env's EnvironmentRecord.
715 JSHandle<TaggedArray> envRec = arr;
716 // 8. For each ImportEntry Record in in module.[[ImportEntries]], do
717 auto globalConstants = thread->GlobalConstants();
718 JSMutableHandle<ImportEntry> in(thread, globalConstants->GetUndefined());
719 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
720 JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined());
721 for (size_t idx = 0; idx < importEntriesLen; idx++) {
722 in.Update(importEntries->Get(idx));
723 importName.Update(in->GetImportName());
724 moduleRequest.Update(in->GetModuleRequest());
725 // a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]).
726 JSMutableHandle<SourceTextModule> importedModule(thread, thread->GlobalConstants()->GetUndefined());
727 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
728 if (moduleRecordName.IsUndefined()) {
729 JSHandle<JSTaggedValue> importedVal =
730 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest);
731 RETURN_IF_ABRUPT_COMPLETION(thread);
732 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal));
733 } else {
734 ASSERT(moduleRecordName.IsString());
735 JSHandle<JSTaggedValue> importedVal =
736 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest);
737 RETURN_IF_ABRUPT_COMPLETION(thread);
738 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal));
739 }
740 // c. If in.[[ImportName]] is "*", then
741 JSHandle<JSTaggedValue> starString = globalConstants->GetHandledStarString();
742 if (JSTaggedValue::SameValue(importName, starString)) {
743 // need refactor
744 return;
745 }
746 // i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »).
747 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector;
748 JSHandle<JSTaggedValue> resolution =
749 SourceTextModule::ResolveExport(thread, importedModule, importName, resolveVector);
750 // ii. If resolution is null or "ambiguous", throw a SyntaxError exception.
751 if (resolution->IsNull() || resolution->IsString()) {
752 if (thread->GetEcmaVM()->EnableReportModuleResolvingFailure()) {
753 CString msg = "the requested module '" +
754 ConvertToString(moduleRequest.GetTaggedValue()) +
755 "' does not provide an export named '" +
756 ConvertToString(importName.GetTaggedValue());
757 if (!module->GetEcmaModuleRecordName().IsUndefined()) {
758 msg += "' which imported by '" + ConvertToString(module->GetEcmaModuleRecordName()) + "'";
759 } else {
760 msg += "' which imported by '" + ConvertToString(module->GetEcmaModuleFilename()) + "'";
761 }
762 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str());
763 } else {
764 // if in aot compiation, we should skip this error.
765 envRec->Set(thread, idx, JSTaggedValue::Hole());
766 continue;
767 }
768 }
769 // iii. Call envRec.CreateImportBinding(
770 // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
771 envRec->Set(thread, idx, resolution);
772 }
773
774 module->SetEnvironment(thread, envRec);
775 }
776
GetModuleNamespace(JSThread * thread,const JSHandle<SourceTextModule> & module)777 JSHandle<JSTaggedValue> SourceTextModule::GetModuleNamespace(JSThread *thread,
778 const JSHandle<SourceTextModule> &module)
779 {
780 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
781 // 1. Assert: module is an instance of a concrete subclass of Module Record.
782 // 2. Assert: module.[[Status]] is not "uninstantiated".
783 ModuleStatus status = module->GetStatus();
784 ASSERT(status != ModuleStatus::UNINSTANTIATED);
785 // 3. Assert: If module.[[Status]] is "evaluated", module.[[EvaluationError]] is undefined.
786 if (status == ModuleStatus::EVALUATED) {
787 ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
788 }
789 // 4. Let namespace be module.[[Namespace]].
790 JSMutableHandle<JSTaggedValue> moduleNamespace(thread, module->GetNamespace());
791 // If namespace is undefined, then
792 if (moduleNamespace->IsUndefined()) {
793 // a. Let exportedNames be ? module.GetExportedNames(« »).
794 JSHandle<TaggedArray> exportStarSet = factory->EmptyArray();
795 CVector<std::string> exportedNames = SourceTextModule::GetExportedNames(thread, module, exportStarSet);
796 // b. Let unambiguousNames be a new empty List.
797 JSHandle<TaggedArray> unambiguousNames = factory->NewTaggedArray(exportedNames.size());
798 // c. For each name that is an element of exportedNames, do
799 size_t idx = 0;
800 for (std::string &name : exportedNames) {
801 // i. Let resolution be ? module.ResolveExport(name, « »).
802 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector;
803 JSHandle<JSTaggedValue> nameHandle = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(name));
804 JSHandle<JSTaggedValue> resolution =
805 SourceTextModule::ResolveExport(thread, module, nameHandle, resolveVector);
806 // ii. If resolution is a ResolvedBinding Record, append name to unambiguousNames.
807 if (resolution->IsResolvedBinding() || resolution->IsResolvedIndexBinding()) {
808 unambiguousNames->Set(thread, idx, nameHandle);
809 idx++;
810 }
811 }
812 JSHandle<TaggedArray> fixUnambiguousNames = TaggedArray::SetCapacity(thread, unambiguousNames, idx);
813 JSHandle<JSTaggedValue> moduleTagged = JSHandle<JSTaggedValue>::Cast(module);
814 JSHandle<ModuleNamespace> np =
815 ModuleNamespace::ModuleNamespaceCreate(thread, moduleTagged, fixUnambiguousNames);
816 moduleNamespace.Update(np.GetTaggedValue());
817 }
818 return moduleNamespace;
819 }
820
Evaluate(JSThread * thread,const JSHandle<SourceTextModule> & module,const void * buffer,size_t size,bool excuteFromJob)821 int SourceTextModule::Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &module,
822 const void *buffer, size_t size, bool excuteFromJob)
823 {
824 // 1. Let module be this Source Text Module Record.
825 // 2. Assert: module.[[Status]] is "instantiated" or "evaluated".
826 [[maybe_unused]] ModuleStatus status = module->GetStatus();
827 ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED));
828 // 3. Let stack be a new empty List.
829 CVector<JSHandle<SourceTextModule>> stack;
830 // 4. Let result be InnerModuleEvaluation(module, stack, 0)
831 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
832 int result = SourceTextModule::InnerModuleEvaluation(thread, moduleRecord, stack, 0, buffer, size, excuteFromJob);
833 // 5. If result is an abrupt completion, then
834 if (thread->HasPendingException()) {
835 // a. For each module m in stack, do
836 for (auto mm : stack) {
837 // i. Assert: m.[[Status]] is "evaluating".
838 ASSERT(mm->GetStatus() == ModuleStatus::EVALUATING);
839 // ii. Set m.[[Status]] to "evaluated".
840 mm->SetStatus(ModuleStatus::EVALUATED);
841 // iii. Set m.[[EvaluationError]] to result.
842 mm->SetEvaluationError(result);
843 }
844 // b. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is result.
845 status = module->GetStatus();
846 ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == result);
847 // c. return result
848 return result;
849 }
850 // 6. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is undefined.
851 status = module->GetStatus();
852 ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
853 // 7. Assert: stack is empty.
854 ASSERT(stack.empty());
855 // 8. Return undefined.
856 return SourceTextModule::UNDEFINED_INDEX;
857 }
858
EvaluateForConcurrent(JSThread * thread,const JSHandle<SourceTextModule> & module)859 int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module)
860 {
861 // 1. Let module be this Source Text Module Record.
862 // 2. Assert: module.[[Status]] is "instantiated" or "evaluated".
863 [[maybe_unused]] ModuleStatus status = module->GetStatus();
864 ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED));
865 // 3. Let stack be a new empty List.
866 CVector<JSHandle<SourceTextModule>> stack;
867 // 4. Let result be InnerModuleEvaluation(module, stack, 0)
868 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
869 int result = SourceTextModule::ModuleEvaluation(thread, moduleRecord, stack, 0);
870 // 5. If result is an abrupt completion, then
871 if (thread->HasPendingException()) {
872 // a. For each module m in stack, do
873 for (auto mm : stack) {
874 // i. Assert: m.[[Status]] is "evaluating".
875 ASSERT(mm->GetStatus() == ModuleStatus::EVALUATING);
876 // ii. Set m.[[Status]] to "evaluated".
877 mm->SetStatus(ModuleStatus::EVALUATED);
878 // iii. Set m.[[EvaluationError]] to result.
879 mm->SetEvaluationError(result);
880 }
881 // b. Assert: module.[[EvaluationError]] is result.
882 ASSERT(module->GetEvaluationError() == result);
883 // c. return result
884 return result;
885 }
886 // 6. Assert: module.[[EvaluationError]] is undefined.
887 ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
888 // 7. Assert: stack is empty.
889 ASSERT(stack.empty());
890 // 8. Return undefined.
891 return SourceTextModule::UNDEFINED_INDEX;
892 }
893
InnerModuleEvaluation(JSThread * thread,const JSHandle<ModuleRecord> & moduleRecord,CVector<JSHandle<SourceTextModule>> & stack,int index,const void * buffer,size_t size,bool excuteFromJob)894 int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
895 CVector<JSHandle<SourceTextModule>> &stack, int index,
896 const void *buffer, size_t size, bool excuteFromJob)
897 {
898 // 1. If module is not a Source Text Module Record, then
899 if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) {
900 // a. Perform ? module.Instantiate().
901 ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
902 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
903 // b. Return index.
904 return index;
905 }
906 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
907 // 2.If module.[[Status]] is "evaluated", then
908 ModuleStatus status = module->GetStatus();
909 if (status == ModuleStatus::EVALUATED) {
910 // a. If module.[[EvaluationError]] is undefined, return index
911 if (module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX) {
912 return index;
913 }
914 // Otherwise return module.[[EvaluationError]].
915 return module->GetEvaluationError();
916 }
917 // 3. If module.[[Status]] is "evaluating", return index.
918 if (status == ModuleStatus::EVALUATING) {
919 return index;
920 }
921 // 4. Assert: module.[[Status]] is "instantiated".
922 ASSERT(status == ModuleStatus::INSTANTIATED);
923 // 5. Set module.[[Status]] to "evaluating".
924 module->SetStatus(ModuleStatus::EVALUATING);
925 // 6. Set module.[[DFSIndex]] to index.
926 module->SetDFSIndex(index);
927 // 7. Set module.[[DFSAncestorIndex]] to index.
928 module->SetDFSAncestorIndex(index);
929 // 8. Set index to index + 1.
930 index++;
931 // 9. Append module to stack.
932 stack.emplace_back(module);
933 // 10. For each String required that is an element of module.[[RequestedModules]], do
934 if (!module->GetRequestedModules().IsUndefined()) {
935 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
936 size_t requestedModulesLen = requestedModules->GetLength();
937 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
938 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
939 required.Update(requestedModules->Get(idx));
940 // a. Let requiredModule be ! HostResolveImportedModule(module, required).
941 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
942 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
943 if (moduleRecordName.IsUndefined()) {
944 JSHandle<JSTaggedValue> requiredVal =
945 SourceTextModule::HostResolveImportedModule(thread, module, required);
946 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
947 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
948 } else {
949 ASSERT(moduleRecordName.IsString());
950 JSHandle<JSTaggedValue> requiredVal =
951 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
952 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
953 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
954 }
955 ModuleTypes moduleType = requiredModule->GetTypes();
956 if (SourceTextModule::IsNativeModule(moduleType)) {
957 InstantiateNativeModule(thread, module, requiredModule, required, moduleType);
958 requiredModule->SetStatus(ModuleStatus::EVALUATED);
959 continue;
960 }
961 // if requiredModule is jsonModule, then don't need to execute.
962 if (moduleType == ModuleTypes::JSON_MODULE) {
963 requiredModule->SetStatus(ModuleStatus::EVALUATED);
964 continue;
965 }
966 // c. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
967 JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
968 index = SourceTextModule::InnerModuleEvaluation(thread, requiredModuleRecord, stack, index);
969 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
970 // d. Assert: requiredModule.[[Status]] is either "evaluating" or "evaluated".
971 ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
972 ASSERT((requiredModuleStatus == ModuleStatus::EVALUATING ||
973 requiredModuleStatus == ModuleStatus::EVALUATED));
974 // e. Assert: requiredModule.[[Status]] is "evaluating" if and only if requiredModule is in stack.
975 if (requiredModuleStatus == ModuleStatus::EVALUATING) {
976 ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end());
977 }
978 // f. If requiredModule.[[Status]] is "evaluating", then
979 if (requiredModuleStatus == ModuleStatus::EVALUATING) {
980 // i. Assert: requiredModule is a Source Text Module Record.
981 // ii. Set module.[[DFSAncestorIndex]] to min(
982 // module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
983 int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex());
984 module->SetDFSAncestorIndex(dfsAncIdx);
985 }
986 // if requiredModule is CommonJS Module, instantiate here (after CommonJS execution).
987 if (moduleType == ModuleTypes::CJS_MODULE) {
988 InstantiateCJS(thread, module, requiredModule);
989 }
990 }
991 }
992
993 // 11. Perform ? ModuleExecution(module).
994 SourceTextModule::ModuleExecution(thread, module, buffer, size, excuteFromJob);
995 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
996 // 12. Assert: module occurs exactly once in stack.
997 // 13. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]].
998 int dfsAncIdx = module->GetDFSAncestorIndex();
999 int dfsIdx = module->GetDFSIndex();
1000 ASSERT(dfsAncIdx <= dfsIdx);
1001 // 14. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then
1002 if (dfsAncIdx == dfsIdx) {
1003 // a. Let done be false.
1004 bool done = false;
1005 // b. Repeat, while done is false,
1006 while (!done) {
1007 // i. Let requiredModule be the last element in stack.
1008 JSHandle<SourceTextModule> requiredModule = stack.back();
1009 // ii. Remove the last element of stack.
1010 stack.pop_back();
1011 // iii. Set requiredModule.[[Status]] to "evaluated".
1012 requiredModule->SetStatus(ModuleStatus::EVALUATED);
1013 // iv. If requiredModule and module are the same Module Record, set done to true.
1014 if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) {
1015 done = true;
1016 }
1017 }
1018 }
1019 return index;
1020 }
1021
ModuleEvaluation(JSThread * thread,const JSHandle<ModuleRecord> & moduleRecord,CVector<JSHandle<SourceTextModule>> & stack,int index)1022 int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
1023 CVector<JSHandle<SourceTextModule>> &stack, int index)
1024 {
1025 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
1026 if (!module->GetRequestedModules().IsUndefined()) {
1027 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
1028 size_t requestedModulesLen = requestedModules->GetLength();
1029 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
1030 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
1031 required.Update(requestedModules->Get(idx));
1032 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
1033 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
1034 if (moduleRecordName.IsUndefined()) {
1035 requiredModule.Update(SourceTextModule::HostResolveImportedModule(thread, module, required));
1036 } else {
1037 ASSERT(moduleRecordName.IsString());
1038 requiredModule.Update(SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required));
1039 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
1040 }
1041 ModuleTypes moduleType = requiredModule->GetTypes();
1042 if (SourceTextModule::IsNativeModule(moduleType)) {
1043 InstantiateNativeModule(thread, module, requiredModule, required, moduleType);
1044 requiredModule->SetStatus(ModuleStatus::EVALUATED);
1045 continue;
1046 }
1047 if (moduleType == ModuleTypes::JSON_MODULE) {
1048 requiredModule->SetStatus(ModuleStatus::EVALUATED);
1049 continue;
1050 }
1051 JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
1052 index = SourceTextModule::InnerModuleEvaluation(thread, requiredModuleRecord, stack, index);
1053 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
1054 [[maybe_unused]] ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
1055 ASSERT(requiredModuleStatus == ModuleStatus::EVALUATED);
1056 if (moduleType == ModuleTypes::CJS_MODULE) {
1057 InstantiateCJS(thread, module, requiredModule);
1058 }
1059 }
1060 }
1061 return index;
1062 }
1063
ModuleExecution(JSThread * thread,const JSHandle<SourceTextModule> & module,const void * buffer,size_t size,bool excuteFromJob)1064 void SourceTextModule::ModuleExecution(JSThread *thread, const JSHandle<SourceTextModule> &module,
1065 const void *buffer, size_t size, bool excuteFromJob)
1066 {
1067 JSTaggedValue moduleFileName = module->GetEcmaModuleFilename();
1068 ASSERT(moduleFileName.IsString());
1069 CString moduleFilenameStr = ConvertToString(EcmaString::Cast(moduleFileName.GetTaggedObject()));
1070
1071 std::string entryPoint;
1072 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
1073 if (moduleRecordName.IsUndefined()) {
1074 entryPoint = JSPandaFile::ENTRY_FUNCTION_NAME;
1075 } else {
1076 ASSERT(moduleRecordName.IsString());
1077 entryPoint = ConvertToString(moduleRecordName);
1078 }
1079
1080 std::shared_ptr<JSPandaFile> jsPandaFile;
1081 if (buffer != nullptr) {
1082 jsPandaFile =
1083 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint, buffer, size);
1084 } else {
1085 jsPandaFile =
1086 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint);
1087 }
1088
1089 if (jsPandaFile == nullptr) {
1090 CString msg = "Load file with filename '" + moduleFilenameStr + "' failed, recordName '" +
1091 entryPoint.c_str() + "'";
1092 THROW_ERROR(thread, ErrorType::REFERENCE_ERROR, msg.c_str());
1093 }
1094 JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entryPoint, excuteFromJob);
1095 }
1096
AddImportEntry(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<ImportEntry> & importEntry,size_t idx,uint32_t len)1097 void SourceTextModule::AddImportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module,
1098 const JSHandle<ImportEntry> &importEntry, size_t idx, uint32_t len)
1099 {
1100 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1101 JSTaggedValue importEntries = module->GetImportEntries();
1102 if (importEntries.IsUndefined()) {
1103 JSHandle<TaggedArray> array = factory->NewTaggedArray(len);
1104 array->Set(thread, idx, importEntry.GetTaggedValue());
1105 module->SetImportEntries(thread, array);
1106 } else {
1107 JSHandle<TaggedArray> entries(thread, importEntries);
1108 if (len > entries->GetLength()) {
1109 entries = TaggedArray::SetCapacity(thread, entries, len);
1110 entries->Set(thread, idx, importEntry.GetTaggedValue());
1111 module->SetImportEntries(thread, entries);
1112 return;
1113 }
1114 entries->Set(thread, idx, importEntry.GetTaggedValue());
1115 }
1116 }
1117
AddLocalExportEntry(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<LocalExportEntry> & exportEntry,size_t idx,uint32_t len)1118 void SourceTextModule::AddLocalExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module,
1119 const JSHandle<LocalExportEntry> &exportEntry, size_t idx, uint32_t len)
1120 {
1121 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1122 JSTaggedValue localExportEntries = module->GetLocalExportEntries();
1123 if (localExportEntries.IsUndefined()) {
1124 JSHandle<TaggedArray> array = factory->NewTaggedArray(len);
1125 array->Set(thread, idx, exportEntry.GetTaggedValue());
1126 module->SetLocalExportEntries(thread, array);
1127 } else {
1128 JSHandle<TaggedArray> entries(thread, localExportEntries);
1129 entries->Set(thread, idx, exportEntry.GetTaggedValue());
1130 }
1131 }
1132
AddIndirectExportEntry(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<IndirectExportEntry> & exportEntry,size_t idx,uint32_t len)1133 void SourceTextModule::AddIndirectExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module,
1134 const JSHandle<IndirectExportEntry> &exportEntry,
1135 size_t idx, uint32_t len)
1136 {
1137 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1138 JSTaggedValue indirectExportEntries = module->GetIndirectExportEntries();
1139 if (indirectExportEntries.IsUndefined()) {
1140 JSHandle<TaggedArray> array = factory->NewTaggedArray(len);
1141 array->Set(thread, idx, exportEntry.GetTaggedValue());
1142 module->SetIndirectExportEntries(thread, array);
1143 } else {
1144 JSHandle<TaggedArray> entries(thread, indirectExportEntries);
1145 entries->Set(thread, idx, exportEntry.GetTaggedValue());
1146 }
1147 }
1148
AddStarExportEntry(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<StarExportEntry> & exportEntry,size_t idx,uint32_t len)1149 void SourceTextModule::AddStarExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module,
1150 const JSHandle<StarExportEntry> &exportEntry, size_t idx, uint32_t len)
1151 {
1152 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1153 JSTaggedValue starExportEntries = module->GetStarExportEntries();
1154 if (starExportEntries.IsUndefined()) {
1155 JSHandle<TaggedArray> array = factory->NewTaggedArray(len);
1156 array->Set(thread, idx, exportEntry.GetTaggedValue());
1157 module->SetStarExportEntries(thread, array);
1158 } else {
1159 JSHandle<TaggedArray> entries(thread, starExportEntries);
1160 entries->Set(thread, idx, exportEntry.GetTaggedValue());
1161 }
1162 }
1163
GetModuleValue(JSThread * thread,int32_t index,bool isThrow)1164 JSTaggedValue SourceTextModule::GetModuleValue(JSThread *thread, int32_t index, bool isThrow)
1165 {
1166 DISALLOW_GARBAGE_COLLECTION;
1167 JSTaggedValue dictionary = GetNameDictionary();
1168 if (dictionary.IsUndefined()) {
1169 if (isThrow) {
1170 THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", JSTaggedValue::Exception());
1171 }
1172 return JSTaggedValue::Hole();
1173 }
1174
1175 TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject());
1176 return array->Get(index);
1177 }
1178
GetModuleValue(JSThread * thread,JSTaggedValue key,bool isThrow)1179 JSTaggedValue SourceTextModule::GetModuleValue(JSThread *thread, JSTaggedValue key, bool isThrow)
1180 {
1181 DISALLOW_GARBAGE_COLLECTION;
1182 JSTaggedValue dictionary = GetNameDictionary();
1183 if (dictionary.IsUndefined()) {
1184 if (isThrow) {
1185 THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", JSTaggedValue::Exception());
1186 }
1187 return JSTaggedValue::Hole();
1188 }
1189
1190 NameDictionary *dict = NameDictionary::Cast(dictionary.GetTaggedObject());
1191 int entry = dict->FindEntry(key);
1192 if (entry != -1) {
1193 return dict->GetValue(entry);
1194 }
1195
1196 // when key is exportName, need to get localName
1197 JSTaggedValue exportEntriesTv = GetLocalExportEntries();
1198 if (!exportEntriesTv.IsUndefined()) {
1199 JSTaggedValue resolution = FindByExport(exportEntriesTv, key, dictionary);
1200 if (!resolution.IsHole()) {
1201 return resolution;
1202 }
1203 }
1204
1205 return JSTaggedValue::Hole();
1206 }
1207
FindByExport(const JSTaggedValue & exportEntriesTv,const JSTaggedValue & key,const JSTaggedValue & dictionary)1208 JSTaggedValue SourceTextModule::FindByExport(const JSTaggedValue &exportEntriesTv, const JSTaggedValue &key,
1209 const JSTaggedValue &dictionary)
1210 {
1211 DISALLOW_GARBAGE_COLLECTION;
1212 NameDictionary *dict = NameDictionary::Cast(dictionary.GetTaggedObject());
1213 TaggedArray *exportEntries = TaggedArray::Cast(exportEntriesTv.GetTaggedObject());
1214 size_t exportEntriesLen = exportEntries->GetLength();
1215 for (size_t idx = 0; idx < exportEntriesLen; idx++) {
1216 LocalExportEntry *ee = LocalExportEntry::Cast(exportEntries->Get(idx).GetTaggedObject());
1217 if (!JSTaggedValue::SameValue(ee->GetExportName(), key)) {
1218 continue;
1219 }
1220 JSTaggedValue localName = ee->GetLocalName();
1221 int entry = dict->FindEntry(localName);
1222 if (entry != -1) {
1223 return dict->GetValue(entry);
1224 }
1225 }
1226
1227 return JSTaggedValue::Hole();
1228 }
1229
StoreModuleValue(JSThread * thread,int32_t index,const JSHandle<JSTaggedValue> & value)1230 void SourceTextModule::StoreModuleValue(JSThread *thread, int32_t index, const JSHandle<JSTaggedValue> &value)
1231 {
1232 JSHandle<SourceTextModule> module(thread, this);
1233 JSTaggedValue localExportEntries = module->GetLocalExportEntries();
1234 ASSERT(localExportEntries.IsTaggedArray());
1235
1236 JSHandle<JSTaggedValue> data(thread, module->GetNameDictionary());
1237 if (data->IsUndefined()) {
1238 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1239 uint32_t size = TaggedArray::Cast(localExportEntries.GetTaggedObject())->GetLength();
1240 ASSERT(index < static_cast<int32_t>(size));
1241 data = JSHandle<JSTaggedValue>(factory->NewTaggedArray(size));
1242 module->SetNameDictionary(thread, data);
1243 }
1244 JSHandle<TaggedArray> arr(data);
1245 arr->Set(thread, index, value);
1246 }
1247
StoreModuleValue(JSThread * thread,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1248 void SourceTextModule::StoreModuleValue(JSThread *thread, const JSHandle<JSTaggedValue> &key,
1249 const JSHandle<JSTaggedValue> &value)
1250 {
1251 JSHandle<SourceTextModule> module(thread, this);
1252 JSMutableHandle<JSTaggedValue> data(thread, module->GetNameDictionary());
1253 if (data->IsUndefined()) {
1254 data.Update(NameDictionary::Create(thread, DEFAULT_DICTIONART_CAPACITY));
1255 }
1256 JSHandle<NameDictionary> dataDict = JSHandle<NameDictionary>::Cast(data);
1257 data.Update(NameDictionary::Put(thread, dataDict, key, value, PropertyAttributes::Default()));
1258
1259 module->SetNameDictionary(thread, data);
1260 }
1261
SetExportName(JSThread * thread,const JSHandle<JSTaggedValue> & moduleRequest,const JSHandle<SourceTextModule> & module,CVector<std::string> & exportedNames,JSHandle<TaggedArray> & newExportStarSet)1262 void SourceTextModule::SetExportName(JSThread *thread, const JSHandle<JSTaggedValue> &moduleRequest,
1263 const JSHandle<SourceTextModule> &module,
1264 CVector<std::string> &exportedNames, JSHandle<TaggedArray> &newExportStarSet)
1265
1266 {
1267 JSMutableHandle<SourceTextModule> requestedModule(thread, thread->GlobalConstants()->GetUndefined());
1268 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
1269 if (moduleRecordName.IsUndefined()) {
1270 JSHandle<JSTaggedValue> requestedVal =
1271 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest);
1272 RETURN_IF_ABRUPT_COMPLETION(thread);
1273 requestedModule.Update(JSHandle<SourceTextModule>::Cast(requestedVal));
1274 } else {
1275 ASSERT(moduleRecordName.IsString());
1276 JSHandle<JSTaggedValue> requestedVal =
1277 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest);
1278 RETURN_IF_ABRUPT_COMPLETION(thread);
1279 requestedModule.Update(JSHandle<SourceTextModule>::Cast(requestedVal));
1280 }
1281 // b. Let starNames be ? requestedModule.GetExportedNames(exportStarSet).
1282 CVector<std::string> starNames =
1283 SourceTextModule::GetExportedNames(thread, requestedModule, newExportStarSet);
1284 // c. For each element n of starNames, do
1285 for (std::string &nn : starNames) {
1286 // i. If SameValue(n, "default") is false, then
1287 if (nn != "default" && std::find(exportedNames.begin(), exportedNames.end(), nn) == exportedNames.end()) {
1288 // 1. If n is not an element of exportedNames, then
1289 // a. Append n to exportedNames.
1290 exportedNames.emplace_back(nn);
1291 }
1292 }
1293 }
1294
GetStarResolution(JSThread * thread,const JSHandle<JSTaggedValue> & exportName,const JSHandle<JSTaggedValue> & moduleRequest,const JSHandle<SourceTextModule> & module,JSMutableHandle<JSTaggedValue> & starResolution,CVector<std::pair<JSHandle<SourceTextModule>,JSHandle<JSTaggedValue>>> & resolveVector)1295 JSHandle<JSTaggedValue> SourceTextModule::GetStarResolution(JSThread *thread,
1296 const JSHandle<JSTaggedValue> &exportName,
1297 const JSHandle<JSTaggedValue> &moduleRequest,
1298 const JSHandle<SourceTextModule> &module,
1299 JSMutableHandle<JSTaggedValue> &starResolution,
1300 CVector<std::pair<JSHandle<SourceTextModule>,
1301 JSHandle<JSTaggedValue>>> &resolveVector)
1302 {
1303 auto globalConstants = thread->GlobalConstants();
1304 // a. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
1305 JSMutableHandle<SourceTextModule> importedModule(thread, thread->GlobalConstants()->GetUndefined());
1306 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
1307 if (moduleRecordName.IsUndefined()) {
1308 JSHandle<JSTaggedValue> importedVal =
1309 SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest);
1310 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1311 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal));
1312 } else {
1313 ASSERT(moduleRecordName.IsString());
1314 JSHandle<JSTaggedValue> importedVal =
1315 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest);
1316 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1317 importedModule.Update(JSHandle<SourceTextModule>::Cast(importedVal));
1318 }
1319 // b. Let resolution be ? importedModule.ResolveExport(exportName, resolveVector).
1320 JSHandle<JSTaggedValue> resolution =
1321 SourceTextModule::ResolveExport(thread, importedModule, exportName, resolveVector);
1322 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1323 // if step into GetStarResolution in aot phase, the module must be a normal SourceTextModule not an empty
1324 // aot module. Sometimes for normal module, if indirectExportEntries, localExportEntries, starExportEntries
1325 // all don't have right exportName which means the export element is not from this module,
1326 // it should return null but now will be hole.
1327 if (!thread->GetEcmaVM()->EnableReportModuleResolvingFailure() && resolution->IsHole()) {
1328 return globalConstants->GetHandledNull();
1329 }
1330 // c. If resolution is "ambiguous", return "ambiguous".
1331 if (resolution->IsString()) { // if resolution is string, resolution must be "ambiguous"
1332 return globalConstants->GetHandledAmbiguousString();
1333 }
1334 // d. If resolution is not null, then
1335 if (resolution->IsNull()) {
1336 return globalConstants->GetHandledNull();
1337 }
1338 // i. Assert: resolution is a ResolvedBinding Record.
1339 ASSERT(resolution->IsResolvedBinding() || resolution->IsResolvedIndexBinding());
1340 // ii. If starResolution is null, set starResolution to resolution.
1341 if (starResolution->IsNull()) {
1342 starResolution.Update(resolution.GetTaggedValue());
1343 } else {
1344 // 1. Assert: There is more than one * import that includes the requested name.
1345 // 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record or
1346 // SameValue(
1347 // resolution.[[BindingName]], starResolution.[[BindingName]]) is false, return "ambiguous".
1348 // Adapter new opcode
1349 if (resolution->IsResolvedBinding()) {
1350 JSHandle<ResolvedBinding> resolutionBd = JSHandle<ResolvedBinding>::Cast(resolution);
1351 JSHandle<ResolvedBinding> starResolutionBd = JSHandle<ResolvedBinding>::Cast(starResolution);
1352 if ((!JSTaggedValue::SameValue(resolutionBd->GetModule(), starResolutionBd->GetModule())) ||
1353 (!JSTaggedValue::SameValue(
1354 resolutionBd->GetBindingName(), starResolutionBd->GetBindingName()))) {
1355 return globalConstants->GetHandledAmbiguousString();
1356 }
1357 } else {
1358 JSHandle<ResolvedIndexBinding> resolutionBd = JSHandle<ResolvedIndexBinding>::Cast(resolution);
1359 JSHandle<ResolvedIndexBinding> starResolutionBd = JSHandle<ResolvedIndexBinding>::Cast(starResolution);
1360 if ((!JSTaggedValue::SameValue(resolutionBd->GetModule(), starResolutionBd->GetModule())) ||
1361 resolutionBd->GetIndex() != starResolutionBd->GetIndex()) {
1362 return globalConstants->GetHandledAmbiguousString();
1363 }
1364 }
1365 }
1366 return resolution;
1367 }
1368
1369 template <typename T>
AddExportName(JSThread * thread,const JSTaggedValue & exportEntry,CVector<std::string> & exportedNames)1370 void SourceTextModule::AddExportName(JSThread *thread, const JSTaggedValue &exportEntry,
1371 CVector<std::string> &exportedNames)
1372 {
1373 if (!exportEntry.IsUndefined()) {
1374 JSMutableHandle<T> ee(thread, thread->GlobalConstants()->GetUndefined());
1375 JSHandle<TaggedArray> exportEntries(thread, exportEntry);
1376 size_t exportEntriesLen = exportEntries->GetLength();
1377 for (size_t idx = 0; idx < exportEntriesLen; idx++) {
1378 ee.Update(exportEntries->Get(idx));
1379 // a. Assert: module provides the direct binding for this export.
1380 // b. Append e.[[ExportName]] to exportedNames.
1381 std::string exportName = EcmaStringAccessor(ee->GetExportName()).ToStdString();
1382 exportedNames.emplace_back(exportName);
1383 }
1384 }
1385 }
1386
ResolveElementOfObject(JSThread * thread,const JSHandle<JSHClass> & hclass,const JSHandle<JSTaggedValue> & exportName,const JSHandle<SourceTextModule> & module)1387 JSHandle<JSTaggedValue> SourceTextModule::ResolveElementOfObject(JSThread *thread,
1388 const JSHandle<JSHClass> &hclass,
1389 const JSHandle<JSTaggedValue> &exportName,
1390 const JSHandle<SourceTextModule> &module)
1391 {
1392 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1393 int idx = JSHClass::FindPropertyEntry(thread, *hclass, exportName.GetTaggedValue());
1394 if (idx != -1) {
1395 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, idx));
1396 }
1397 return thread->GlobalConstants()->GetHandledUndefined();
1398 }
1399
ResolveLocalExport(JSThread * thread,const JSHandle<JSTaggedValue> & exportEntry,const JSHandle<JSTaggedValue> & exportName,const JSHandle<SourceTextModule> & module)1400 JSHandle<JSTaggedValue> SourceTextModule::ResolveLocalExport(JSThread *thread,
1401 const JSHandle<JSTaggedValue> &exportEntry,
1402 const JSHandle<JSTaggedValue> &exportName,
1403 const JSHandle<SourceTextModule> &module)
1404 {
1405 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1406 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
1407 JSMutableHandle<JSTaggedValue> localName(thread, thread->GlobalConstants()->GetUndefined());
1408
1409 JSHandle<TaggedArray> localExportEntries(exportEntry);
1410 size_t localExportEntriesLen = localExportEntries->GetLength();
1411 for (size_t idx = 0; idx < localExportEntriesLen; idx++) {
1412 ee.Update(localExportEntries->Get(idx));
1413 // a. If SameValue(exportName, e.[[ExportName]]) is true, then
1414 // if module is type of CommonJS or native, export first, check after execution.
1415 auto moduleType = module->GetTypes();
1416 if (moduleType == ModuleTypes::CJS_MODULE) {
1417 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedBindingRecord(module, exportName));
1418 }
1419
1420 if ((JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue())) ||
1421 IsNativeModule(moduleType)) {
1422 // Adapter new module
1423 if (module->GetIsNewBcVersion()) {
1424 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module,
1425 ee->GetLocalIndex()));
1426 }
1427 // i. Assert: module provides the direct binding for this export.
1428 // ii. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }.
1429 localName.Update(ee->GetLocalName());
1430 return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedBindingRecord(module, localName));
1431 }
1432 }
1433 return thread->GlobalConstants()->GetHandledUndefined();
1434 }
1435
ResolveIndirectExport(JSThread * thread,const JSHandle<JSTaggedValue> & exportEntry,const JSHandle<JSTaggedValue> & exportName,const JSHandle<SourceTextModule> & module,CVector<std::pair<JSHandle<SourceTextModule>,JSHandle<JSTaggedValue>>> & resolveVector)1436 JSHandle<JSTaggedValue> SourceTextModule::ResolveIndirectExport(JSThread *thread,
1437 const JSHandle<JSTaggedValue> &exportEntry,
1438 const JSHandle<JSTaggedValue> &exportName,
1439 const JSHandle<SourceTextModule> &module,
1440 CVector<std::pair<JSHandle<SourceTextModule>,
1441 JSHandle<JSTaggedValue>>> &resolveVector)
1442 {
1443 auto globalConstants = thread->GlobalConstants();
1444 JSMutableHandle<IndirectExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
1445 JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
1446 JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined());
1447 JSHandle<TaggedArray> indirectExportEntries(exportEntry);
1448 size_t indirectExportEntriesLen = indirectExportEntries->GetLength();
1449 for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) {
1450 ee.Update(indirectExportEntries->Get(idx));
1451 // a. If SameValue(exportName, e.[[ExportName]]) is true, then
1452 if (JSTaggedValue::SameValue(exportName.GetTaggedValue(), ee->GetExportName())) {
1453 // i. Assert: module imports a specific binding for this export.
1454 // ii. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
1455 moduleRequest.Update(ee->GetModuleRequest());
1456 JSMutableHandle<SourceTextModule> requestedModule(thread, thread->GlobalConstants()->GetUndefined());
1457 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
1458 if (moduleRecordName.IsUndefined()) {
1459 requestedModule.Update(SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest));
1460 } else {
1461 ASSERT(moduleRecordName.IsString());
1462 requestedModule.Update(
1463 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest));
1464 }
1465 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1466 // iii. Return importedModule.ResolveExport(e.[[ImportName]], resolveVector).
1467 importName.Update(ee->GetImportName());
1468 return SourceTextModule::ResolveExport(thread, requestedModule, importName, resolveVector);
1469 }
1470 }
1471 return thread->GlobalConstants()->GetHandledUndefined();
1472 }
1473
CheckResolvedBinding(JSThread * thread,const JSHandle<SourceTextModule> & module)1474 void SourceTextModule::CheckResolvedBinding(JSThread *thread, const JSHandle<SourceTextModule> &module)
1475 {
1476 auto globalConstants = thread->GlobalConstants();
1477 // 1. For each ExportEntry Record e in module.[[IndirectExportEntries]], do
1478 JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries();
1479 if (indirectExportEntriesTv.IsUndefined()) {
1480 return;
1481 }
1482
1483 JSMutableHandle<IndirectExportEntry> ee(thread, globalConstants->GetUndefined());
1484 JSMutableHandle<JSTaggedValue> exportName(thread, globalConstants->GetUndefined());
1485 JSHandle<TaggedArray> indirectExportEntries(thread, indirectExportEntriesTv);
1486 size_t indirectExportEntriesLen = indirectExportEntries->GetLength();
1487 for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) {
1488 ee.Update(indirectExportEntries->Get(idx));
1489 // a. Let resolution be ? module.ResolveExport(e.[[ExportName]], « »).
1490 exportName.Update(ee->GetExportName());
1491 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector;
1492 JSHandle<JSTaggedValue> resolution =
1493 SourceTextModule::ResolveExport(thread, module, exportName, resolveVector);
1494 // b. If resolution is null or "ambiguous", throw a SyntaxError exception.
1495 if (resolution->IsNull() || resolution->IsString()) {
1496 CString msg = "the requested module '" +
1497 ConvertToString(ee->GetModuleRequest()) +
1498 "' does not provide an export named '" +
1499 ConvertToString(exportName.GetTaggedValue());
1500 if (!module->GetEcmaModuleRecordName().IsUndefined()) {
1501 msg += "' which exported by '" + ConvertToString(module->GetEcmaModuleRecordName()) + "'";
1502 } else {
1503 msg += "' which exported by '" + ConvertToString(module->GetEcmaModuleFilename()) + "'";
1504 }
1505 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str());
1506 }
1507 // c. Assert: resolution is a ResolvedBinding Record.
1508 ASSERT(resolution->IsResolvedBinding());
1509 }
1510 }
1511
CheckResolvedIndexBinding(JSThread * thread,const JSHandle<SourceTextModule> & module)1512 void SourceTextModule::CheckResolvedIndexBinding(JSThread *thread, const JSHandle<SourceTextModule> &module)
1513 {
1514 auto globalConstants = thread->GlobalConstants();
1515 // 1. For each ExportEntry Record e in module.[[IndirectExportEntries]], do
1516 JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries();
1517 if (indirectExportEntriesTv.IsUndefined()) {
1518 return;
1519 }
1520
1521 JSMutableHandle<IndirectExportEntry> ee(thread, globalConstants->GetUndefined());
1522 JSMutableHandle<JSTaggedValue> exportName(thread, globalConstants->GetUndefined());
1523 JSHandle<TaggedArray> indirectExportEntries(thread, indirectExportEntriesTv);
1524 size_t indirectExportEntriesLen = indirectExportEntries->GetLength();
1525 for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) {
1526 ee.Update(indirectExportEntries->Get(idx));
1527 // a. Let resolution be ? module.ResolveExport(e.[[ExportName]], « »).
1528 exportName.Update(ee->GetExportName());
1529 CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveVector;
1530 JSHandle<JSTaggedValue> resolution =
1531 SourceTextModule::ResolveExport(thread, module, exportName, resolveVector);
1532 // b. If resolution is null or "ambiguous", throw a SyntaxError exception.
1533 if (resolution->IsNull() || resolution->IsString()) {
1534 CString msg = "the requested module '" +
1535 ConvertToString(ee->GetModuleRequest()) +
1536 "' does not provide an export named '" +
1537 ConvertToString(exportName.GetTaggedValue());
1538 if (!module->GetEcmaModuleRecordName().IsUndefined()) {
1539 msg += "' which exported by '" + ConvertToString(module->GetEcmaModuleRecordName()) + "'";
1540 } else {
1541 msg += "' which exported by '" + ConvertToString(module->GetEcmaModuleFilename()) + "'";
1542 }
1543 THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str());
1544 }
1545 }
1546 }
1547
GetModuleName(JSTaggedValue currentModule)1548 JSTaggedValue SourceTextModule::GetModuleName(JSTaggedValue currentModule)
1549 {
1550 SourceTextModule *module = SourceTextModule::Cast(currentModule.GetTaggedObject());
1551 JSTaggedValue recordName = module->GetEcmaModuleRecordName();
1552 if (recordName.IsUndefined()) {
1553 return module->GetEcmaModuleFilename();
1554 }
1555 return recordName;
1556 }
1557
IsDynamicModule(LoadingTypes types)1558 bool SourceTextModule::IsDynamicModule(LoadingTypes types)
1559 {
1560 return types == LoadingTypes::DYNAMITC_MODULE;
1561 }
1562 } // namespace panda::ecmascript
1563