• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &currentModule,
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> &currentModule,
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> &currentModule,
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