diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 1dcdab6f2fd..10734e76d25 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -523,28 +523,6 @@ inline ThrowCompletionOr put_by_value(VM& vm, Value base, Optional get_variable(Bytecode::Interpreter& interpreter, DeprecatedFlyString const& name, EnvironmentVariableCache& cache) -{ - auto& vm = interpreter.vm(); - - if (cache.has_value()) { - auto environment = vm.running_execution_context().lexical_environment; - for (size_t i = 0; i < cache->hops; ++i) - environment = environment->outer_environment(); - VERIFY(environment); - VERIFY(environment->is_declarative_environment()); - if (!environment->is_permanently_screwed_by_eval()) { - return TRY(verify_cast(*environment).get_binding_value_direct(vm, cache.value().index, vm.in_strict_mode())); - } - cache = {}; - } - - auto reference = TRY(vm.resolve_binding(name)); - if (reference.environment_coordinate().has_value()) - cache = reference.environment_coordinate(); - return TRY(reference.get_value(vm)); -} - struct CalleeAndThis { Value callee; Value this_value; @@ -558,13 +536,11 @@ inline ThrowCompletionOr get_callee_and_this_from_environment(Byt Value this_value = js_undefined(); if (cache.has_value()) { - auto environment = vm.running_execution_context().lexical_environment; + auto const* environment = vm.running_execution_context().lexical_environment.ptr(); for (size_t i = 0; i < cache->hops; ++i) environment = environment->outer_environment(); - VERIFY(environment); - VERIFY(environment->is_declarative_environment()); if (!environment->is_permanently_screwed_by_eval()) { - callee = TRY(verify_cast(*environment).get_binding_value_direct(vm, cache.value().index, vm.in_strict_mode())); + callee = TRY(static_cast(*environment).get_binding_value_direct(vm, cache.value().index)); this_value = js_undefined(); if (auto base_object = environment->with_base_object()) this_value = base_object; diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 3d3c844d62c..d9585894f10 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1232,7 +1232,25 @@ ThrowCompletionOr ConcatString::execute_impl(Bytecode::Interpreter& interp ThrowCompletionOr GetVariable::execute_impl(Bytecode::Interpreter& interpreter) const { - interpreter.set(dst(), TRY(get_variable(interpreter, interpreter.current_executable().get_identifier(m_identifier), interpreter.current_executable().environment_variable_caches[m_cache_index]))); + auto& vm = interpreter.vm(); + auto& executable = interpreter.current_executable(); + auto& cache = executable.environment_variable_caches[m_cache_index]; + + if (cache.has_value()) { + auto const* environment = vm.running_execution_context().lexical_environment.ptr(); + for (size_t i = 0; i < cache->hops; ++i) + environment = environment->outer_environment(); + if (!environment->is_permanently_screwed_by_eval()) { + interpreter.set(dst(), TRY(static_cast(*environment).get_binding_value_direct(vm, cache.value().index))); + return {}; + } + cache = {}; + } + + auto reference = TRY(vm.resolve_binding(executable.get_identifier(m_identifier))); + if (reference.environment_coordinate().has_value()) + cache = reference.environment_coordinate(); + interpreter.set(dst(), TRY(reference.get_value(vm))); return {}; } diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp index f901c2ca8ab..8e30f69bbf0 100644 --- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp +++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp @@ -182,29 +182,14 @@ ThrowCompletionOr DeclarativeEnvironment::set_mutable_binding_direct(VM& v } // 9.1.1.1.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s -ThrowCompletionOr DeclarativeEnvironment::get_binding_value(VM& vm, DeprecatedFlyString const& name, bool strict) +ThrowCompletionOr DeclarativeEnvironment::get_binding_value(VM& vm, DeprecatedFlyString const& name, [[maybe_unused]] bool strict) { // 1. Assert: envRec has a binding for N. auto binding_and_index = find_binding_and_index(name); VERIFY(binding_and_index.has_value()); // 2-3. (extracted into a non-standard function below) - return get_binding_value_direct(vm, binding_and_index->binding(), strict); -} - -ThrowCompletionOr DeclarativeEnvironment::get_binding_value_direct(VM& vm, size_t index, bool strict) -{ - return get_binding_value_direct(vm, m_bindings[index], strict); -} - -ThrowCompletionOr DeclarativeEnvironment::get_binding_value_direct(VM&, Binding& binding, bool) -{ - // 2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception. - if (!binding.initialized) - return vm().throw_completion(ErrorType::BindingNotInitialized, binding.name); - - // 3. Return the value currently bound to N in envRec. - return binding.value; + return get_binding_value_direct(vm, binding_and_index->binding()); } // 9.1.1.1.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h index 5cd04192e38..dea181b219b 100644 --- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h +++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h @@ -57,7 +57,7 @@ public: } ThrowCompletionOr set_mutable_binding_direct(VM&, size_t index, Value, bool strict); - ThrowCompletionOr get_binding_value_direct(VM&, size_t index, bool strict); + ThrowCompletionOr get_binding_value_direct(VM&, size_t index) const; void shrink_to_fit(); @@ -69,7 +69,7 @@ public: [[nodiscard]] u64 environment_serial_number() const { return m_environment_serial_number; } private: - ThrowCompletionOr get_binding_value_direct(VM&, Binding&, bool strict); + ThrowCompletionOr get_binding_value_direct(VM&, Binding const&) const; ThrowCompletionOr set_mutable_binding_direct(VM&, Binding&, Value, bool strict); friend Completion dispose_resources(VM&, GCPtr, Completion); @@ -131,6 +131,21 @@ private: u64 m_environment_serial_number { 0 }; }; +inline ThrowCompletionOr DeclarativeEnvironment::get_binding_value_direct(VM& vm, size_t index) const +{ + return get_binding_value_direct(vm, m_bindings[index]); +} + +inline ThrowCompletionOr DeclarativeEnvironment::get_binding_value_direct(VM&, Binding const& binding) const +{ + // 2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception. + if (!binding.initialized) + return vm().throw_completion(ErrorType::BindingNotInitialized, binding.name); + + // 3. Return the value currently bound to N in envRec. + return binding.value; +} + template<> inline bool Environment::fast_is() const { return is_declarative_environment(); } diff --git a/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp index c0d5512bc61..85ab24ea7c0 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp @@ -119,7 +119,7 @@ ThrowCompletionOr GlobalEnvironment::get_binding_value(VM& vm, Deprecated if (MUST(m_declarative_record->has_binding(name, &index))) { // a. Return ? DclRec.GetBindingValue(N, S). if (index.has_value()) - return m_declarative_record->get_binding_value_direct(vm, index.value(), strict); + return m_declarative_record->get_binding_value_direct(vm, index.value()); return m_declarative_record->get_binding_value(vm, name, strict); } diff --git a/Userland/Libraries/LibJS/Runtime/Reference.cpp b/Userland/Libraries/LibJS/Runtime/Reference.cpp index 7279a55e76d..008b069a25a 100644 --- a/Userland/Libraries/LibJS/Runtime/Reference.cpp +++ b/Userland/Libraries/LibJS/Runtime/Reference.cpp @@ -142,7 +142,7 @@ ThrowCompletionOr Reference::get_value(VM& vm) const // c. Return ? base.GetBindingValue(V.[[ReferencedName]], V.[[Strict]]) (see 9.1). if (m_environment_coordinate.has_value()) - return static_cast(m_base_environment)->get_binding_value_direct(vm, m_environment_coordinate->index, m_strict); + return static_cast(m_base_environment)->get_binding_value_direct(vm, m_environment_coordinate->index); return m_base_environment->get_binding_value(vm, m_name.as_string(), m_strict); }