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 cfdfec846c..012d369053 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 f2ca2b0050..54eb605215 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 ec1dbc729e..5d00a5fdf9 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 c6bff072ec..9cf9e47af1 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); }