mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 03:55:24 +00:00
LibJS/Bytecode: Store unwind contexts inside RegisterWindow
Unwind contexts need to be preserved as we exit and re-enter a generator. For example, this would previously crash when returning from the try statement after yielding as we lost the unwind context when yielding, but still have a LeaveUnwindContext instruction from running `perform_needed_unwinds` when generating the return statement. ```js function* a() { try { return (yield 1); } catch {} } iter = a(); iter.next(); iter.next(); ```
This commit is contained in:
parent
b914680f0c
commit
277132f70d
Notes:
sideshowbarker
2024-07-17 04:01:41 +09:00
Author: https://github.com/Lubrsi Commit: https://github.com/SerenityOS/serenity/commit/277132f70d Pull-request: https://github.com/SerenityOS/serenity/pull/16196
2 changed files with 9 additions and 8 deletions
|
@ -65,7 +65,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
|
|||
if (in_frame)
|
||||
m_register_windows.append(in_frame);
|
||||
else
|
||||
m_register_windows.append(make<RegisterWindow>(MarkedVector<Value>(vm().heap()), MarkedVector<Environment*>(vm().heap()), MarkedVector<Environment*>(vm().heap())));
|
||||
m_register_windows.append(make<RegisterWindow>(MarkedVector<Value>(vm().heap()), MarkedVector<Environment*>(vm().heap()), MarkedVector<Environment*>(vm().heap()), Vector<UnwindInfo> {}));
|
||||
|
||||
registers().resize(executable.number_of_registers);
|
||||
|
||||
|
@ -81,9 +81,9 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
|
|||
if (ran_or_error.is_error()) {
|
||||
auto exception_value = *ran_or_error.throw_completion().value();
|
||||
m_saved_exception = make_handle(exception_value);
|
||||
if (m_unwind_contexts.is_empty())
|
||||
if (unwind_contexts().is_empty())
|
||||
break;
|
||||
auto& unwind_context = m_unwind_contexts.last();
|
||||
auto& unwind_context = unwind_contexts().last();
|
||||
if (unwind_context.executable != m_current_executable)
|
||||
break;
|
||||
if (unwind_context.handler) {
|
||||
|
@ -92,7 +92,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
|
|||
|
||||
// If there's no finalizer, there's nowhere for the handler block to unwind to, so the unwind context is no longer needed.
|
||||
if (!unwind_context.finalizer)
|
||||
m_unwind_contexts.take_last();
|
||||
unwind_contexts().take_last();
|
||||
|
||||
accumulator() = exception_value;
|
||||
m_saved_exception = {};
|
||||
|
@ -101,7 +101,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
|
|||
}
|
||||
if (unwind_context.finalizer) {
|
||||
m_current_block = unwind_context.finalizer;
|
||||
m_unwind_contexts.take_last();
|
||||
unwind_contexts().take_last();
|
||||
will_jump = true;
|
||||
break;
|
||||
}
|
||||
|
@ -179,12 +179,12 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
|
|||
|
||||
void Interpreter::enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target)
|
||||
{
|
||||
m_unwind_contexts.empend(m_current_executable, handler_target.has_value() ? &handler_target->block() : nullptr, finalizer_target.has_value() ? &finalizer_target->block() : nullptr);
|
||||
unwind_contexts().empend(m_current_executable, handler_target.has_value() ? &handler_target->block() : nullptr, finalizer_target.has_value() ? &finalizer_target->block() : nullptr);
|
||||
}
|
||||
|
||||
void Interpreter::leave_unwind_context()
|
||||
{
|
||||
m_unwind_contexts.take_last();
|
||||
unwind_contexts().take_last();
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> Interpreter::continue_pending_unwind(Label const& resume_label)
|
||||
|
|
|
@ -22,6 +22,7 @@ struct RegisterWindow {
|
|||
MarkedVector<Value> registers;
|
||||
MarkedVector<Environment*> saved_lexical_environments;
|
||||
MarkedVector<Environment*> saved_variable_environments;
|
||||
Vector<UnwindInfo> unwind_contexts;
|
||||
};
|
||||
|
||||
class Interpreter {
|
||||
|
@ -52,6 +53,7 @@ public:
|
|||
|
||||
auto& saved_lexical_environment_stack() { return window().saved_lexical_environments; }
|
||||
auto& saved_variable_environment_stack() { return window().saved_variable_environments; }
|
||||
auto& unwind_contexts() { return window().unwind_contexts; }
|
||||
|
||||
void jump(Label const& label)
|
||||
{
|
||||
|
@ -98,7 +100,6 @@ private:
|
|||
Optional<BasicBlock const*> m_pending_jump;
|
||||
Value m_return_value;
|
||||
Executable const* m_current_executable { nullptr };
|
||||
Vector<UnwindInfo> m_unwind_contexts;
|
||||
Handle<Value> m_saved_exception;
|
||||
OwnPtr<JS::Interpreter> m_ast_interpreter;
|
||||
BasicBlock const* m_current_block { nullptr };
|
||||
|
|
Loading…
Add table
Reference in a new issue