summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r--Userland/Libraries/LibJS/AST.cpp42
-rw-r--r--Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp14
-rw-r--r--Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h26
3 files changed, 42 insertions, 40 deletions
diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp
index 512ec9e143..9b16c99711 100644
--- a/Userland/Libraries/LibJS/AST.cpp
+++ b/Userland/Libraries/LibJS/AST.cpp
@@ -714,7 +714,7 @@ Completion ForStatement::loop_evaluation(Interpreter& interpreter, GlobalObject&
interpreter.vm().running_execution_context().lexical_environment = old_environment;
};
- Vector<FlyString> let_declarations;
+ size_t per_iteration_bindings_size = 0;
if (m_init) {
if (is<VariableDeclaration>(*m_init) && static_cast<VariableDeclaration const&>(*m_init).declaration_kind() != DeclarationKind::Var) {
@@ -725,7 +725,7 @@ Completion ForStatement::loop_evaluation(Interpreter& interpreter, GlobalObject&
MUST(loop_environment->create_immutable_binding(global_object, name, true));
} else {
MUST(loop_environment->create_mutable_binding(global_object, name, false));
- let_declarations.append(name);
+ ++per_iteration_bindings_size;
}
});
@@ -739,44 +739,34 @@ Completion ForStatement::loop_evaluation(Interpreter& interpreter, GlobalObject&
// NOTE: Our implementation of this AO is heavily dependent on DeclarativeEnvironment using a Vector with constant indices.
// For performance, we can take advantage of the fact that the declarations of the initialization statement are created
// in the same order each time CreatePerIterationEnvironment is invoked.
- auto create_per_iteration_environment = [&]() -> ThrowCompletionOr<void> {
+ auto create_per_iteration_environment = [&]() {
// 1. If perIterationBindings has any elements, then
- if (let_declarations.is_empty())
- return {};
+ if (per_iteration_bindings_size == 0)
+ return;
// a. Let lastIterationEnv be the running execution context's LexicalEnvironment.
auto* last_iteration_env = verify_cast<DeclarativeEnvironment>(interpreter.lexical_environment());
// b. Let outer be lastIterationEnv.[[OuterEnv]].
- auto* outer = last_iteration_env->outer_environment();
-
// c. Assert: outer is not null.
- VERIFY(outer);
+ VERIFY(last_iteration_env->outer_environment());
// d. Let thisIterationEnv be NewDeclarativeEnvironment(outer).
- auto* this_iteration_env = new_declarative_environment(*outer);
- this_iteration_env->ensure_capacity(let_declarations.size());
+ auto this_iteration_env = DeclarativeEnvironment::create_for_per_iteration_bindings({}, *last_iteration_env, per_iteration_bindings_size);
// e. For each element bn of perIterationBindings, do
- for (size_t declaration_index = 0; declaration_index < let_declarations.size(); ++declaration_index) {
- auto const& name = let_declarations[declaration_index];
-
- // i. Perform ! thisIterationEnv.CreateMutableBinding(bn, false).
- MUST(this_iteration_env->create_mutable_binding(global_object, name, false));
-
- // ii. Let lastValue be ? lastIterationEnv.GetBindingValue(bn, true).
- auto last_value = TRY(last_iteration_env->get_binding_value_direct(global_object, declaration_index, true));
- VERIFY(!last_value.is_empty());
-
- // iii. Perform thisIterationEnv.InitializeBinding(bn, lastValue).
- MUST(this_iteration_env->initialize_binding_direct(global_object, declaration_index, last_value));
- }
+ // i. Perform ! thisIterationEnv.CreateMutableBinding(bn, false).
+ // ii. Let lastValue be ? lastIterationEnv.GetBindingValue(bn, true).
+ // iii. Perform ! thisIterationEnv.InitializeBinding(bn, lastValue).
+ //
+ // NOTE: This is handled by DeclarativeEnvironment::create_for_per_iteration_bindings. Step e.ii indicates it may throw,
+ // but that is not possible. The potential for throwing was added to accommodate support for do-expressions in the
+ // initialization statement, but that idea was dropped: https://github.com/tc39/ecma262/issues/299#issuecomment-172950045
// f. Set the running execution context's LexicalEnvironment to thisIterationEnv.
interpreter.vm().running_execution_context().lexical_environment = this_iteration_env;
// 2. Return undefined.
- return {};
};
// 14.7.4.3 ForBodyEvaluation ( test, increment, stmt, perIterationBindings, labelSet ), https://tc39.es/ecma262/#sec-forbodyevaluation
@@ -785,7 +775,7 @@ Completion ForStatement::loop_evaluation(Interpreter& interpreter, GlobalObject&
auto last_value = js_undefined();
// 2. Perform ? CreatePerIterationEnvironment(perIterationBindings).
- TRY(create_per_iteration_environment());
+ create_per_iteration_environment();
// 3. Repeat,
while (true) {
@@ -812,7 +802,7 @@ Completion ForStatement::loop_evaluation(Interpreter& interpreter, GlobalObject&
last_value = *result.value();
// e. Perform ? CreatePerIterationEnvironment(perIterationBindings).
- TRY(create_per_iteration_environment());
+ create_per_iteration_environment();
// f. If increment is not [empty], then
if (m_update) {
diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp
index ec61b3ca13..e3255d6e0d 100644
--- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp
+++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp
@@ -13,6 +13,14 @@
namespace JS {
+DeclarativeEnvironment* DeclarativeEnvironment::create_for_per_iteration_bindings(Badge<ForStatement>, DeclarativeEnvironment& other, size_t bindings_size)
+{
+ auto bindings = other.m_bindings.span().slice(0, bindings_size);
+ auto* parent_scope = other.outer_environment();
+
+ return parent_scope->heap().allocate_without_global_object<DeclarativeEnvironment>(parent_scope, bindings);
+}
+
DeclarativeEnvironment::DeclarativeEnvironment()
: Environment(nullptr)
{
@@ -23,6 +31,12 @@ DeclarativeEnvironment::DeclarativeEnvironment(Environment* parent_scope)
{
}
+DeclarativeEnvironment::DeclarativeEnvironment(Environment* parent_scope, Span<Binding const> bindings)
+ : Environment(parent_scope)
+ , m_bindings(bindings)
+{
+}
+
DeclarativeEnvironment::~DeclarativeEnvironment()
{
}
diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h
index 85d98298ca..d664fab136 100644
--- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h
+++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h
@@ -17,9 +17,21 @@ namespace JS {
class DeclarativeEnvironment : public Environment {
JS_ENVIRONMENT(DeclarativeEnvironment, Environment);
+ struct Binding {
+ FlyString name;
+ Value value;
+ bool strict { false };
+ bool mutable_ { false };
+ bool can_be_deleted { false };
+ bool initialized { false };
+ };
+
public:
+ static DeclarativeEnvironment* create_for_per_iteration_bindings(Badge<ForStatement>, DeclarativeEnvironment& other, size_t bindings_size);
+
DeclarativeEnvironment();
explicit DeclarativeEnvironment(Environment* parent_scope);
+ explicit DeclarativeEnvironment(Environment* parent_scope, Span<Binding const> bindings);
virtual ~DeclarativeEnvironment() override;
virtual ThrowCompletionOr<bool> has_binding(FlyString const& name, Optional<size_t>* = nullptr) const override;
@@ -49,11 +61,6 @@ public:
ThrowCompletionOr<Value> get_binding_value_direct(GlobalObject&, size_t index, bool strict);
ThrowCompletionOr<void> set_mutable_binding_direct(GlobalObject&, size_t index, Value, bool strict);
- void ensure_capacity(size_t capacity)
- {
- m_bindings.ensure_capacity(capacity);
- }
-
protected:
virtual void visit_edges(Visitor&) override;
@@ -71,15 +78,6 @@ private:
return it.index();
}
- struct Binding {
- FlyString name;
- Value value;
- bool strict { false };
- bool mutable_ { false };
- bool can_be_deleted { false };
- bool initialized { false };
- };
-
Vector<Binding> m_bindings;
};