summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2022-02-12 19:48:45 +0330
committerLinus Groh <mail@linusgroh.de>2022-02-13 14:41:33 +0000
commit1bbfaf8627112438ee177d4b0986970755e958bb (patch)
tree2cb98a6219120904fddc34c0ea8c9a00a8af7b22 /Userland/Libraries/LibJS/Runtime
parentc7e6b65fd299e60385179f40a2cadee1fc28f77e (diff)
downloadserenity-1bbfaf8627112438ee177d4b0986970755e958bb.zip
LibJS: More properly implement scoping rules in bytecode codegen
Now we emit CreateVariable and SetVariable with the appropriate initialization/environment modes, much closer to the spec. This makes a whole lot of things like let/const variables, function and variable hoisting and some other things work :^)
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
-rw-r--r--Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp12
-rw-r--r--Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp16
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorObject.h2
5 files changed, 21 insertions, 12 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp
index 214f1a28c6..17e126ffd0 100644
--- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp
+++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp
@@ -196,15 +196,21 @@ ThrowCompletionOr<bool> DeclarativeEnvironment::delete_binding(GlobalObject&, Fl
return true;
}
-void DeclarativeEnvironment::initialize_or_set_mutable_binding(Badge<ScopeNode>, GlobalObject& global_object, FlyString const& name, Value value)
+ThrowCompletionOr<void> DeclarativeEnvironment::initialize_or_set_mutable_binding(GlobalObject& global_object, FlyString const& name, Value value)
{
auto it = m_names.find(name);
VERIFY(it != m_names.end());
auto& binding = m_bindings[it->value];
if (!binding.initialized)
- MUST(initialize_binding(global_object, name, value));
+ TRY(initialize_binding(global_object, name, value));
else
- MUST(set_mutable_binding(global_object, name, value, false));
+ TRY(set_mutable_binding(global_object, name, value, false));
+ return {};
+}
+
+void DeclarativeEnvironment::initialize_or_set_mutable_binding(Badge<ScopeNode>, GlobalObject& global_object, FlyString const& name, Value value)
+{
+ MUST(initialize_or_set_mutable_binding(global_object, name, value));
}
Vector<String> DeclarativeEnvironment::bindings() const
diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h
index 934c14400d..4da324a0d8 100644
--- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h
+++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h
@@ -31,6 +31,7 @@ public:
virtual ThrowCompletionOr<bool> delete_binding(GlobalObject&, FlyString const& name) override;
void initialize_or_set_mutable_binding(Badge<ScopeNode>, GlobalObject& global_object, FlyString const& name, Value value);
+ ThrowCompletionOr<void> initialize_or_set_mutable_binding(GlobalObject& global_object, FlyString const& name, Value value);
// This is not a method defined in the spec! Do not use this in any LibJS (or other spec related) code.
[[nodiscard]] Vector<String> bindings() const;
diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp
index 65e29633a0..17423a6cae 100644
--- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp
@@ -542,14 +542,16 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
if (!scope_body)
return {};
- scope_body->for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
- declaration.for_each_bound_name([&](auto const& name) {
- if (declaration.is_constant_declaration())
- MUST(lex_environment->create_immutable_binding(global_object(), name, true));
- else
- MUST(lex_environment->create_mutable_binding(global_object(), name, false));
+ if (!Bytecode::Interpreter::current()) {
+ scope_body->for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
+ declaration.for_each_bound_name([&](auto const& name) {
+ if (declaration.is_constant_declaration())
+ MUST(lex_environment->create_immutable_binding(global_object(), name, true));
+ else
+ MUST(lex_environment->create_mutable_binding(global_object(), name, false));
+ });
});
- });
+ }
auto* private_environment = callee_context.private_environment;
for (auto& declaration : functions_to_initialize) {
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
index 78d35700cd..6644e0092d 100644
--- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
@@ -97,7 +97,7 @@ ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global
VERIFY(!m_generating_function->bytecode_executable()->basic_blocks.find_if([next_block](auto& block) { return block == next_block; }).is_end());
// Restore the snapshot registers
- bytecode_interpreter->enter_frame(m_frame);
+ bytecode_interpreter->enter_frame(*m_frame);
// Temporarily switch to the captured execution context
TRY(vm.push_execution_context(m_execution_context, global_object));
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.h b/Userland/Libraries/LibJS/Runtime/GeneratorObject.h
index 29ea61ff4d..dd84506528 100644
--- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.h
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.h
@@ -29,7 +29,7 @@ private:
ExecutionContext m_execution_context;
ECMAScriptFunctionObject* m_generating_function { nullptr };
Value m_previous_value;
- Bytecode::RegisterWindow m_frame;
+ Optional<Bytecode::RegisterWindow> m_frame;
bool m_done { false };
};