diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index c5495762f4..f531bb5258 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -31,8 +31,6 @@ Interpreter::~Interpreter() void Interpreter::visit_edges(Cell::Visitor& visitor) { - if (m_return_value.has_value()) - visitor.visit(*m_return_value); for (auto& frame : m_call_frames) { frame.visit([&](auto& value) { value->visit_edges(visitor); }); } @@ -226,7 +224,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa will_jump = true; break; } - if (m_return_value.has_value()) { + if (!reg(Register::return_value()).is_empty()) { will_return = true; // Note: A `yield` statement will not go through a finally statement, // hence we need to set a flag to not do so, @@ -245,7 +243,8 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa if (!unwind_contexts().is_empty() && !will_yield) { auto& unwind_context = unwind_contexts().last(); if (unwind_context.executable == m_current_executable && unwind_context.finalizer) { - reg(Register::saved_return_value()) = m_return_value.release_value(); + reg(Register::saved_return_value()) = reg(Register::return_value()); + reg(Register::return_value()) = {}; m_current_block = unwind_context.finalizer; // the unwind_context will be pop'ed when entering the finally block continue; @@ -275,18 +274,15 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa } } - auto saved_return_value = reg(Register::saved_return_value()); + auto return_value = js_undefined(); + if (!reg(Register::return_value()).is_empty()) + return_value = reg(Register::return_value()); + else if (!reg(Register::saved_return_value()).is_empty()) + return_value = reg(Register::saved_return_value()); auto exception = reg(Register::exception()); auto frame = pop_call_frame(); - Value return_value = js_undefined(); - if (m_return_value.has_value()) { - return_value = m_return_value.release_value(); - } else if (!saved_return_value.is_empty()) { - return_value = saved_return_value; - } - // NOTE: The return value from a called function is put into $0 in the caller context. if (!m_call_frames.is_empty()) call_frame().registers[0] = return_value; @@ -374,6 +370,7 @@ void Interpreter::push_call_frame(Variant, CallFrame*> m_call_frames.append(move(frame)); this->call_frame().registers.resize(register_count); m_current_call_frame = this->call_frame().registers; + reg(Register::return_value()) = {}; } Variant, CallFrame*> Interpreter::pop_call_frame() diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index b27e5a6a5a..4729a2d8e7 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -74,9 +74,9 @@ public: VERIFY(unwind_contexts().last().finalizer); jump(Label { *unwind_contexts().last().finalizer }); } - void do_return(Value return_value) + void do_return(Value value) { - m_return_value = return_value; + reg(Register::return_value()) = value; reg(Register::exception()) = {}; } @@ -114,7 +114,6 @@ private: Span m_current_call_frame; Optional m_pending_jump; BasicBlock const* m_scheduled_jump { nullptr }; - Optional m_return_value; Executable* m_current_executable { nullptr }; BasicBlock const* m_current_block { nullptr }; Optional m_pc {}; diff --git a/Userland/Libraries/LibJS/Bytecode/Register.h b/Userland/Libraries/LibJS/Bytecode/Register.h index bb951852cc..0662f552e7 100644 --- a/Userland/Libraries/LibJS/Bytecode/Register.h +++ b/Userland/Libraries/LibJS/Bytecode/Register.h @@ -39,7 +39,13 @@ public: return Register(this_value_index); } - static constexpr u32 reserved_register_count = 4; + static constexpr Register return_value() + { + constexpr u32 return_value_index = 4; + return Register(return_value_index); + } + + static constexpr u32 reserved_register_count = 5; constexpr explicit Register(u32 index) : m_index(index)