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:
parent
c2108489a5
commit
fcc3348bc8
5 changed files with 81 additions and 9 deletions
|
@ -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 {};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue