1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-21 15:35:07 +00:00

LibJS: Intercept returns through finally blocks in Bytecode

This is still not perfect, as we now actually crash in the
`try-finally-continue` tests, while we now succeed all
`try-catch-finally-*` tests.

Note that we do not yet go through the finally block when exiting the
unwind context through a break or continue.
This commit is contained in:
Hendiadyoin1 2022-11-13 20:56:53 +01:00 committed by Ali Mohammad Pur
parent c2108489a5
commit fcc3348bc8
5 changed files with 81 additions and 9 deletions

View file

@ -117,14 +117,28 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
++pc;
}
if (will_return)
break;
if (will_jump)
continue;
if (pc.at_end() && !will_jump)
if (!unwind_contexts().is_empty()) {
auto& unwind_context = unwind_contexts().last();
if (unwind_context.executable == m_current_executable && unwind_context.finalizer) {
m_saved_return_value = make_handle(m_return_value);
m_return_value = {};
m_current_block = unwind_context.finalizer;
// the unwind_context will be pop'ed when entering the finally block
continue;
}
}
if (pc.at_end())
break;
if (!m_saved_exception.is_null())
break;
if (will_return)
break;
}
dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter did run unit {:p}", &executable);
@ -142,8 +156,14 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
auto frame = m_register_windows.take_last();
auto return_value = m_return_value.value_or(js_undefined());
m_return_value = {};
Value return_value = js_undefined();
if (!m_return_value.is_empty()) {
return_value = m_return_value;
m_return_value = {};
} else if (!m_saved_return_value.is_null()) {
return_value = m_saved_return_value.value();
m_saved_return_value = {};
}
// NOTE: The return value from a called function is put into $0 in the caller context.
if (!m_register_windows.is_empty())
@ -168,7 +188,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
return { throw_completion(thrown_value), nullptr };
}
if (auto register_window = frame.get_pointer<NonnullOwnPtr<RegisterWindow>>())
if (auto* register_window = frame.get_pointer<NonnullOwnPtr<RegisterWindow>>())
return { return_value, move(*register_window) };
return { return_value, nullptr };
}
@ -191,6 +211,12 @@ ThrowCompletionOr<void> Interpreter::continue_pending_unwind(Label const& resume
return result;
}
if (!m_saved_return_value.is_null()) {
do_return(m_saved_return_value.value());
m_saved_return_value = {};
return {};
}
jump(resume_label);
return {};
}