2021-09-14 20:51:16 +02:00
|
|
|
/*
|
2024-10-04 13:19:50 +02:00
|
|
|
* Copyright (c) 2021-2023, Andreas Kling <andreas@ladybird.org>
|
2022-01-18 19:29:17 +01:00
|
|
|
* Copyright (c) 2022, David Tuin <davidot@serenityos.org>
|
2021-09-14 20:51:16 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
2023-01-02 21:07:18 +01:00
|
|
|
#include <AK/Debug.h>
|
2022-01-18 19:29:17 +01:00
|
|
|
#include <AK/QuickSort.h>
|
2026-02-23 11:50:46 +01:00
|
|
|
#include <LibJS/Bytecode/Executable.h>
|
2023-06-24 16:07:15 +02:00
|
|
|
#include <LibJS/Bytecode/Interpreter.h>
|
2023-12-06 11:35:40 +01:00
|
|
|
#include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
|
2022-01-18 19:29:17 +01:00
|
|
|
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
2023-08-07 19:59:00 +02:00
|
|
|
#include <LibJS/Runtime/GlobalEnvironment.h>
|
2022-01-18 19:29:17 +01:00
|
|
|
#include <LibJS/Runtime/ModuleEnvironment.h>
|
2023-12-06 11:35:40 +01:00
|
|
|
#include <LibJS/Runtime/PromiseCapability.h>
|
2026-02-11 09:48:00 +01:00
|
|
|
#include <LibJS/Runtime/SharedFunctionInstanceData.h>
|
2026-02-23 11:50:46 +01:00
|
|
|
#include <LibJS/RustIntegration.h>
|
|
|
|
|
#include <LibJS/Script.h>
|
|
|
|
|
#include <LibJS/SourceCode.h>
|
2021-09-14 20:51:16 +02:00
|
|
|
#include <LibJS/SourceTextModule.h>
|
|
|
|
|
|
|
|
|
|
namespace JS {
|
|
|
|
|
|
2024-11-15 04:01:23 +13:00
|
|
|
GC_DEFINE_ALLOCATOR(SourceTextModule);
|
2023-11-19 09:45:05 +01:00
|
|
|
|
2026-02-23 11:50:46 +01:00
|
|
|
SourceTextModule::SourceTextModule(Realm& realm, StringView filename, Script::HostDefined* host_defined, bool has_top_level_await,
|
|
|
|
|
Vector<ModuleRequest> requested_modules, Vector<ImportEntry> import_entries,
|
|
|
|
|
Vector<ExportEntry> local_export_entries, Vector<ExportEntry> indirect_export_entries,
|
|
|
|
|
Vector<ExportEntry> star_export_entries, Optional<Utf16FlyString> default_export_binding_name,
|
|
|
|
|
Vector<Utf16FlyString> var_declared_names, Vector<LexicalBinding> lexical_bindings,
|
|
|
|
|
Vector<FunctionToInitialize> functions_to_initialize,
|
|
|
|
|
GC::Ptr<Bytecode::Executable> executable,
|
|
|
|
|
GC::Ptr<SharedFunctionInstanceData> tla_shared_data)
|
|
|
|
|
: CyclicModule(realm, filename, has_top_level_await, move(requested_modules), host_defined)
|
2026-03-27 23:45:15 +01:00
|
|
|
, m_execution_context(ExecutionContext::create(0, ReadonlySpan<Value> {}, 0))
|
2026-02-23 11:50:46 +01:00
|
|
|
, m_import_entries(move(import_entries))
|
|
|
|
|
, m_local_export_entries(move(local_export_entries))
|
|
|
|
|
, m_indirect_export_entries(move(indirect_export_entries))
|
|
|
|
|
, m_star_export_entries(move(star_export_entries))
|
|
|
|
|
, m_var_declared_names(move(var_declared_names))
|
|
|
|
|
, m_lexical_bindings(move(lexical_bindings))
|
|
|
|
|
, m_functions_to_initialize(move(functions_to_initialize))
|
|
|
|
|
, m_default_export_binding_name(move(default_export_binding_name))
|
|
|
|
|
, m_executable(executable)
|
|
|
|
|
, m_tla_shared_data(tla_shared_data)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 10:38:35 +02:00
|
|
|
SourceTextModule::~SourceTextModule() = default;
|
|
|
|
|
|
2022-09-05 14:31:25 +02:00
|
|
|
void SourceTextModule::visit_edges(Cell::Visitor& visitor)
|
|
|
|
|
{
|
|
|
|
|
Base::visit_edges(visitor);
|
|
|
|
|
visitor.visit(m_import_meta);
|
2023-12-13 10:24:30 +01:00
|
|
|
m_execution_context->visit_edges(visitor);
|
2026-02-11 09:48:00 +01:00
|
|
|
for (auto const& function : m_functions_to_initialize)
|
|
|
|
|
visitor.visit(function.shared_data);
|
2026-02-11 09:49:52 +01:00
|
|
|
visitor.visit(m_executable);
|
|
|
|
|
visitor.visit(m_tla_shared_data);
|
2022-09-05 14:31:25 +02:00
|
|
|
}
|
|
|
|
|
|
2026-03-17 15:47:58 -06:00
|
|
|
Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse_from_pre_parsed(FFI::ParsedProgram* parsed, NonnullRefPtr<SourceCode const> source_code, Realm& realm, Script::HostDefined* host_defined)
|
2026-02-27 23:44:44 +01:00
|
|
|
{
|
|
|
|
|
auto filename = source_code->filename();
|
|
|
|
|
auto rust_result = RustIntegration::compile_parsed_module(parsed, move(source_code), realm);
|
|
|
|
|
// Always from the Rust pipeline, so the Optional must have a value.
|
|
|
|
|
VERIFY(rust_result.has_value());
|
|
|
|
|
if (rust_result->is_error())
|
|
|
|
|
return rust_result->release_error();
|
|
|
|
|
auto& module_result = rust_result->value();
|
|
|
|
|
Vector<FunctionToInitialize> functions_to_initialize;
|
|
|
|
|
functions_to_initialize.ensure_capacity(module_result.functions_to_initialize.size());
|
|
|
|
|
for (auto& f : module_result.functions_to_initialize)
|
|
|
|
|
functions_to_initialize.append({ *f.shared_data, move(f.name) });
|
|
|
|
|
return realm.heap().allocate<SourceTextModule>(
|
|
|
|
|
realm, filename, host_defined, module_result.has_top_level_await,
|
|
|
|
|
move(module_result.requested_modules), move(module_result.import_entries),
|
|
|
|
|
move(module_result.local_export_entries), move(module_result.indirect_export_entries),
|
|
|
|
|
move(module_result.star_export_entries), move(module_result.default_export_binding_name),
|
|
|
|
|
move(module_result.var_declared_names), move(module_result.lexical_bindings),
|
|
|
|
|
move(functions_to_initialize),
|
|
|
|
|
module_result.executable.ptr(), module_result.tla_shared_data.ptr());
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
|
2024-11-15 04:01:23 +13:00
|
|
|
Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename, Script::HostDefined* host_defined)
|
2021-09-14 20:51:16 +02:00
|
|
|
{
|
2026-02-23 11:50:46 +01:00
|
|
|
auto rust_result = RustIntegration::compile_module(source_text, realm, filename);
|
2026-03-19 12:26:15 -05:00
|
|
|
if (!rust_result.has_value())
|
|
|
|
|
return Vector<ParserError> {};
|
|
|
|
|
if (rust_result->is_error())
|
|
|
|
|
return rust_result->release_error();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2026-03-19 12:26:15 -05:00
|
|
|
auto& module_result = rust_result->value();
|
|
|
|
|
Vector<FunctionToInitialize> functions_to_initialize;
|
|
|
|
|
functions_to_initialize.ensure_capacity(module_result.functions_to_initialize.size());
|
|
|
|
|
for (auto& f : module_result.functions_to_initialize)
|
|
|
|
|
functions_to_initialize.append({ *f.shared_data, move(f.name) });
|
2024-11-14 06:13:46 +13:00
|
|
|
return realm.heap().allocate<SourceTextModule>(
|
2026-03-19 12:26:15 -05:00
|
|
|
realm, filename, host_defined, module_result.has_top_level_await,
|
|
|
|
|
move(module_result.requested_modules), move(module_result.import_entries),
|
|
|
|
|
move(module_result.local_export_entries), move(module_result.indirect_export_entries),
|
|
|
|
|
move(module_result.star_export_entries), move(module_result.default_export_binding_name),
|
|
|
|
|
move(module_result.var_declared_names), move(module_result.lexical_bindings),
|
|
|
|
|
move(functions_to_initialize),
|
|
|
|
|
module_result.executable.ptr(), module_result.tla_shared_data.ptr());
|
2021-09-14 20:51:16 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 16.2.1.7.2.1 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
|
2025-08-02 19:27:29 -04:00
|
|
|
Vector<Utf16FlyString> SourceTextModule::get_exported_names(VM& vm, HashTable<Module const*>& export_star_set)
|
2021-09-14 20:51:16 +02:00
|
|
|
{
|
2022-01-18 19:29:17 +01:00
|
|
|
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] get_export_names of {}", filename());
|
2025-04-28 15:03:56 -04:00
|
|
|
|
|
|
|
|
// 1. Assert: module.[[Status]] is not NEW.
|
2023-12-02 13:02:52 +01:00
|
|
|
VERIFY(m_status != ModuleStatus::New);
|
|
|
|
|
|
|
|
|
|
// 2. If exportStarSet is not present, set exportStarSet to a new empty List.
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: This is done by Module.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 3. If exportStarSet contains module, then
|
2025-04-28 15:03:56 -04:00
|
|
|
if (export_star_set.contains(this)) {
|
2022-01-18 19:29:17 +01:00
|
|
|
// a. Assert: We've reached the starting point of an export * circularity.
|
|
|
|
|
// FIXME: How do we check that?
|
|
|
|
|
|
|
|
|
|
// b. Return a new empty List.
|
2025-04-28 15:03:56 -04:00
|
|
|
return {};
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 4. Append module to exportStarSet.
|
2025-04-28 15:03:56 -04:00
|
|
|
export_star_set.set(this);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 5. Let exportedNames be a new empty List.
|
2025-08-02 19:27:29 -04:00
|
|
|
Vector<Utf16FlyString> exported_names;
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 6. For each ExportEntry Record e of module.[[LocalExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_local_export_entries) {
|
2022-01-18 19:29:17 +01:00
|
|
|
// a. Assert: module provides the direct binding for this export.
|
|
|
|
|
// FIXME: How do we check that?
|
|
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// b. Assert: e.[[ExportName]] is not null.
|
2024-01-24 14:45:11 -05:00
|
|
|
VERIFY(entry.export_name.has_value());
|
2023-12-02 13:02:52 +01:00
|
|
|
|
|
|
|
|
// c. Append e.[[ExportName]] to exportedNames.
|
2025-08-06 11:12:58 -04:00
|
|
|
exported_names.empend(entry.export_name.value());
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 7. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_indirect_export_entries) {
|
2023-12-02 13:02:52 +01:00
|
|
|
// a. a. Assert: module imports a specific binding for this export.
|
2022-01-18 19:29:17 +01:00
|
|
|
// FIXME: How do we check that?
|
|
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// b. Assert: e.[[ExportName]] is not null.
|
2024-01-24 14:45:11 -05:00
|
|
|
VERIFY(entry.export_name.has_value());
|
2023-12-02 13:02:52 +01:00
|
|
|
|
|
|
|
|
// c. Append e.[[ExportName]] to exportedNames.
|
2025-08-06 11:12:58 -04:00
|
|
|
exported_names.empend(entry.export_name.value());
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 8. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_star_export_entries) {
|
2023-12-02 13:02:52 +01:00
|
|
|
// a. Assert: e.[[ModuleRequest]] is not null.
|
2023-12-02 13:16:45 +01:00
|
|
|
// b. Let requestedModule be GetImportedModule(module, e.[[ModuleRequest]]).
|
|
|
|
|
auto requested_module = get_imported_module(entry.module_request());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// c. Let starNames be requestedModule.GetExportedNames(exportStarSet).
|
|
|
|
|
auto star_names = requested_module->get_exported_names(vm, export_star_set);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// d. For each element n of starNames, do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& name : star_names) {
|
|
|
|
|
// i. If n is not "default", then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (name != "default"sv) {
|
2025-04-28 15:03:56 -04:00
|
|
|
// 1. If exportedNames does not contain n, then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (!exported_names.contains_slow(name)) {
|
|
|
|
|
// a. Append n to exportedNames.
|
|
|
|
|
exported_names.empend(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:02:52 +01:00
|
|
|
// 9. Return exportedNames.
|
2022-01-18 19:29:17 +01:00
|
|
|
return exported_names;
|
2021-09-14 20:51:16 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 16.2.1.7.3.1 InitializeEnvironment ( ), https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
|
2022-05-02 20:54:39 +02:00
|
|
|
ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
2021-09-14 20:51:16 +02:00
|
|
|
{
|
2022-01-18 19:29:17 +01:00
|
|
|
// 1. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_indirect_export_entries) {
|
|
|
|
|
// a. Assert: e.[[ExportName]] is not null.
|
|
|
|
|
VERIFY(entry.export_name.has_value());
|
|
|
|
|
|
|
|
|
|
// a. Let resolution be module.ResolveExport(e.[[ExportName]]).
|
2025-08-06 11:12:58 -04:00
|
|
|
auto resolution = resolve_export(vm, entry.export_name.value());
|
2025-04-28 15:03:56 -04:00
|
|
|
|
|
|
|
|
// b. If resolution is either null or AMBIGUOUS, throw a SyntaxError exception.
|
2022-01-18 19:29:17 +01:00
|
|
|
if (!resolution.is_valid())
|
2022-08-16 20:33:17 +01:00
|
|
|
return vm.throw_completion<SyntaxError>(ErrorType::InvalidOrAmbiguousExportEntry, entry.export_name);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// c. Assert: resolution is a ResolvedBinding Record.
|
|
|
|
|
VERIFY(resolution.is_valid());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. Assert: All named exports from module are resolvable.
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: We check all the indirect export entries above in step 1 and all the local named exports are resolvable by construction.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 3. Let realm be module.[[Realm]].
|
|
|
|
|
// 4. Assert: realm is not undefined.
|
2025-04-28 15:03:56 -04:00
|
|
|
auto& realm = this->realm();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
|
2025-04-28 15:03:56 -04:00
|
|
|
auto environment = vm.heap().allocate<ModuleEnvironment>(&realm.global_environment());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 6. Set module.[[Environment]] to env.
|
|
|
|
|
set_environment(environment);
|
|
|
|
|
|
|
|
|
|
// 7. For each ImportEntry Record in of module.[[ImportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& import_entry : m_import_entries) {
|
2023-12-02 13:16:45 +01:00
|
|
|
// a. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
|
|
|
|
|
auto imported_module = get_imported_module(import_entry.module_request());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// b. If in.[[ImportName]] is NAMESPACE-OBJECT, then
|
2024-01-24 14:45:11 -05:00
|
|
|
if (import_entry.is_namespace()) {
|
2025-04-28 15:03:56 -04:00
|
|
|
// i. Let namespace be GetModuleNamespace(importedModule).
|
|
|
|
|
auto namespace_ = imported_module->get_module_namespace(vm);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
|
2025-08-06 11:12:58 -04:00
|
|
|
MUST(environment->create_immutable_binding(vm, import_entry.local_name, true));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2022-12-14 13:26:10 +01:00
|
|
|
// iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace, normal).
|
2025-08-06 11:12:58 -04:00
|
|
|
MUST(environment->initialize_binding(vm, import_entry.local_name, namespace_, Environment::InitializeBindingHint::Normal));
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
2025-04-28 15:03:56 -04:00
|
|
|
// c. Else,
|
2022-01-18 19:29:17 +01:00
|
|
|
else {
|
2025-08-06 11:12:58 -04:00
|
|
|
auto const& import_name = import_entry.import_name.value();
|
2025-08-02 19:27:29 -04:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// i. Let resolution be importedModule.ResolveExport(in.[[ImportName]]).
|
2025-08-02 19:27:29 -04:00
|
|
|
auto resolution = imported_module->resolve_export(vm, import_name);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// ii. If resolution is either null or AMBIGUOUS, throw a SyntaxError exception.
|
2022-01-18 19:29:17 +01:00
|
|
|
if (!resolution.is_valid())
|
2025-08-02 19:27:29 -04:00
|
|
|
return vm.throw_completion<SyntaxError>(ErrorType::InvalidOrAmbiguousExportEntry, import_name);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// iii. If resolution.[[BindingName]] is NAMESPACE, then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (resolution.is_namespace()) {
|
2025-04-28 15:03:56 -04:00
|
|
|
// 1. Let namespace be GetModuleNamespace(resolution.[[Module]]).
|
|
|
|
|
auto namespace_ = resolution.module->get_module_namespace(vm);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
|
2025-08-06 11:12:58 -04:00
|
|
|
MUST(environment->create_immutable_binding(vm, import_entry.local_name, true));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2022-12-14 13:26:10 +01:00
|
|
|
// 3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace, normal).
|
2025-08-06 11:12:58 -04:00
|
|
|
MUST(environment->initialize_binding(vm, import_entry.local_name, namespace_, Environment::InitializeBindingHint::Normal));
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
// iv. Else,
|
|
|
|
|
else {
|
2022-05-02 20:54:39 +02:00
|
|
|
// 1. Perform env.CreateImportBinding(in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
|
2025-08-06 11:12:58 -04:00
|
|
|
MUST(environment->create_import_binding(import_entry.local_name, resolution.module, resolution.export_name));
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 8. Let moduleContext be a new ECMAScript code execution context.
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: this has already been created during the construction of this object.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 9. Set the Function of moduleContext to null.
|
|
|
|
|
|
|
|
|
|
// 10. Assert: module.[[Realm]] is not undefined.
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: This must be true because we use a reference.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 11. Set the Realm of moduleContext to module.[[Realm]].
|
2025-04-28 15:03:56 -04:00
|
|
|
m_execution_context->realm = &this->realm();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 12. Set the ScriptOrModule of moduleContext to module.
|
2026-03-11 20:35:43 +00:00
|
|
|
m_execution_context->script_or_module = GC::Ref<Module>(*this);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
|
2023-11-27 16:45:45 +01:00
|
|
|
m_execution_context->variable_environment = environment;
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 14. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
|
2023-11-27 16:45:45 +01:00
|
|
|
m_execution_context->lexical_environment = environment;
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 15. Set the PrivateEnvironment of moduleContext to null.
|
|
|
|
|
|
|
|
|
|
// 16. Set module.[[Context]] to moduleContext.
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: We're already working on that one.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 17. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
|
2023-11-27 16:45:45 +01:00
|
|
|
TRY(vm.push_execution_context(*m_execution_context, {}));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 18. Let code be module.[[ECMAScriptCode]].
|
|
|
|
|
|
|
|
|
|
// 19. Let varDeclarations be the VarScopedDeclarations of code.
|
|
|
|
|
// 20. Let declaredVarNames be a new empty List.
|
2025-08-02 19:27:29 -04:00
|
|
|
Vector<Utf16FlyString> declared_var_names;
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 21. For each element d of varDeclarations, do
|
|
|
|
|
// a. For each element dn of the BoundNames of d, do
|
2026-02-11 09:48:00 +01:00
|
|
|
for (auto const& name : m_var_declared_names) {
|
2022-01-18 19:29:17 +01:00
|
|
|
// i. If dn is not an element of declaredVarNames, then
|
|
|
|
|
if (!declared_var_names.contains_slow(name)) {
|
|
|
|
|
// 1. Perform ! env.CreateMutableBinding(dn, false).
|
2022-08-21 15:12:43 +01:00
|
|
|
MUST(environment->create_mutable_binding(vm, name, false));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2022-12-14 13:26:10 +01:00
|
|
|
// 2. Perform ! env.InitializeBinding(dn, undefined, normal).
|
|
|
|
|
MUST(environment->initialize_binding(vm, name, js_undefined(), Environment::InitializeBindingHint::Normal));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 3. Append dn to declaredVarNames.
|
|
|
|
|
declared_var_names.empend(name);
|
|
|
|
|
}
|
2026-02-11 09:48:00 +01:00
|
|
|
}
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 22. Let lexDeclarations be the LexicallyScopedDeclarations of code.
|
|
|
|
|
// 23. Let privateEnv be null.
|
|
|
|
|
PrivateEnvironment* private_environment = nullptr;
|
|
|
|
|
|
|
|
|
|
// 24. For each element d of lexDeclarations, do
|
2026-02-11 09:48:00 +01:00
|
|
|
for (auto const& binding : m_lexical_bindings) {
|
2022-01-18 19:29:17 +01:00
|
|
|
// a. For each element dn of the BoundNames of d, do
|
2026-02-11 09:48:00 +01:00
|
|
|
// i. If IsConstantDeclaration of d is true, then
|
|
|
|
|
if (binding.is_constant) {
|
|
|
|
|
// 1. Perform ! env.CreateImmutableBinding(dn, true).
|
|
|
|
|
MUST(environment->create_immutable_binding(vm, binding.name, true));
|
|
|
|
|
}
|
|
|
|
|
// ii. Else,
|
|
|
|
|
else {
|
|
|
|
|
// 1. Perform ! env.CreateMutableBinding(dn, false).
|
|
|
|
|
MUST(environment->create_mutable_binding(vm, binding.name, false));
|
|
|
|
|
}
|
2025-08-02 19:27:29 -04:00
|
|
|
|
2026-02-11 09:48:00 +01:00
|
|
|
// iii. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
|
|
|
|
|
if (binding.function_index >= 0) {
|
|
|
|
|
auto const& function_to_initialize = m_functions_to_initialize[binding.function_index];
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2026-02-11 09:48:00 +01:00
|
|
|
// 1. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
|
|
|
|
|
auto function = ECMAScriptFunctionObject::create_from_function_data(
|
|
|
|
|
realm,
|
|
|
|
|
function_to_initialize.shared_data,
|
|
|
|
|
environment,
|
|
|
|
|
private_environment);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2026-02-11 09:48:00 +01:00
|
|
|
// 2. Perform ! env.InitializeBinding(dn, fo, normal).
|
|
|
|
|
MUST(environment->initialize_binding(vm, binding.name, function, Environment::InitializeBindingHint::Normal));
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: The default export name is also part of the local lexical declarations but instead of making that a special
|
|
|
|
|
// case in the parser we just check it here. This is only needed for things which are not declarations. For more
|
|
|
|
|
// info check Parser::parse_export_statement. Furthermore, that declaration is not constant. so we take 24.a.ii.
|
2026-02-11 09:48:00 +01:00
|
|
|
if (m_default_export_binding_name.has_value())
|
|
|
|
|
MUST(environment->create_mutable_binding(vm, *m_default_export_binding_name, false));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 25. Remove moduleContext from the execution context stack.
|
|
|
|
|
vm.pop_execution_context();
|
|
|
|
|
|
2022-05-02 20:54:39 +02:00
|
|
|
// 26. Return unused.
|
|
|
|
|
return {};
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 16.2.1.7.2.2 ResolveExport ( exportName [ , resolveSet ] ), https://tc39.es/ecma262/#sec-resolveexport
|
2025-08-02 19:27:29 -04:00
|
|
|
ResolvedBinding SourceTextModule::resolve_export(VM& vm, Utf16FlyString const& export_name, Vector<ResolvedBinding> resolve_set)
|
2022-01-18 19:29:17 +01:00
|
|
|
{
|
2025-04-28 15:03:56 -04:00
|
|
|
// 1. Assert: module.[[Status]] is not NEW.
|
2023-12-02 13:08:31 +01:00
|
|
|
VERIFY(m_status != ModuleStatus::New);
|
|
|
|
|
|
|
|
|
|
// 2. If resolveSet is not present, set resolveSet to a new empty List.
|
2025-04-28 15:03:56 -04:00
|
|
|
// NOTE: This is done by the default argument.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// 3. For each Record { [[Module]], [[ExportName]] } r of resolveSet, do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& [type, module, exported_name] : resolve_set) {
|
|
|
|
|
// a. If module and r.[[Module]] are the same Module Record and exportName is r.[[ExportName]], then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (module == this && exported_name == export_name) {
|
|
|
|
|
// i. Assert: This is a circular import request.
|
|
|
|
|
|
|
|
|
|
// ii. Return null.
|
|
|
|
|
return ResolvedBinding::null();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// 4. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet.
|
2022-01-18 19:29:17 +01:00
|
|
|
resolve_set.append({ ResolvedBinding::Type::BindingName, this, export_name });
|
|
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// 5. For each ExportEntry Record e of module.[[LocalExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_local_export_entries) {
|
|
|
|
|
// a. If e.[[ExportName]] is exportName, then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (export_name != entry.export_name)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// i. Assert: module provides the direct binding for this export.
|
|
|
|
|
// FIXME: What does this mean?
|
|
|
|
|
|
|
|
|
|
// ii. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }.
|
|
|
|
|
return ResolvedBinding {
|
|
|
|
|
ResolvedBinding::Type::BindingName,
|
|
|
|
|
this,
|
2025-08-06 11:12:58 -04:00
|
|
|
entry.local_or_import_name.value(),
|
2022-01-18 19:29:17 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_indirect_export_entries) {
|
|
|
|
|
// a. If e.[[ExportName]] is exportName, then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (export_name != entry.export_name)
|
|
|
|
|
continue;
|
|
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// i. Assert: e.[[ModuleRequest]] is not null.
|
2023-12-02 13:16:45 +01:00
|
|
|
// ii. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
|
|
|
|
|
auto imported_module = get_imported_module(entry.module_request());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// iii. If e.[[ImportName]] is all, then
|
2022-11-23 12:16:51 +01:00
|
|
|
if (entry.kind == ExportEntry::Kind::ModuleRequestAll) {
|
2022-01-18 19:29:17 +01:00
|
|
|
// 1. Assert: module does not provide the direct binding for this export.
|
|
|
|
|
// FIXME: What does this mean? / How do we check this
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: NAMESPACE }.
|
2022-01-18 19:29:17 +01:00
|
|
|
return ResolvedBinding {
|
|
|
|
|
ResolvedBinding::Type::Namespace,
|
|
|
|
|
imported_module.ptr(),
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
}
|
2023-12-02 13:08:31 +01:00
|
|
|
// iv. Else,
|
2022-01-18 19:29:17 +01:00
|
|
|
else {
|
|
|
|
|
// 1. Assert: module imports a specific binding for this export.
|
|
|
|
|
// FIXME: What does this mean? / How do we check this
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 2. Return importedModule.ResolveExport(e.[[ImportName]], resolveSet).
|
2025-08-06 11:12:58 -04:00
|
|
|
return imported_module->resolve_export(vm, entry.local_or_import_name.value(), resolve_set);
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 7. If exportName is "default", then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (export_name == "default"sv) {
|
|
|
|
|
// a. Assert: A default export was not explicitly defined by this module.
|
|
|
|
|
// FIXME: What does this mean? / How do we check this
|
|
|
|
|
|
|
|
|
|
// b. Return null.
|
|
|
|
|
return ResolvedBinding::null();
|
2025-04-28 15:03:56 -04:00
|
|
|
|
2022-01-18 19:29:17 +01:00
|
|
|
// c. NOTE: A default export cannot be provided by an export * from "mod" declaration.
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// 8. Let starResolution be null.
|
2025-04-28 15:03:56 -04:00
|
|
|
auto star_resolution = ResolvedBinding::null();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// 9. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
2025-04-28 15:03:56 -04:00
|
|
|
for (auto const& entry : m_star_export_entries) {
|
2023-12-02 13:08:31 +01:00
|
|
|
// a. Assert: e.[[ModuleRequest]] is not null.
|
2023-12-02 13:16:45 +01:00
|
|
|
// b. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
|
|
|
|
|
auto imported_module = get_imported_module(entry.module_request());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// c. Let resolution be importedModule.ResolveExport(exportName, resolveSet).
|
|
|
|
|
auto resolution = imported_module->resolve_export(vm, export_name, resolve_set);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// d. If resolution is AMBIGUOUS, return AMBIGUOUS.
|
2022-01-18 19:29:17 +01:00
|
|
|
if (resolution.is_ambiguous())
|
|
|
|
|
return ResolvedBinding::ambiguous();
|
|
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// e. If resolution is not null, then
|
2022-01-18 19:29:17 +01:00
|
|
|
if (resolution.type == ResolvedBinding::Null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// i. Assert: resolution is a ResolvedBinding Record.
|
|
|
|
|
VERIFY(resolution.is_valid());
|
|
|
|
|
|
|
|
|
|
// ii. If starResolution is null, set starResolution to resolution.
|
|
|
|
|
if (star_resolution.type == ResolvedBinding::Null) {
|
|
|
|
|
star_resolution = resolution;
|
|
|
|
|
}
|
|
|
|
|
// iii. Else,
|
|
|
|
|
else {
|
2025-12-02 11:54:23 -05:00
|
|
|
// 1. Assert: There is more than one * export that includes the requested name.
|
2022-01-18 19:29:17 +01:00
|
|
|
// FIXME: Assert this
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return AMBIGUOUS.
|
2022-01-18 19:29:17 +01:00
|
|
|
if (resolution.module != star_resolution.module)
|
|
|
|
|
return ResolvedBinding::ambiguous();
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 3. If resolution.[[BindingName]] is not starResolution.[[BindingName]] and either resolution.[[BindingName]]
|
|
|
|
|
// or starResolution.[[BindingName]] is NAMESPACE, return AMBIGUOUS.
|
2022-01-18 19:29:17 +01:00
|
|
|
if (resolution.is_namespace() != star_resolution.is_namespace())
|
|
|
|
|
return ResolvedBinding::ambiguous();
|
|
|
|
|
|
2025-04-28 15:03:56 -04:00
|
|
|
// 4. If resolution.[[BindingName]] is a String, starResolution.[[BindingName]] is a String, and
|
|
|
|
|
// resolution.[[BindingName]] is not starResolution.[[BindingName]], return ambiguous.
|
|
|
|
|
// NOTE: We know from the previous step that either both are namespaces or both are string, so we can check just one.
|
|
|
|
|
if (!resolution.is_namespace() && resolution.export_name != star_resolution.export_name)
|
2022-01-18 19:29:17 +01:00
|
|
|
return ResolvedBinding::ambiguous();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 13:08:31 +01:00
|
|
|
// 10. Return starResolution.
|
2022-01-18 19:29:17 +01:00
|
|
|
return star_resolution;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 16.2.1.6.5 ExecuteModule ( [ capability ] ), https://tc39.es/ecma262/#sec-source-text-module-record-execute-module
|
2025-01-16 16:51:26 -05:00
|
|
|
// 9.1.1.1.2 ExecuteModule ( [ capability ] ), https://tc39.es/proposal-explicit-resource-management/#sec-source-text-module-record-execute-module
|
2024-11-15 04:01:23 +13:00
|
|
|
ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GC::Ptr<PromiseCapability> capability)
|
2022-01-18 19:29:17 +01:00
|
|
|
{
|
2022-10-02 12:11:30 +01:00
|
|
|
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] SourceTextModule::execute_module({}, PromiseCapability @ {})", filename(), capability.ptr());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2026-03-19 12:26:15 -05:00
|
|
|
VERIFY(m_has_top_level_await || m_executable);
|
2025-04-22 21:49:41 +02:00
|
|
|
|
2026-01-18 23:17:10 +01:00
|
|
|
u32 registers_and_locals_count = 0;
|
2026-03-27 23:45:15 +01:00
|
|
|
ReadonlySpan<Value> constants;
|
2026-02-11 09:49:52 +01:00
|
|
|
if (m_executable) {
|
|
|
|
|
registers_and_locals_count = m_executable->registers_and_locals_count;
|
2026-03-27 23:45:15 +01:00
|
|
|
constants = m_executable->constants;
|
2025-04-22 21:49:41 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-18 19:29:17 +01:00
|
|
|
// 1. Let moduleContext be a new ECMAScript code execution context.
|
2026-03-04 10:32:01 +01:00
|
|
|
auto& stack = vm.interpreter_stack();
|
|
|
|
|
auto* stack_mark = stack.top();
|
2026-03-27 23:45:15 +01:00
|
|
|
auto* module_context = stack.allocate(registers_and_locals_count, constants, 0);
|
2026-03-04 10:32:01 +01:00
|
|
|
if (!module_context) [[unlikely]]
|
|
|
|
|
return vm.throw_completion<InternalError>(ErrorType::CallStackSizeExceeded);
|
|
|
|
|
ScopeGuard deallocate_guard = [&stack, stack_mark] { stack.deallocate(stack_mark); };
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 2. Set the Function of moduleContext to null.
|
|
|
|
|
|
|
|
|
|
// 3. Set the Realm of moduleContext to module.[[Realm]].
|
2023-11-27 16:45:45 +01:00
|
|
|
module_context->realm = &realm();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 4. Set the ScriptOrModule of moduleContext to module.
|
2026-03-11 20:35:43 +00:00
|
|
|
module_context->script_or_module = GC::Ref<Module>(*this);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 5. Assert: module has been linked and declarations in its module environment have been instantiated.
|
2023-12-02 12:38:21 +01:00
|
|
|
VERIFY(m_status != ModuleStatus::New);
|
|
|
|
|
VERIFY(m_status != ModuleStatus::Unlinked);
|
|
|
|
|
VERIFY(m_status != ModuleStatus::Linking);
|
|
|
|
|
VERIFY(environment());
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
|
2023-11-27 16:45:45 +01:00
|
|
|
module_context->variable_environment = environment();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 7. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
|
2023-11-27 16:45:45 +01:00
|
|
|
module_context->lexical_environment = environment();
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 8. Suspend the currently running execution context.
|
2025-01-01 22:51:52 +13:00
|
|
|
// NOTE: Done by the push of execution context in steps below.
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// 9. If module.[[HasTLA]] is false, then
|
|
|
|
|
if (!m_has_top_level_await) {
|
|
|
|
|
// a. Assert: capability is not present.
|
2022-10-02 12:11:30 +01:00
|
|
|
VERIFY(capability == nullptr);
|
2025-01-16 16:51:26 -05:00
|
|
|
|
2022-01-18 19:29:17 +01:00
|
|
|
// b. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
|
2023-11-27 16:45:45 +01:00
|
|
|
TRY(vm.push_execution_context(*module_context, {}));
|
2022-01-18 19:29:17 +01:00
|
|
|
|
|
|
|
|
// c. Let result be the result of evaluating module.[[ECMAScriptCode]].
|
2023-06-24 16:07:15 +02:00
|
|
|
Completion result;
|
|
|
|
|
|
2026-02-11 09:49:52 +01:00
|
|
|
auto result_or_error = vm.bytecode_interpreter().run_executable(*module_context, *m_executable, {});
|
2025-10-30 10:27:47 +01:00
|
|
|
if (result_or_error.is_error()) {
|
|
|
|
|
result = result_or_error.release_error();
|
2025-04-22 21:49:41 +02:00
|
|
|
} else {
|
2025-10-30 10:27:47 +01:00
|
|
|
result = result_or_error.value().is_special_empty_value() ? js_undefined() : result_or_error.release_value();
|
2023-06-24 16:07:15 +02:00
|
|
|
}
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2022-12-20 22:09:57 +01:00
|
|
|
// d. Let env be moduleContext's LexicalEnvironment.
|
2025-01-21 09:12:05 -05:00
|
|
|
auto& env = as<DeclarativeEnvironment>(*module_context->lexical_environment);
|
2022-12-20 22:09:57 +01:00
|
|
|
|
2025-01-16 16:51:26 -05:00
|
|
|
// e. Set result to Completion(DisposeResources(env.[[DisposeCapability]], result)).
|
|
|
|
|
result = dispose_resources(vm, env.dispose_capability(), result);
|
2022-12-20 22:09:57 +01:00
|
|
|
|
|
|
|
|
// f. Suspend moduleContext and remove it from the execution context stack.
|
2022-01-18 19:29:17 +01:00
|
|
|
vm.pop_execution_context();
|
|
|
|
|
|
2022-12-20 22:09:57 +01:00
|
|
|
// g. Resume the context that is now on the top of the execution context stack as the running execution context.
|
2022-01-18 19:29:17 +01:00
|
|
|
// FIXME: We don't have resume yet.
|
|
|
|
|
|
2022-12-20 22:09:57 +01:00
|
|
|
// h. If result is an abrupt completion, then
|
2022-05-02 20:54:39 +02:00
|
|
|
if (result.is_error()) {
|
|
|
|
|
// i. Return ? result.
|
2023-06-24 16:07:15 +02:00
|
|
|
return result.release_error();
|
2022-05-02 20:54:39 +02:00
|
|
|
}
|
2022-01-18 19:29:17 +01:00
|
|
|
}
|
|
|
|
|
// 10. Else,
|
2022-05-02 20:54:39 +02:00
|
|
|
else {
|
|
|
|
|
// a. Assert: capability is a PromiseCapability Record.
|
2022-10-02 12:11:30 +01:00
|
|
|
VERIFY(capability != nullptr);
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2022-05-02 20:54:39 +02:00
|
|
|
// b. Perform AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext).
|
2023-12-06 11:35:40 +01:00
|
|
|
|
|
|
|
|
// AD-HOC: We implement asynchronous execution via synthetic generator functions,
|
|
|
|
|
// so we fake "AsyncBlockStart" here by creating an async function to wrap
|
|
|
|
|
// the top-level module code.
|
|
|
|
|
// FIXME: Improve this situation, so we can match the spec better.
|
|
|
|
|
|
2025-01-01 22:51:52 +13:00
|
|
|
// NOTE: Like AsyncBlockStart, we need to push/pop the moduleContext around the function construction to ensure that
|
|
|
|
|
// the async execution context captures the module execution context.
|
2024-11-15 15:11:48 +00:00
|
|
|
vm.push_execution_context(*module_context);
|
|
|
|
|
|
2026-02-11 09:49:52 +01:00
|
|
|
auto module_wrapper_function = ECMAScriptFunctionObject::create_from_function_data(
|
|
|
|
|
realm(), *m_tla_shared_data, environment(), nullptr);
|
2023-12-06 11:35:40 +01:00
|
|
|
|
|
|
|
|
vm.pop_execution_context();
|
|
|
|
|
|
2024-11-15 15:11:48 +00:00
|
|
|
auto result = call(vm, Value { module_wrapper_function }, js_undefined(), ReadonlySpan<Value> {});
|
|
|
|
|
|
2023-12-06 11:35:40 +01:00
|
|
|
// AD-HOC: This is basically analogous to what AsyncBlockStart would do.
|
|
|
|
|
if (result.is_throw_completion()) {
|
2025-04-04 18:11:45 +02:00
|
|
|
MUST(call(vm, *capability->reject(), js_undefined(), result.throw_completion().value()));
|
2023-12-06 11:35:40 +01:00
|
|
|
} else {
|
|
|
|
|
MUST(call(vm, *capability->resolve(), js_undefined(), result.value()));
|
|
|
|
|
}
|
2022-05-02 20:54:39 +02:00
|
|
|
}
|
2022-01-18 19:29:17 +01:00
|
|
|
|
2022-05-02 20:54:39 +02:00
|
|
|
// 11. Return unused.
|
|
|
|
|
return {};
|
2021-09-14 20:51:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|