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