From d7e5a2058d6ad0412aa4d018f1d7084ff1ce279e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 10 Nov 2022 20:55:03 +0100 Subject: [PATCH] LibJS: Cache access to bindings in the global environment This patch adds a special EnvironmentCoordinate::global_marker value that signifies that a binding lookup ended up searching the global environment. It doesn't matter if we find it there or not, the global marker is always returned. This allows us to bypass other environments on subsequent access, going directly to the global environment. --- Userland/Libraries/LibJS/AST.cpp | 15 ++++++++++----- .../LibJS/Runtime/EnvironmentCoordinate.h | 2 ++ .../Libraries/LibJS/Runtime/GlobalEnvironment.cpp | 5 ++++- Userland/Libraries/LibJS/Runtime/Reference.cpp | 4 ++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index cfdfec846c4..012d3690539 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -1376,11 +1376,16 @@ ThrowCompletionOr Expression::to_reference(Interpreter&) const ThrowCompletionOr Identifier::to_reference(Interpreter& interpreter) const { if (m_cached_environment_coordinate.has_value()) { - auto* environment = interpreter.vm().running_execution_context().lexical_environment; - for (size_t i = 0; i < m_cached_environment_coordinate->hops; ++i) - environment = environment->outer_environment(); - VERIFY(environment); - VERIFY(environment->is_declarative_environment()); + Environment* environment = nullptr; + if (m_cached_environment_coordinate->index == EnvironmentCoordinate::global_marker) { + environment = &interpreter.vm().current_realm()->global_environment(); + } else { + environment = interpreter.vm().running_execution_context().lexical_environment; + for (size_t i = 0; i < m_cached_environment_coordinate->hops; ++i) + environment = environment->outer_environment(); + VERIFY(environment); + VERIFY(environment->is_declarative_environment()); + } if (!environment->is_permanently_screwed_by_eval()) { return Reference { *environment, string(), interpreter.vm().in_strict_mode(), m_cached_environment_coordinate }; } diff --git a/Userland/Libraries/LibJS/Runtime/EnvironmentCoordinate.h b/Userland/Libraries/LibJS/Runtime/EnvironmentCoordinate.h index f2ca2b00505..54eb605215e 100644 --- a/Userland/Libraries/LibJS/Runtime/EnvironmentCoordinate.h +++ b/Userland/Libraries/LibJS/Runtime/EnvironmentCoordinate.h @@ -14,6 +14,8 @@ namespace JS { struct EnvironmentCoordinate { size_t hops { 0 }; size_t index { 0 }; + + static constexpr size_t global_marker = 0xffffffff; }; } diff --git a/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp index ec1dbc729e4..5d00a5fdf93 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp @@ -39,8 +39,11 @@ ThrowCompletionOr GlobalEnvironment::get_this_binding(VM&) const } // 9.1.1.4.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-global-environment-records-hasbinding-n -ThrowCompletionOr GlobalEnvironment::has_binding(FlyString const& name, Optional*) const +ThrowCompletionOr GlobalEnvironment::has_binding(FlyString const& name, Optional* out_index) const { + if (out_index) + *out_index = EnvironmentCoordinate::global_marker; + // 1. Let DclRec be envRec.[[DeclarativeRecord]]. // 2. If ! DclRec.HasBinding(N) is true, return true. if (MUST(m_declarative_record->has_binding(name))) diff --git a/Userland/Libraries/LibJS/Runtime/Reference.cpp b/Userland/Libraries/LibJS/Runtime/Reference.cpp index c6bff072eca..9cf9e47af12 100644 --- a/Userland/Libraries/LibJS/Runtime/Reference.cpp +++ b/Userland/Libraries/LibJS/Runtime/Reference.cpp @@ -68,7 +68,7 @@ ThrowCompletionOr Reference::put_value(VM& vm, Value value) VERIFY(m_base_environment); // c. Return ? base.SetMutableBinding(V.[[ReferencedName]], W, V.[[Strict]]) (see 9.1). - if (m_environment_coordinate.has_value()) + if (m_environment_coordinate.has_value() && m_environment_coordinate->index != EnvironmentCoordinate::global_marker) return static_cast(m_base_environment)->set_mutable_binding_direct(vm, m_environment_coordinate->index, value, m_strict); else return m_base_environment->set_mutable_binding(vm, m_name.as_string(), value, m_strict); @@ -138,7 +138,7 @@ ThrowCompletionOr Reference::get_value(VM& vm) const VERIFY(m_base_environment); // c. Return ? base.GetBindingValue(V.[[ReferencedName]], V.[[Strict]]) (see 9.1). - if (m_environment_coordinate.has_value()) + if (m_environment_coordinate.has_value() && m_environment_coordinate->index != EnvironmentCoordinate::global_marker) return static_cast(m_base_environment)->get_binding_value_direct(vm, m_environment_coordinate->index, m_strict); return m_base_environment->get_binding_value(vm, m_name.as_string(), m_strict); }