1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-18 21:35:06 +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)
{
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<NonnullOwnPtr<CallFrame>, 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<NonnullOwnPtr<CallFrame>, CallFrame*> Interpreter::pop_call_frame()