mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:08:13 +00:00
LibJS: Make Script and Module GC-allocated
This ensures that code currently in any active or saved execution stack always stays alive.
This commit is contained in:
parent
cb15132146
commit
00c8f07192
18 changed files with 145 additions and 89 deletions
|
@ -3262,10 +3262,10 @@ Completion MetaProperty::execute(Interpreter& interpreter) const
|
||||||
auto script_or_module = interpreter.vm().get_active_script_or_module();
|
auto script_or_module = interpreter.vm().get_active_script_or_module();
|
||||||
|
|
||||||
// 2. Assert: module is a Source Text Module Record.
|
// 2. Assert: module is a Source Text Module Record.
|
||||||
VERIFY(script_or_module.has<WeakPtr<Module>>());
|
VERIFY(script_or_module.has<NonnullGCPtr<Module>>());
|
||||||
VERIFY(script_or_module.get<WeakPtr<Module>>());
|
VERIFY(script_or_module.get<NonnullGCPtr<Module>>());
|
||||||
VERIFY(is<SourceTextModule>(*script_or_module.get<WeakPtr<Module>>()));
|
VERIFY(is<SourceTextModule>(*script_or_module.get<NonnullGCPtr<Module>>()));
|
||||||
auto& module = static_cast<SourceTextModule&>(*script_or_module.get<WeakPtr<Module>>());
|
auto& module = static_cast<SourceTextModule&>(*script_or_module.get<NonnullGCPtr<Module>>());
|
||||||
|
|
||||||
// 3. Let importMeta be module.[[ImportMeta]].
|
// 3. Let importMeta be module.[[ImportMeta]].
|
||||||
auto* import_meta = module.import_meta();
|
auto* import_meta = module.import_meta();
|
||||||
|
|
|
@ -17,6 +17,14 @@ CyclicModule::CyclicModule(Realm& realm, StringView filename, bool has_top_level
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CyclicModule::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_cycle_root);
|
||||||
|
for (auto* module : m_async_parent_modules)
|
||||||
|
visitor.visit(module);
|
||||||
|
}
|
||||||
|
|
||||||
// 16.2.1.5.1 Link ( ), https://tc39.es/ecma262/#sec-moduledeclarationlinking
|
// 16.2.1.5.1 Link ( ), https://tc39.es/ecma262/#sec-moduledeclarationlinking
|
||||||
ThrowCompletionOr<void> CyclicModule::link(VM& vm)
|
ThrowCompletionOr<void> CyclicModule::link(VM& vm)
|
||||||
{
|
{
|
||||||
|
@ -106,7 +114,7 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_linking(VM& vm, Vector<Module*
|
||||||
ModuleRequest required { required_string };
|
ModuleRequest required { required_string };
|
||||||
|
|
||||||
// a. Let requiredModule be ? HostResolveImportedModule(module, required).
|
// a. Let requiredModule be ? HostResolveImportedModule(module, required).
|
||||||
auto required_module = TRY(vm.host_resolve_imported_module(this->make_weak_ptr(), required));
|
auto required_module = TRY(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), required));
|
||||||
|
|
||||||
// b. Set index to ? InnerModuleLinking(requiredModule, stack, index).
|
// b. Set index to ? InnerModuleLinking(requiredModule, stack, index).
|
||||||
index = TRY(required_module->inner_module_linking(vm, stack, index));
|
index = TRY(required_module->inner_module_linking(vm, stack, index));
|
||||||
|
@ -305,7 +313,7 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_evaluation(VM& vm, Vector<Modu
|
||||||
for (auto& required : m_requested_modules) {
|
for (auto& required : m_requested_modules) {
|
||||||
|
|
||||||
// a. Let requiredModule be ! HostResolveImportedModule(module, required).
|
// a. Let requiredModule be ! HostResolveImportedModule(module, required).
|
||||||
auto* required_module = MUST(vm.host_resolve_imported_module(this->make_weak_ptr(), required)).ptr();
|
auto* required_module = MUST(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), required)).ptr();
|
||||||
// b. NOTE: Link must be completed successfully prior to invoking this method, so every requested module is guaranteed to resolve successfully.
|
// b. NOTE: Link must be completed successfully prior to invoking this method, so every requested module is guaranteed to resolve successfully.
|
||||||
|
|
||||||
// c. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
|
// c. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
|
||||||
|
|
|
@ -25,6 +25,8 @@ enum class ModuleStatus {
|
||||||
|
|
||||||
// 16.2.1.5 Cyclic Module Records, https://tc39.es/ecma262/#sec-cyclic-module-records
|
// 16.2.1.5 Cyclic Module Records, https://tc39.es/ecma262/#sec-cyclic-module-records
|
||||||
class CyclicModule : public Module {
|
class CyclicModule : public Module {
|
||||||
|
JS_CELL(CyclicModule, Module);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Note: Do not call these methods directly unless you are HostResolveImportedModule.
|
// Note: Do not call these methods directly unless you are HostResolveImportedModule.
|
||||||
// Badges cannot be used because other hosts must be able to call this (and it is called recursively)
|
// Badges cannot be used because other hosts must be able to call this (and it is called recursively)
|
||||||
|
@ -34,6 +36,8 @@ public:
|
||||||
protected:
|
protected:
|
||||||
CyclicModule(Realm& realm, StringView filename, bool has_top_level_await, Vector<ModuleRequest> requested_modules);
|
CyclicModule(Realm& realm, StringView filename, bool has_top_level_await, Vector<ModuleRequest> requested_modules);
|
||||||
|
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
virtual ThrowCompletionOr<u32> inner_module_linking(VM& vm, Vector<Module*>& stack, u32 index) override;
|
virtual ThrowCompletionOr<u32> inner_module_linking(VM& vm, Vector<Module*>& stack, u32 index) override;
|
||||||
virtual ThrowCompletionOr<u32> inner_module_evaluation(VM& vm, Vector<Module*>& stack, u32 index) override;
|
virtual ThrowCompletionOr<u32> inner_module_evaluation(VM& vm, Vector<Module*>& stack, u32 index) override;
|
||||||
|
|
||||||
|
@ -50,7 +54,7 @@ protected:
|
||||||
Optional<u32> m_dfs_index; // [[DFSIndex]]
|
Optional<u32> m_dfs_index; // [[DFSIndex]]
|
||||||
Optional<u32> m_dfs_ancestor_index; // [[DFSAncestorIndex]]
|
Optional<u32> m_dfs_ancestor_index; // [[DFSAncestorIndex]]
|
||||||
Vector<ModuleRequest> m_requested_modules; // [[RequestedModules]]
|
Vector<ModuleRequest> m_requested_modules; // [[RequestedModules]]
|
||||||
CyclicModule* m_cycle_root; // [[CycleRoot]]
|
CyclicModule* m_cycle_root { nullptr }; // [[CycleRoot]]
|
||||||
bool m_has_top_level_await { false }; // [[HasTLA]]
|
bool m_has_top_level_await { false }; // [[HasTLA]]
|
||||||
bool m_async_evaluation { false }; // [[AsyncEvaluation]]
|
bool m_async_evaluation { false }; // [[AsyncEvaluation]]
|
||||||
Optional<PromiseCapability> m_top_level_capability; // [[TopLevelCapability]]
|
Optional<PromiseCapability> m_top_level_capability; // [[TopLevelCapability]]
|
||||||
|
|
|
@ -54,7 +54,7 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record)
|
||||||
script_context.realm = &script_record.realm();
|
script_context.realm = &script_record.realm();
|
||||||
|
|
||||||
// 5. Set the ScriptOrModule of scriptContext to scriptRecord.
|
// 5. Set the ScriptOrModule of scriptContext to scriptRecord.
|
||||||
script_context.script_or_module = script_record.make_weak_ptr();
|
script_context.script_or_module = NonnullGCPtr<Script>(script_record);
|
||||||
|
|
||||||
// 6. Set the VariableEnvironment of scriptContext to globalEnv.
|
// 6. Set the VariableEnvironment of scriptContext to globalEnv.
|
||||||
script_context.variable_environment = &global_environment;
|
script_context.variable_environment = &global_environment;
|
||||||
|
|
|
@ -12,11 +12,21 @@
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
Module::Module(Realm& realm, String filename)
|
Module::Module(Realm& realm, String filename)
|
||||||
: m_realm(make_handle(&realm))
|
: m_realm(realm)
|
||||||
, m_filename(move(filename))
|
, m_filename(move(filename))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Module::~Module() = default;
|
||||||
|
|
||||||
|
void Module::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_realm);
|
||||||
|
visitor.visit(m_environment);
|
||||||
|
visitor.visit(m_namespace);
|
||||||
|
}
|
||||||
|
|
||||||
// 16.2.1.5.1.1 InnerModuleLinking ( module, stack, index ), https://tc39.es/ecma262/#sec-InnerModuleLinking
|
// 16.2.1.5.1.1 InnerModuleLinking ( module, stack, index ), https://tc39.es/ecma262/#sec-InnerModuleLinking
|
||||||
ThrowCompletionOr<u32> Module::inner_module_linking(VM& vm, Vector<Module*>&, u32 index)
|
ThrowCompletionOr<u32> Module::inner_module_linking(VM& vm, Vector<Module*>&, u32 index)
|
||||||
{
|
{
|
||||||
|
@ -54,7 +64,7 @@ ThrowCompletionOr<Object*> Module::get_module_namespace(VM& vm)
|
||||||
// FIXME: How do we check this without breaking encapsulation?
|
// FIXME: How do we check this without breaking encapsulation?
|
||||||
|
|
||||||
// 2. Let namespace be module.[[Namespace]].
|
// 2. Let namespace be module.[[Namespace]].
|
||||||
auto* namespace_ = m_namespace.is_null() ? nullptr : m_namespace.cell();
|
auto* namespace_ = m_namespace.ptr();
|
||||||
|
|
||||||
// 3. If namespace is empty, then
|
// 3. If namespace is empty, then
|
||||||
if (!namespace_) {
|
if (!namespace_) {
|
||||||
|
@ -76,7 +86,7 @@ ThrowCompletionOr<Object*> Module::get_module_namespace(VM& vm)
|
||||||
|
|
||||||
// d. Set namespace to ModuleNamespaceCreate(module, unambiguousNames).
|
// d. Set namespace to ModuleNamespaceCreate(module, unambiguousNames).
|
||||||
namespace_ = module_namespace_create(vm, unambiguous_names);
|
namespace_ = module_namespace_create(vm, unambiguous_names);
|
||||||
VERIFY(!m_namespace.is_null());
|
VERIFY(m_namespace);
|
||||||
// Note: This set the local variable 'namespace' and not the member variable which is done by ModuleNamespaceCreate
|
// Note: This set the local variable 'namespace' and not the member variable which is done by ModuleNamespaceCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +100,7 @@ Object* Module::module_namespace_create(VM& vm, Vector<FlyString> unambiguous_na
|
||||||
auto& realm = this->realm();
|
auto& realm = this->realm();
|
||||||
|
|
||||||
// 1. Assert: module.[[Namespace]] is empty.
|
// 1. Assert: module.[[Namespace]] is empty.
|
||||||
VERIFY(m_namespace.is_null());
|
VERIFY(!m_namespace);
|
||||||
|
|
||||||
// 2. Let internalSlotsList be the internal slots listed in Table 34.
|
// 2. Let internalSlotsList be the internal slots listed in Table 34.
|
||||||
// 3. Let M be MakeBasicObject(internalSlotsList).
|
// 3. Let M be MakeBasicObject(internalSlotsList).
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <LibJS/Heap/Handle.h>
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/Runtime/Environment.h>
|
#include <LibJS/Runtime/Environment.h>
|
||||||
#include <LibJS/Runtime/Realm.h>
|
#include <LibJS/Runtime/Realm.h>
|
||||||
|
|
||||||
|
@ -55,18 +55,18 @@ struct ResolvedBinding {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 16.2.1.4 Abstract Module Records, https://tc39.es/ecma262/#sec-abstract-module-records
|
// 16.2.1.4 Abstract Module Records, https://tc39.es/ecma262/#sec-abstract-module-records
|
||||||
class Module
|
class Module : public Cell {
|
||||||
: public RefCounted<Module>
|
JS_CELL(Module, Cell);
|
||||||
, public Weakable<Module> {
|
|
||||||
public:
|
|
||||||
virtual ~Module() = default;
|
|
||||||
|
|
||||||
Realm& realm() { return *m_realm.cell(); }
|
public:
|
||||||
Realm const& realm() const { return *m_realm.cell(); }
|
virtual ~Module() override;
|
||||||
|
|
||||||
|
Realm& realm() { return *m_realm; }
|
||||||
|
Realm const& realm() const { return *m_realm; }
|
||||||
|
|
||||||
StringView filename() const { return m_filename; }
|
StringView filename() const { return m_filename; }
|
||||||
|
|
||||||
Environment* environment() { return m_environment.cell(); }
|
Environment* environment() { return m_environment; }
|
||||||
|
|
||||||
ThrowCompletionOr<Object*> get_module_namespace(VM& vm);
|
ThrowCompletionOr<Object*> get_module_namespace(VM& vm);
|
||||||
|
|
||||||
|
@ -82,9 +82,11 @@ public:
|
||||||
protected:
|
protected:
|
||||||
Module(Realm&, String filename);
|
Module(Realm&, String filename);
|
||||||
|
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
void set_environment(Environment* environment)
|
void set_environment(Environment* environment)
|
||||||
{
|
{
|
||||||
m_environment = make_handle(environment);
|
m_environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -95,9 +97,9 @@ private:
|
||||||
// destroy the VM but keep the modules this should not happen. Because VM
|
// destroy the VM but keep the modules this should not happen. Because VM
|
||||||
// stores modules with a RefPtr we cannot just store the VM as that leads to
|
// stores modules with a RefPtr we cannot just store the VM as that leads to
|
||||||
// cycles.
|
// cycles.
|
||||||
Handle<Realm> m_realm; // [[Realm]]
|
GCPtr<Realm> m_realm; // [[Realm]]
|
||||||
Handle<Environment> m_environment; // [[Environment]]
|
GCPtr<Environment> m_environment; // [[Environment]]
|
||||||
Handle<Object> m_namespace; // [[Namespace]]
|
GCPtr<Object> m_namespace; // [[Namespace]]
|
||||||
|
|
||||||
// Needed for potential lookups of modules.
|
// Needed for potential lookups of modules.
|
||||||
String m_filename;
|
String m_filename;
|
||||||
|
|
|
@ -303,6 +303,12 @@ void ECMAScriptFunctionObject::visit_edges(Visitor& visitor)
|
||||||
if (auto* property_key_ptr = field.name.get_pointer<PropertyKey>(); property_key_ptr && property_key_ptr->is_symbol())
|
if (auto* property_key_ptr = field.name.get_pointer<PropertyKey>(); property_key_ptr && property_key_ptr->is_symbol())
|
||||||
visitor.visit(property_key_ptr->as_symbol());
|
visitor.visit(property_key_ptr->as_symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_script_or_module.visit(
|
||||||
|
[](Empty) {},
|
||||||
|
[&](auto& script_or_module) {
|
||||||
|
visitor.visit(script_or_module.ptr());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10.2.7 MakeMethod ( F, homeObject ), https://tc39.es/ecma262/#sec-makemethod
|
// 10.2.7 MakeMethod ( F, homeObject ), https://tc39.es/ecma262/#sec-makemethod
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
using ScriptOrModule = Variant<Empty, WeakPtr<Script>, WeakPtr<Module>>;
|
using ScriptOrModule = Variant<Empty, NonnullGCPtr<Script>, NonnullGCPtr<Module>>;
|
||||||
|
|
||||||
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
||||||
struct ExecutionContext {
|
struct ExecutionContext {
|
||||||
|
|
|
@ -205,6 +205,11 @@ void VM::gather_roots(HashTable<Cell*>& roots)
|
||||||
roots.set(execution_context->lexical_environment);
|
roots.set(execution_context->lexical_environment);
|
||||||
roots.set(execution_context->variable_environment);
|
roots.set(execution_context->variable_environment);
|
||||||
roots.set(execution_context->private_environment);
|
roots.set(execution_context->private_environment);
|
||||||
|
execution_context->script_or_module.visit(
|
||||||
|
[](Empty) {},
|
||||||
|
[&](auto& script_or_module) {
|
||||||
|
roots.set(script_or_module.ptr());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -800,7 +805,7 @@ ThrowCompletionOr<void> VM::link_and_eval_module(Module& module)
|
||||||
dbgln("Warning: Using multiple modules as entry point can lead to unexpected results");
|
dbgln("Warning: Using multiple modules as entry point can lead to unexpected results");
|
||||||
|
|
||||||
m_loaded_modules.empend(
|
m_loaded_modules.empend(
|
||||||
module.make_weak_ptr(),
|
NonnullGCPtr(module),
|
||||||
module.filename(),
|
module.filename(),
|
||||||
String {}, // Null type
|
String {}, // Null type
|
||||||
module,
|
module,
|
||||||
|
@ -865,7 +870,7 @@ static String resolve_module_filename(StringView filename, StringView module_typ
|
||||||
}
|
}
|
||||||
|
|
||||||
// 16.2.1.7 HostResolveImportedModule ( referencingScriptOrModule, specifier ), https://tc39.es/ecma262/#sec-hostresolveimportedmodule
|
// 16.2.1.7 HostResolveImportedModule ( referencingScriptOrModule, specifier ), https://tc39.es/ecma262/#sec-hostresolveimportedmodule
|
||||||
ThrowCompletionOr<NonnullRefPtr<Module>> VM::resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request)
|
ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request)
|
||||||
{
|
{
|
||||||
// An implementation of HostResolveImportedModule must conform to the following requirements:
|
// An implementation of HostResolveImportedModule must conform to the following requirements:
|
||||||
// - If it completes normally, the [[Value]] slot of the completion must contain an instance of a concrete subclass of Module Record.
|
// - If it completes normally, the [[Value]] slot of the completion must contain an instance of a concrete subclass of Module Record.
|
||||||
|
@ -912,9 +917,9 @@ ThrowCompletionOr<NonnullRefPtr<Module>> VM::resolve_imported_module(ScriptOrMod
|
||||||
},
|
},
|
||||||
[&](auto& script_or_module) {
|
[&](auto& script_or_module) {
|
||||||
if constexpr (IsSame<Script*, decltype(script_or_module)>) {
|
if constexpr (IsSame<Script*, decltype(script_or_module)>) {
|
||||||
return String::formatted("Script @ {}", script_or_module);
|
return String::formatted("Script @ {}", script_or_module.ptr());
|
||||||
}
|
}
|
||||||
return String::formatted("Module @ {}", script_or_module);
|
return String::formatted("Module @ {}", script_or_module.ptr());
|
||||||
});
|
});
|
||||||
|
|
||||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolve_imported_module({}, {})", referencing_module_string, filename);
|
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolve_imported_module({}, {})", referencing_module_string, filename);
|
||||||
|
@ -924,7 +929,7 @@ ThrowCompletionOr<NonnullRefPtr<Module>> VM::resolve_imported_module(ScriptOrMod
|
||||||
auto* loaded_module_or_end = get_stored_module(referencing_script_or_module, filename, module_type);
|
auto* loaded_module_or_end = get_stored_module(referencing_script_or_module, filename, module_type);
|
||||||
if (loaded_module_or_end != nullptr) {
|
if (loaded_module_or_end != nullptr) {
|
||||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolve_imported_module({}) already loaded at {}", filename, loaded_module_or_end->module.ptr());
|
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolve_imported_module({}) already loaded at {}", filename, loaded_module_or_end->module.ptr());
|
||||||
return loaded_module_or_end->module;
|
return NonnullGCPtr(*loaded_module_or_end->module);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] reading and parsing module {}", filename);
|
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] reading and parsing module {}", filename);
|
||||||
|
@ -939,7 +944,7 @@ ThrowCompletionOr<NonnullRefPtr<Module>> VM::resolve_imported_module(ScriptOrMod
|
||||||
auto file_content = file_or_error.value()->read_all();
|
auto file_content = file_or_error.value()->read_all();
|
||||||
StringView content_view { file_content.data(), file_content.size() };
|
StringView content_view { file_content.data(), file_content.size() };
|
||||||
|
|
||||||
auto module = TRY([&]() -> ThrowCompletionOr<NonnullRefPtr<Module>> {
|
auto module = TRY([&]() -> ThrowCompletionOr<NonnullGCPtr<Module>> {
|
||||||
// If assertions has an entry entry such that entry.[[Key]] is "type", let type be entry.[[Value]]. The following requirements apply:
|
// If assertions has an entry entry such that entry.[[Key]] is "type", let type be entry.[[Value]]. The following requirements apply:
|
||||||
// If type is "json", then this algorithm must either invoke ParseJSONModule and return the resulting Completion Record, or throw an exception.
|
// If type is "json", then this algorithm must either invoke ParseJSONModule and return the resulting Completion Record, or throw an exception.
|
||||||
if (module_type == "json"sv) {
|
if (module_type == "json"sv) {
|
||||||
|
@ -965,7 +970,7 @@ ThrowCompletionOr<NonnullRefPtr<Module>> VM::resolve_imported_module(ScriptOrMod
|
||||||
referencing_script_or_module,
|
referencing_script_or_module,
|
||||||
filename,
|
filename,
|
||||||
module_type,
|
module_type,
|
||||||
module,
|
*module,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
|
|
|
@ -220,7 +220,7 @@ public:
|
||||||
|
|
||||||
ScriptOrModule get_active_script_or_module() const;
|
ScriptOrModule get_active_script_or_module() const;
|
||||||
|
|
||||||
Function<ThrowCompletionOr<NonnullRefPtr<Module>>(ScriptOrModule, ModuleRequest const&)> host_resolve_imported_module;
|
Function<ThrowCompletionOr<NonnullGCPtr<Module>>(ScriptOrModule, ModuleRequest const&)> host_resolve_imported_module;
|
||||||
Function<void(ScriptOrModule, ModuleRequest, PromiseCapability)> host_import_module_dynamically;
|
Function<void(ScriptOrModule, ModuleRequest, PromiseCapability)> host_import_module_dynamically;
|
||||||
Function<void(ScriptOrModule, ModuleRequest const&, PromiseCapability, Promise*)> host_finish_dynamic_import;
|
Function<void(ScriptOrModule, ModuleRequest const&, PromiseCapability, Promise*)> host_finish_dynamic_import;
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ private:
|
||||||
ThrowCompletionOr<void> property_binding_initialization(BindingPattern const& binding, Value value, Environment* environment);
|
ThrowCompletionOr<void> property_binding_initialization(BindingPattern const& binding, Value value, Environment* environment);
|
||||||
ThrowCompletionOr<void> iterator_binding_initialization(BindingPattern const& binding, Iterator& iterator_record, Environment* environment);
|
ThrowCompletionOr<void> iterator_binding_initialization(BindingPattern const& binding, Iterator& iterator_record, Environment* environment);
|
||||||
|
|
||||||
ThrowCompletionOr<NonnullRefPtr<Module>> resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request);
|
ThrowCompletionOr<NonnullGCPtr<Module>> resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request);
|
||||||
ThrowCompletionOr<void> link_and_eval_module(Module& module);
|
ThrowCompletionOr<void> link_and_eval_module(Module& module);
|
||||||
|
|
||||||
void import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability promise_capability);
|
void import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability promise_capability);
|
||||||
|
@ -275,7 +275,7 @@ private:
|
||||||
ScriptOrModule referencing_script_or_module;
|
ScriptOrModule referencing_script_or_module;
|
||||||
String filename;
|
String filename;
|
||||||
String type;
|
String type;
|
||||||
NonnullRefPtr<Module> module;
|
Handle<Module> module;
|
||||||
bool has_once_started_linking { false };
|
bool has_once_started_linking { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
// 16.1.5 ParseScript ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parse-script
|
// 16.1.5 ParseScript ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parse-script
|
||||||
Result<NonnullRefPtr<Script>, Vector<Parser::Error>> Script::parse(StringView source_text, Realm& realm, StringView filename, HostDefined* host_defined, size_t line_number_offset)
|
Result<NonnullGCPtr<Script>, Vector<Parser::Error>> Script::parse(StringView source_text, Realm& realm, StringView filename, HostDefined* host_defined, size_t line_number_offset)
|
||||||
{
|
{
|
||||||
// 1. Let script be ParseText(sourceText, Script).
|
// 1. Let script be ParseText(sourceText, Script).
|
||||||
auto parser = Parser(Lexer(source_text, filename, line_number_offset));
|
auto parser = Parser(Lexer(source_text, filename, line_number_offset));
|
||||||
|
@ -24,16 +24,25 @@ Result<NonnullRefPtr<Script>, Vector<Parser::Error>> Script::parse(StringView so
|
||||||
return parser.errors();
|
return parser.errors();
|
||||||
|
|
||||||
// 3. Return Script Record { [[Realm]]: realm, [[ECMAScriptCode]]: script, [[HostDefined]]: hostDefined }.
|
// 3. Return Script Record { [[Realm]]: realm, [[ECMAScriptCode]]: script, [[HostDefined]]: hostDefined }.
|
||||||
return adopt_ref(*new Script(realm, filename, move(script), host_defined));
|
return NonnullGCPtr(*realm.heap().allocate_without_realm<Script>(realm, filename, move(script), host_defined));
|
||||||
}
|
}
|
||||||
|
|
||||||
Script::Script(Realm& realm, StringView filename, NonnullRefPtr<Program> parse_node, HostDefined* host_defined)
|
Script::Script(Realm& realm, StringView filename, NonnullRefPtr<Program> parse_node, HostDefined* host_defined)
|
||||||
: m_vm(realm.vm())
|
: m_realm(realm)
|
||||||
, m_realm(make_handle(&realm))
|
|
||||||
, m_parse_node(move(parse_node))
|
, m_parse_node(move(parse_node))
|
||||||
, m_filename(filename)
|
, m_filename(filename)
|
||||||
, m_host_defined(host_defined)
|
, m_host_defined(host_defined)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Script::~Script()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Script::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_realm);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
#include <AK/NonnullRefPtr.h>
|
||||||
#include <AK/RefCounted.h>
|
|
||||||
#include <LibJS/AST.h>
|
#include <LibJS/AST.h>
|
||||||
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/Heap/Handle.h>
|
#include <LibJS/Heap/Handle.h>
|
||||||
#include <LibJS/Parser.h>
|
#include <LibJS/Parser.h>
|
||||||
#include <LibJS/Runtime/Realm.h>
|
#include <LibJS/Runtime/Realm.h>
|
||||||
|
@ -16,18 +16,18 @@
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
// 16.1.4 Script Records, https://tc39.es/ecma262/#sec-script-records
|
// 16.1.4 Script Records, https://tc39.es/ecma262/#sec-script-records
|
||||||
class Script
|
class Script final : public Cell {
|
||||||
: public RefCounted<Script>
|
JS_CELL(Script, Cell);
|
||||||
, public Weakable<Script> {
|
|
||||||
public:
|
public:
|
||||||
struct HostDefined {
|
struct HostDefined {
|
||||||
virtual ~HostDefined() = default;
|
virtual ~HostDefined() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
~Script() = default;
|
virtual ~Script() override;
|
||||||
static Result<NonnullRefPtr<Script>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {}, HostDefined* = nullptr, size_t line_number_offset = 1);
|
static Result<NonnullGCPtr<Script>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {}, HostDefined* = nullptr, size_t line_number_offset = 1);
|
||||||
|
|
||||||
Realm& realm() { return *m_realm.cell(); }
|
Realm& realm() { return *m_realm; }
|
||||||
Program const& parse_node() const { return *m_parse_node; }
|
Program const& parse_node() const { return *m_parse_node; }
|
||||||
|
|
||||||
HostDefined* host_defined() { return m_host_defined; }
|
HostDefined* host_defined() { return m_host_defined; }
|
||||||
|
@ -35,10 +35,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Script(Realm&, StringView filename, NonnullRefPtr<Program>, HostDefined* = nullptr);
|
Script(Realm&, StringView filename, NonnullRefPtr<Program>, HostDefined* = nullptr);
|
||||||
// Handles are not safe unless we keep the VM alive.
|
|
||||||
NonnullRefPtr<VM> m_vm;
|
|
||||||
|
|
||||||
Handle<Realm> m_realm; // [[Realm]]
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
|
GCPtr<Realm> m_realm; // [[Realm]]
|
||||||
NonnullRefPtr<Program> m_parse_node; // [[ECMAScriptCode]]
|
NonnullRefPtr<Program> m_parse_node; // [[ECMAScriptCode]]
|
||||||
|
|
||||||
// Needed for potential lookups of modules.
|
// Needed for potential lookups of modules.
|
||||||
|
|
|
@ -113,8 +113,14 @@ SourceTextModule::SourceTextModule(Realm& realm, StringView filename, bool has_t
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SourceTextModule::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_import_meta);
|
||||||
|
}
|
||||||
|
|
||||||
// 16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
|
// 16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
|
||||||
Result<NonnullRefPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename)
|
Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename)
|
||||||
{
|
{
|
||||||
// 1. Let body be ParseText(sourceText, Module).
|
// 1. Let body be ParseText(sourceText, Module).
|
||||||
auto parser = Parser(Lexer(source_text, filename), Program::Type::Module);
|
auto parser = Parser(Lexer(source_text, filename), Program::Type::Module);
|
||||||
|
@ -239,7 +245,17 @@ Result<NonnullRefPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule:
|
||||||
// [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries,
|
// [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries,
|
||||||
// [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: empty, [[DFSAncestorIndex]]: empty }.
|
// [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: empty, [[DFSAncestorIndex]]: empty }.
|
||||||
// FIXME: Add HostDefined
|
// FIXME: Add HostDefined
|
||||||
return adopt_ref(*new SourceTextModule(realm, filename, async, move(body), move(requested_modules), move(import_entries), move(local_export_entries), move(indirect_export_entries), move(star_export_entries), move(default_export)));
|
return NonnullGCPtr(*realm.heap().allocate_without_realm<SourceTextModule>(
|
||||||
|
realm,
|
||||||
|
filename,
|
||||||
|
async,
|
||||||
|
move(body),
|
||||||
|
move(requested_modules),
|
||||||
|
move(import_entries),
|
||||||
|
move(local_export_entries),
|
||||||
|
move(indirect_export_entries),
|
||||||
|
move(star_export_entries),
|
||||||
|
move(default_export)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 16.2.1.6.2 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
|
// 16.2.1.6.2 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
|
||||||
|
@ -285,7 +301,7 @@ ThrowCompletionOr<Vector<FlyString>> SourceTextModule::get_exported_names(VM& vm
|
||||||
// 7. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
// 7. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
||||||
for (auto& entry : m_star_export_entries) {
|
for (auto& entry : m_star_export_entries) {
|
||||||
// a. Let requestedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
|
// a. Let requestedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
|
||||||
auto requested_module = TRY(vm.host_resolve_imported_module(this->make_weak_ptr(), entry.module_request()));
|
auto requested_module = TRY(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), entry.module_request()));
|
||||||
|
|
||||||
// b. Let starNames be ? requestedModule.GetExportedNames(exportStarSet).
|
// b. Let starNames be ? requestedModule.GetExportedNames(exportStarSet).
|
||||||
auto star_names = TRY(requested_module->get_exported_names(vm, export_star_set));
|
auto star_names = TRY(requested_module->get_exported_names(vm, export_star_set));
|
||||||
|
@ -339,7 +355,7 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
||||||
// 7. For each ImportEntry Record in of module.[[ImportEntries]], do
|
// 7. For each ImportEntry Record in of module.[[ImportEntries]], do
|
||||||
for (auto& import_entry : m_import_entries) {
|
for (auto& import_entry : m_import_entries) {
|
||||||
// a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]).
|
// a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]).
|
||||||
auto imported_module = MUST(vm.host_resolve_imported_module(this->make_weak_ptr(), import_entry.module_request()));
|
auto imported_module = MUST(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), import_entry.module_request()));
|
||||||
// b. NOTE: The above call cannot fail because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.
|
// b. NOTE: The above call cannot fail because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.
|
||||||
|
|
||||||
// c. If in.[[ImportName]] is namespace-object, then
|
// c. If in.[[ImportName]] is namespace-object, then
|
||||||
|
@ -393,7 +409,7 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
||||||
m_execution_context.realm = &realm();
|
m_execution_context.realm = &realm();
|
||||||
|
|
||||||
// 12. Set the ScriptOrModule of moduleContext to module.
|
// 12. Set the ScriptOrModule of moduleContext to module.
|
||||||
m_execution_context.script_or_module = this->make_weak_ptr();
|
m_execution_context.script_or_module = NonnullGCPtr<Module>(*this);
|
||||||
|
|
||||||
// 13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
|
// 13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
|
||||||
m_execution_context.variable_environment = environment;
|
m_execution_context.variable_environment = environment;
|
||||||
|
@ -544,7 +560,7 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// i. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
|
// i. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
|
||||||
auto imported_module = TRY(vm.host_resolve_imported_module(this->make_weak_ptr(), entry.module_request()));
|
auto imported_module = TRY(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), entry.module_request()));
|
||||||
|
|
||||||
// ii. If e.[[ImportName]] is all, then
|
// ii. If e.[[ImportName]] is all, then
|
||||||
if (entry.kind == ExportStatement::ExportEntry::Kind::ModuleRequestAll) {
|
if (entry.kind == ExportStatement::ExportEntry::Kind::ModuleRequestAll) {
|
||||||
|
@ -584,7 +600,7 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
||||||
// 8. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
// 8. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
||||||
for (auto& entry : m_star_export_entries) {
|
for (auto& entry : m_star_export_entries) {
|
||||||
// a. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
|
// a. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
|
||||||
auto imported_module = TRY(vm.host_resolve_imported_module(this->make_weak_ptr(), entry.module_request()));
|
auto imported_module = TRY(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), entry.module_request()));
|
||||||
|
|
||||||
// b. Let resolution be ? importedModule.ResolveExport(exportName, resolveSet).
|
// b. Let resolution be ? importedModule.ResolveExport(exportName, resolveSet).
|
||||||
auto resolution = TRY(imported_module->resolve_export(vm, export_name, resolve_set));
|
auto resolution = TRY(imported_module->resolve_export(vm, export_name, resolve_set));
|
||||||
|
@ -646,7 +662,7 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, Optional<Promis
|
||||||
module_context.realm = &realm();
|
module_context.realm = &realm();
|
||||||
|
|
||||||
// 4. Set the ScriptOrModule of moduleContext to module.
|
// 4. Set the ScriptOrModule of moduleContext to module.
|
||||||
module_context.script_or_module = this->make_weak_ptr();
|
module_context.script_or_module = NonnullGCPtr<Module>(*this);
|
||||||
|
|
||||||
// 5. Assert: module has been linked and declarations in its module environment have been instantiated.
|
// 5. Assert: module has been linked and declarations in its module environment have been instantiated.
|
||||||
VERIFY(m_status != ModuleStatus::Unlinked && m_status != ModuleStatus::Linking && environment());
|
VERIFY(m_status != ModuleStatus::Unlinked && m_status != ModuleStatus::Linking && environment());
|
||||||
|
|
|
@ -16,28 +16,21 @@ namespace JS {
|
||||||
|
|
||||||
// 16.2.1.6 Source Text Module Records, https://tc39.es/ecma262/#sec-source-text-module-records
|
// 16.2.1.6 Source Text Module Records, https://tc39.es/ecma262/#sec-source-text-module-records
|
||||||
class SourceTextModule final : public CyclicModule {
|
class SourceTextModule final : public CyclicModule {
|
||||||
|
JS_CELL(SourceTextModule, CyclicModule);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ImportEntry = ImportStatement::ImportEntry;
|
using ImportEntry = ImportStatement::ImportEntry;
|
||||||
using ExportEntry = ExportStatement::ExportEntry;
|
using ExportEntry = ExportStatement::ExportEntry;
|
||||||
|
|
||||||
static Result<NonnullRefPtr<SourceTextModule>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {});
|
static Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {});
|
||||||
|
|
||||||
Program const& parse_node() const { return *m_ecmascript_code; }
|
Program const& parse_node() const { return *m_ecmascript_code; }
|
||||||
|
|
||||||
virtual ThrowCompletionOr<Vector<FlyString>> get_exported_names(VM& vm, Vector<Module*> export_star_set) override;
|
virtual ThrowCompletionOr<Vector<FlyString>> get_exported_names(VM& vm, Vector<Module*> export_star_set) override;
|
||||||
virtual ThrowCompletionOr<ResolvedBinding> resolve_export(VM& vm, FlyString const& export_name, Vector<ResolvedBinding> resolve_set = {}) override;
|
virtual ThrowCompletionOr<ResolvedBinding> resolve_export(VM& vm, FlyString const& export_name, Vector<ResolvedBinding> resolve_set = {}) override;
|
||||||
|
|
||||||
Object* import_meta()
|
Object* import_meta() { return m_import_meta; }
|
||||||
{
|
void set_import_meta(Badge<MetaProperty>, Object* import_meta) { m_import_meta = import_meta; }
|
||||||
if (m_import_meta.is_null())
|
|
||||||
return nullptr;
|
|
||||||
return m_import_meta.cell();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_import_meta(Badge<MetaProperty>, Object* import_meta)
|
|
||||||
{
|
|
||||||
m_import_meta = make_handle(import_meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ThrowCompletionOr<void> initialize_environment(VM& vm) override;
|
virtual ThrowCompletionOr<void> initialize_environment(VM& vm) override;
|
||||||
|
@ -49,9 +42,11 @@ private:
|
||||||
Vector<ExportEntry> indirect_export_entries, Vector<ExportEntry> star_export_entries,
|
Vector<ExportEntry> indirect_export_entries, Vector<ExportEntry> star_export_entries,
|
||||||
RefPtr<ExportStatement> default_export);
|
RefPtr<ExportStatement> default_export);
|
||||||
|
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
NonnullRefPtr<Program> m_ecmascript_code; // [[ECMAScriptCode]]
|
NonnullRefPtr<Program> m_ecmascript_code; // [[ECMAScriptCode]]
|
||||||
ExecutionContext m_execution_context; // [[Context]]
|
ExecutionContext m_execution_context; // [[Context]]
|
||||||
Handle<Object> m_import_meta; // [[ImportMeta]]
|
GCPtr<Object> m_import_meta; // [[ImportMeta]]
|
||||||
Vector<ImportEntry> m_import_entries; // [[ImportEntries]]
|
Vector<ImportEntry> m_import_entries; // [[ImportEntries]]
|
||||||
Vector<ExportEntry> m_local_export_entries; // [[LocalExportEntries]]
|
Vector<ExportEntry> m_local_export_entries; // [[LocalExportEntries]]
|
||||||
Vector<ExportEntry> m_indirect_export_entries; // [[IndirectExportEntries]]
|
Vector<ExportEntry> m_indirect_export_entries; // [[IndirectExportEntries]]
|
||||||
|
|
|
@ -86,7 +86,7 @@ ThrowCompletionOr<Promise*> SyntheticModule::evaluate(VM& vm)
|
||||||
module_context.realm = &realm();
|
module_context.realm = &realm();
|
||||||
|
|
||||||
// 5. Set the ScriptOrModule of moduleContext to module.
|
// 5. Set the ScriptOrModule of moduleContext to module.
|
||||||
module_context.script_or_module = this->make_weak_ptr();
|
module_context.script_or_module = NonnullGCPtr<Module>(*this);
|
||||||
|
|
||||||
// 6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
|
// 6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
|
||||||
module_context.variable_environment = environment();
|
module_context.variable_environment = environment();
|
||||||
|
@ -129,7 +129,7 @@ ThrowCompletionOr<void> SyntheticModule::set_synthetic_module_export(FlyString c
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.3 CreateDefaultExportSyntheticModule ( defaultExport ), https://tc39.es/proposal-json-modules/#sec-create-default-export-synthetic-module
|
// 1.3 CreateDefaultExportSyntheticModule ( defaultExport ), https://tc39.es/proposal-json-modules/#sec-create-default-export-synthetic-module
|
||||||
NonnullRefPtr<SyntheticModule> SyntheticModule::create_default_export_synthetic_module(Value default_export, Realm& realm, StringView filename)
|
NonnullGCPtr<SyntheticModule> SyntheticModule::create_default_export_synthetic_module(Value default_export, Realm& realm, StringView filename)
|
||||||
{
|
{
|
||||||
// Note: Has some changes from PR: https://github.com/tc39/proposal-json-modules/pull/13.
|
// Note: Has some changes from PR: https://github.com/tc39/proposal-json-modules/pull/13.
|
||||||
// 1. Let closure be the a Abstract Closure with parameters (module) that captures defaultExport and performs the following steps when called:
|
// 1. Let closure be the a Abstract Closure with parameters (module) that captures defaultExport and performs the following steps when called:
|
||||||
|
@ -139,11 +139,11 @@ NonnullRefPtr<SyntheticModule> SyntheticModule::create_default_export_synthetic_
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. Return CreateSyntheticModule("default", closure, realm)
|
// 2. Return CreateSyntheticModule("default", closure, realm)
|
||||||
return adopt_ref(*new SyntheticModule({ "default" }, move(closure), realm, filename));
|
return *realm.heap().allocate_without_realm<SyntheticModule>(Vector<FlyString> { "default" }, move(closure), realm, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.4 ParseJSONModule ( source ), https://tc39.es/proposal-json-modules/#sec-parse-json-module
|
// 1.4 ParseJSONModule ( source ), https://tc39.es/proposal-json-modules/#sec-parse-json-module
|
||||||
ThrowCompletionOr<NonnullRefPtr<Module>> parse_json_module(StringView source_text, Realm& realm, StringView filename)
|
ThrowCompletionOr<NonnullGCPtr<Module>> parse_json_module(StringView source_text, Realm& realm, StringView filename)
|
||||||
{
|
{
|
||||||
auto& vm = realm.vm();
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,12 @@ namespace JS {
|
||||||
|
|
||||||
// 1.2 Synthetic Module Records, https://tc39.es/proposal-json-modules/#sec-synthetic-module-records
|
// 1.2 Synthetic Module Records, https://tc39.es/proposal-json-modules/#sec-synthetic-module-records
|
||||||
class SyntheticModule final : public Module {
|
class SyntheticModule final : public Module {
|
||||||
|
JS_CELL(SyntheticModule, Module);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using EvaluationFunction = Function<ThrowCompletionOr<void>(SyntheticModule&)>;
|
using EvaluationFunction = Function<ThrowCompletionOr<void>(SyntheticModule&)>;
|
||||||
|
|
||||||
SyntheticModule(Vector<FlyString> export_names, EvaluationFunction evaluation_steps, Realm& realm, StringView filename);
|
static NonnullGCPtr<SyntheticModule> create_default_export_synthetic_module(Value default_export, Realm& realm, StringView filename);
|
||||||
|
|
||||||
static NonnullRefPtr<SyntheticModule> create_default_export_synthetic_module(Value default_export, Realm& realm, StringView filename);
|
|
||||||
|
|
||||||
ThrowCompletionOr<void> set_synthetic_module_export(FlyString const& export_name, Value export_value);
|
ThrowCompletionOr<void> set_synthetic_module_export(FlyString const& export_name, Value export_value);
|
||||||
|
|
||||||
|
@ -27,10 +27,12 @@ public:
|
||||||
virtual ThrowCompletionOr<ResolvedBinding> resolve_export(VM& vm, FlyString const& export_name, Vector<ResolvedBinding> resolve_set) override;
|
virtual ThrowCompletionOr<ResolvedBinding> resolve_export(VM& vm, FlyString const& export_name, Vector<ResolvedBinding> resolve_set) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
SyntheticModule(Vector<FlyString> export_names, EvaluationFunction evaluation_steps, Realm& realm, StringView filename);
|
||||||
|
|
||||||
Vector<FlyString> m_export_names; // [[ExportNames]]
|
Vector<FlyString> m_export_names; // [[ExportNames]]
|
||||||
EvaluationFunction m_evaluation_steps; // [[EvaluationSteps]]
|
EvaluationFunction m_evaluation_steps; // [[EvaluationSteps]]
|
||||||
};
|
};
|
||||||
|
|
||||||
ThrowCompletionOr<NonnullRefPtr<Module>> parse_json_module(StringView source_text, Realm& realm, StringView filename);
|
ThrowCompletionOr<NonnullGCPtr<Module>> parse_json_module(StringView source_text, Realm& realm, StringView filename);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ inline ByteBuffer load_entire_file(StringView path)
|
||||||
return buffer_or_error.release_value();
|
return buffer_or_error.release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline AK::Result<NonnullRefPtr<JS::Script>, ParserError> parse_script(StringView path, JS::Realm& realm)
|
inline AK::Result<JS::NonnullGCPtr<JS::Script>, ParserError> parse_script(StringView path, JS::Realm& realm)
|
||||||
{
|
{
|
||||||
auto contents = load_entire_file(path);
|
auto contents = load_entire_file(path);
|
||||||
auto script_or_errors = JS::Script::parse(contents, realm, path);
|
auto script_or_errors = JS::Script::parse(contents, realm, path);
|
||||||
|
@ -244,7 +244,7 @@ inline AK::Result<NonnullRefPtr<JS::Script>, ParserError> parse_script(StringVie
|
||||||
return script_or_errors.release_value();
|
return script_or_errors.release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline AK::Result<NonnullRefPtr<JS::SourceTextModule>, ParserError> parse_module(StringView path, JS::Realm& realm)
|
inline AK::Result<JS::NonnullGCPtr<JS::SourceTextModule>, ParserError> parse_module(StringView path, JS::Realm& realm)
|
||||||
{
|
{
|
||||||
auto contents = load_entire_file(path);
|
auto contents = load_entire_file(path);
|
||||||
auto script_or_errors = JS::SourceTextModule::parse(contents, realm, path);
|
auto script_or_errors = JS::SourceTextModule::parse(contents, realm, path);
|
||||||
|
|
|
@ -35,12 +35,12 @@ HTML::ClassicScript* active_script()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// 3. Return record.[[HostDefined]].
|
// 3. Return record.[[HostDefined]].
|
||||||
if (record.has<WeakPtr<JS::Module>>()) {
|
if (record.has<JS::NonnullGCPtr<JS::Module>>()) {
|
||||||
// FIXME: We don't currently have a module script.
|
// FIXME: We don't currently have a module script.
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto js_script = record.get<WeakPtr<JS::Script>>();
|
auto js_script = record.get<JS::NonnullGCPtr<JS::Script>>();
|
||||||
VERIFY(js_script);
|
VERIFY(js_script);
|
||||||
VERIFY(js_script->host_defined());
|
VERIFY(js_script->host_defined());
|
||||||
return verify_cast<HTML::ClassicScript>(js_script->host_defined());
|
return verify_cast<HTML::ClassicScript>(js_script->host_defined());
|
||||||
|
@ -76,10 +76,10 @@ JS::VM& main_thread_vm()
|
||||||
// The running script is the script in the [[HostDefined]] field in the ScriptOrModule component of the running JavaScript execution context.
|
// The running script is the script in the [[HostDefined]] field in the ScriptOrModule component of the running JavaScript execution context.
|
||||||
HTML::Script* script { nullptr };
|
HTML::Script* script { nullptr };
|
||||||
vm->running_execution_context().script_or_module.visit(
|
vm->running_execution_context().script_or_module.visit(
|
||||||
[&script](WeakPtr<JS::Script>& js_script) {
|
[&script](JS::NonnullGCPtr<JS::Script>& js_script) {
|
||||||
script = verify_cast<HTML::ClassicScript>(js_script->host_defined());
|
script = verify_cast<HTML::ClassicScript>(js_script->host_defined());
|
||||||
},
|
},
|
||||||
[](WeakPtr<JS::Module>&) {
|
[](JS::NonnullGCPtr<JS::Module>&) {
|
||||||
TODO();
|
TODO();
|
||||||
},
|
},
|
||||||
[](Empty) {
|
[](Empty) {
|
||||||
|
@ -240,8 +240,7 @@ JS::VM& main_thread_vm()
|
||||||
// Since this requires pushing an execution context onto the stack, it also requires a global object. The only thing we can get a global object from in this case is the script or module.
|
// Since this requires pushing an execution context onto the stack, it also requires a global object. The only thing we can get a global object from in this case is the script or module.
|
||||||
// To do this, we must assume script or module is not Empty. We must also assume that it is a Script Record for now as we don't currently run modules.
|
// To do this, we must assume script or module is not Empty. We must also assume that it is a Script Record for now as we don't currently run modules.
|
||||||
// Do note that the JS spec gives _no_ guarantee that the execution context stack has something on it if HostEnqueuePromiseJob was called with a null realm: https://tc39.es/ecma262/#job-preparedtoevaluatecode
|
// Do note that the JS spec gives _no_ guarantee that the execution context stack has something on it if HostEnqueuePromiseJob was called with a null realm: https://tc39.es/ecma262/#job-preparedtoevaluatecode
|
||||||
VERIFY(script_or_module.has<WeakPtr<JS::Script>>());
|
VERIFY(script_or_module.has<JS::NonnullGCPtr<JS::Script>>());
|
||||||
auto script_record = script_or_module.get<WeakPtr<JS::Script>>();
|
|
||||||
dummy_execution_context = JS::ExecutionContext { vm->heap() };
|
dummy_execution_context = JS::ExecutionContext { vm->heap() };
|
||||||
dummy_execution_context->script_or_module = script_or_module;
|
dummy_execution_context->script_or_module = script_or_module;
|
||||||
vm->push_execution_context(dummy_execution_context.value());
|
vm->push_execution_context(dummy_execution_context.value());
|
||||||
|
@ -285,7 +284,7 @@ JS::VM& main_thread_vm()
|
||||||
script_execution_context->function = nullptr;
|
script_execution_context->function = nullptr;
|
||||||
script_execution_context->realm = &script->settings_object().realm();
|
script_execution_context->realm = &script->settings_object().realm();
|
||||||
VERIFY(script->script_record());
|
VERIFY(script->script_record());
|
||||||
script_execution_context->script_or_module = script->script_record()->make_weak_ptr();
|
script_execution_context->script_or_module = JS::NonnullGCPtr<JS::Script>(*script->script_record());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Return the JobCallback Record { [[Callback]]: callable, [[HostDefined]]: { [[IncumbentSettings]]: incumbent settings, [[ActiveScriptContext]]: script execution context } }.
|
// 5. Return the JobCallback Record { [[Callback]]: callable, [[HostDefined]]: { [[IncumbentSettings]]: incumbent settings, [[ActiveScriptContext]]: script execution context } }.
|
||||||
|
@ -298,7 +297,7 @@ JS::VM& main_thread_vm()
|
||||||
// FIXME: Implement 8.1.5.5.3 HostResolveImportedModule(referencingScriptOrModule, moduleRequest), https://html.spec.whatwg.org/multipage/webappapis.html#hostresolveimportedmodule(referencingscriptormodule,-modulerequest)
|
// FIXME: Implement 8.1.5.5.3 HostResolveImportedModule(referencingScriptOrModule, moduleRequest), https://html.spec.whatwg.org/multipage/webappapis.html#hostresolveimportedmodule(referencingscriptormodule,-modulerequest)
|
||||||
// FIXME: Implement 8.1.5.5.4 HostGetSupportedImportAssertions(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
|
// FIXME: Implement 8.1.5.5.4 HostGetSupportedImportAssertions(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
|
||||||
|
|
||||||
vm->host_resolve_imported_module = [](JS::ScriptOrModule, JS::ModuleRequest const&) -> JS::ThrowCompletionOr<NonnullRefPtr<JS::Module>> {
|
vm->host_resolve_imported_module = [](JS::ScriptOrModule, JS::ModuleRequest const&) -> JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>> {
|
||||||
return vm->throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Modules in the browser");
|
return vm->throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Modules in the browser");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue