diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index c818d9c527..b747ce9b2e 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -208,6 +208,8 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu else push_call_frame(make(), executable.number_of_registers); + TemporaryChange restore_this_value { m_this_value, {} }; + for (;;) { Bytecode::InstructionStreamIterator pc(m_current_block->instruction_stream()); TemporaryChange temp_change { m_pc, &pc }; diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index dfd57fe936..1c4e05883a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -95,6 +95,8 @@ public: VM::InterpreterExecutionScope ast_interpreter_scope(Realm&); + Optional& this_value() { return m_this_value; } + void visit_edges(Cell::Visitor&); private: @@ -119,6 +121,7 @@ private: Span m_current_call_frame; Optional m_pending_jump; BasicBlock const* m_scheduled_jump { nullptr }; + Optional m_this_value; Optional m_return_value; Optional m_saved_exception; Executable* m_current_executable { nullptr }; diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 1e37fd6aee..164ed5b829 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -732,8 +732,13 @@ ThrowCompletionOr Jump::execute_impl(Bytecode::Interpreter& interpreter) c ThrowCompletionOr ResolveThisBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - auto& vm = interpreter.vm(); - interpreter.accumulator() = TRY(vm.resolve_this_binding()); + if (!interpreter.this_value().has_value()) { + // OPTIMIZATION: Because the value of 'this' cannot be reassigned during a function execution, it's + // resolved once and then saved for subsequent use. + auto& vm = interpreter.vm(); + interpreter.this_value() = TRY(vm.resolve_this_binding()); + } + interpreter.accumulator() = interpreter.this_value().value(); return {}; }