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