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