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> ¤tModule,
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> ¤tModule,
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> ¤tModule,
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