1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-30 23:08:11 +00:00

LibJS: Keep return value in a call frame register

This commit is contained in:
Andreas Kling 2023-09-26 15:32:46 +02:00
parent c833885fb5
commit 0c746366cc
3 changed files with 18 additions and 16 deletions

View file

@ -31,8 +31,6 @@ Interpreter::~Interpreter()
void Interpreter::visit_edges(Cell::Visitor& visitor) void Interpreter::visit_edges(Cell::Visitor& visitor)
{ {
if (m_return_value.has_value())
visitor.visit(*m_return_value);
for (auto& frame : m_call_frames) { for (auto& frame : m_call_frames) {
frame.visit([&](auto& value) { value->visit_edges(visitor); }); frame.visit([&](auto& value) { value->visit_edges(visitor); });
} }
@ -226,7 +224,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
will_jump = true; will_jump = true;
break; break;
} }
if (m_return_value.has_value()) { if (!reg(Register::return_value()).is_empty()) {
will_return = true; will_return = true;
// Note: A `yield` statement will not go through a finally statement, // Note: A `yield` statement will not go through a finally statement,
// hence we need to set a flag to not do so, // 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) { if (!unwind_contexts().is_empty() && !will_yield) {
auto& unwind_context = unwind_contexts().last(); auto& unwind_context = unwind_contexts().last();
if (unwind_context.executable == m_current_executable && unwind_context.finalizer) { 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; m_current_block = unwind_context.finalizer;
// the unwind_context will be pop'ed when entering the finally block // the unwind_context will be pop'ed when entering the finally block
continue; 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 exception = reg(Register::exception());
auto frame = pop_call_frame(); 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. // NOTE: The return value from a called function is put into $0 in the caller context.
if (!m_call_frames.is_empty()) if (!m_call_frames.is_empty())
call_frame().registers[0] = return_value; call_frame().registers[0] = return_value;
@ -374,6 +370,7 @@ void Interpreter::push_call_frame(Variant<NonnullOwnPtr<CallFrame>, CallFrame*>
m_call_frames.append(move(frame)); m_call_frames.append(move(frame));
this->call_frame().registers.resize(register_count); this->call_frame().registers.resize(register_count);
m_current_call_frame = this->call_frame().registers; m_current_call_frame = this->call_frame().registers;
reg(Register::return_value()) = {};
} }
Variant<NonnullOwnPtr<CallFrame>, CallFrame*> Interpreter::pop_call_frame() Variant<NonnullOwnPtr<CallFrame>, CallFrame*> Interpreter::pop_call_frame()

View file

@ -74,9 +74,9 @@ public:
VERIFY(unwind_contexts().last().finalizer); VERIFY(unwind_contexts().last().finalizer);
jump(Label { *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()) = {}; reg(Register::exception()) = {};
} }
@ -114,7 +114,6 @@ private:
Span<Value> m_current_call_frame; Span<Value> m_current_call_frame;
Optional<BasicBlock const*> m_pending_jump; Optional<BasicBlock const*> m_pending_jump;
BasicBlock const* m_scheduled_jump { nullptr }; BasicBlock const* m_scheduled_jump { nullptr };
Optional<Value> m_return_value;
Executable* m_current_executable { nullptr }; Executable* m_current_executable { nullptr };
BasicBlock const* m_current_block { nullptr }; BasicBlock const* m_current_block { nullptr };
Optional<InstructionStreamIterator&> m_pc {}; Optional<InstructionStreamIterator&> m_pc {};

View file

@ -39,7 +39,13 @@ public:
return Register(this_value_index); 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) constexpr explicit Register(u32 index)
: m_index(index) : m_index(index)