Ver Fonte

LibJS/Bytecode: Add environment coordinate caching to SetVariable

This means that SetVariable instructions will now remember which
(relative) environment contains the targeted binding, letting it bypass
the full binding resolution machinery on subsequent accesses.
Andreas Kling há 1 ano atrás
pai
commit
ed50eb0aaa

+ 19 - 0
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

@@ -1379,6 +1379,25 @@ ThrowCompletionOr<void> CreateArguments::execute_impl(Bytecode::Interpreter& int
 ThrowCompletionOr<void> SetVariable::execute_impl(Bytecode::Interpreter& interpreter) const
 {
     auto& vm = interpreter.vm();
+
+    if (m_cache.is_valid()) {
+        auto* environment = m_mode == EnvironmentMode::Lexical
+            ? interpreter.running_execution_context().lexical_environment.ptr()
+            : interpreter.running_execution_context().variable_environment.ptr();
+        for (size_t i = 0; i < m_cache.hops; ++i)
+            environment = environment->outer_environment();
+        if (!environment->is_permanently_screwed_by_eval()) {
+            auto value = interpreter.get(src());
+            if (m_initialization_mode == InitializationMode::Initialize) {
+                TRY(static_cast<DeclarativeEnvironment&>(*environment).initialize_binding_direct(vm, m_cache.index, value, Environment::InitializeBindingHint::Normal));
+                return {};
+            }
+            TRY(static_cast<DeclarativeEnvironment&>(*environment).set_mutable_binding_direct(vm, m_cache.index, value, vm.in_strict_mode()));
+            return {};
+        }
+        m_cache = {};
+    }
+
     auto const& name = interpreter.current_executable().get_identifier(m_identifier);
     TRY(set_variable(vm,
         name,

+ 6 - 3
Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp

@@ -110,9 +110,12 @@ ThrowCompletionOr<void> DeclarativeEnvironment::create_immutable_binding(VM&, De
 // 4.1.1.1.1 InitializeBinding ( N, V, hint ), https://tc39.es/proposal-explicit-resource-management/#sec-declarative-environment-records
 ThrowCompletionOr<void> DeclarativeEnvironment::initialize_binding(VM& vm, DeprecatedFlyString const& name, Value value, Environment::InitializeBindingHint hint)
 {
-    auto binding_and_index = find_binding_and_index(name);
-    VERIFY(binding_and_index.has_value());
-    auto& binding = binding_and_index->binding();
+    return initialize_binding_direct(vm, find_binding_and_index(name)->index().value(), value, hint);
+}
+
+ThrowCompletionOr<void> DeclarativeEnvironment::initialize_binding_direct(VM& vm, size_t index, Value value, Environment::InitializeBindingHint hint)
+{
+    auto& binding = m_bindings.at(index);
 
     // 1. Assert: envRec must have an uninitialized binding for N.
     VERIFY(binding.initialized == false);

+ 1 - 0
Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h

@@ -56,6 +56,7 @@ public:
         return names;
     }
 
+    ThrowCompletionOr<void> initialize_binding_direct(VM&, size_t index, Value, InitializeBindingHint);
     ThrowCompletionOr<void> set_mutable_binding_direct(VM&, size_t index, Value, bool strict);
     ThrowCompletionOr<Value> get_binding_value_direct(VM&, size_t index) const;