diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 41a1da612b3..667f57a940f 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -389,24 +389,6 @@ inline ThrowCompletionOr throw_if_needed_for_call(Interpreter& interpreter return {}; } -inline ThrowCompletionOr typeof_binding(VM& vm, DeprecatedFlyString const& string) -{ - // 1. Let val be the result of evaluating UnaryExpression. - auto reference = TRY(vm.resolve_binding(string)); - - // 2. If val is a Reference Record, then - // a. If IsUnresolvableReference(val) is true, return "undefined". - if (reference.is_unresolvable()) - return PrimitiveString::create(vm, "undefined"_string); - - // 3. Set val to ? GetValue(val). - auto value = TRY(reference.get_value(vm)); - - // 4. NOTE: This step is replaced in section B.3.6.3. - // 5. Return a String according to Table 41. - return PrimitiveString::create(vm, value.typeof()); -} - inline Value new_function(VM& vm, FunctionNode const& function_node, Optional const& lhs_name, Optional const& home_object) { Value value; diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 45bfe7f6f9d..938d353893c 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1976,7 +1976,38 @@ ThrowCompletionOr NewClass::execute_impl(Bytecode::Interpreter& interprete ThrowCompletionOr TypeofBinding::execute_impl(Bytecode::Interpreter& interpreter) const { auto& vm = interpreter.vm(); - interpreter.set(dst(), TRY(typeof_binding(vm, interpreter.current_executable().get_identifier(m_identifier)))); + + if (m_cache.is_valid()) { + auto const* environment = interpreter.running_execution_context().lexical_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 = TRY(static_cast(*environment).get_binding_value_direct(vm, m_cache.index)); + interpreter.set(dst(), PrimitiveString::create(vm, value.typeof())); + return {}; + } + m_cache = {}; + } + + // 1. Let val be the result of evaluating UnaryExpression. + auto reference = TRY(vm.resolve_binding(interpreter.current_executable().get_identifier(m_identifier))); + + // 2. If val is a Reference Record, then + // a. If IsUnresolvableReference(val) is true, return "undefined". + if (reference.is_unresolvable()) { + interpreter.set(dst(), PrimitiveString::create(vm, "undefined"_string)); + return {}; + } + + // 3. Set val to ? GetValue(val). + auto value = TRY(reference.get_value(vm)); + + if (reference.environment_coordinate().has_value()) + m_cache = reference.environment_coordinate().value(); + + // 4. NOTE: This step is replaced in section B.3.6.3. + // 5. Return a String according to Table 41. + interpreter.set(dst(), PrimitiveString::create(vm, value.typeof())); return {}; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index f50ef25ffa2..0c34724c6f2 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -2645,6 +2645,7 @@ public: private: Operand m_dst; IdentifierTableIndex m_identifier; + mutable EnvironmentCoordinate m_cache; }; class End final : public Instruction {