LibJS: Save and restore exceptions on yields in finalizers

Also removes a bunch of related old FIXMEs.
This commit is contained in:
Hendiadyoin1 2024-05-06 22:38:43 +02:00 committed by Andreas Kling
commit af94e4c05d
Notes: sideshowbarker 2024-07-16 23:05:02 +09:00
4 changed files with 41 additions and 10 deletions

View file

@ -1782,6 +1782,12 @@ static void generate_yield(Bytecode::Generator& generator,
Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> YieldExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional<Bytecode::Operand> preferred_dst) const
{
// Note: We need to catch any scheduled exceptions and reschedule them on re-entry
// as the act of yielding would otherwise clear them out
// This only applies when we are in a finalizer
bool is_in_finalizer = generator.is_in_finalizer();
Optional<Bytecode::Register> saved_exception;
Bytecode::Generator::SourceLocationScope scope(generator, *this);
VERIFY(generator.is_in_generator_function());
@ -1890,6 +1896,11 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> YieldExpression::ge
auto current_value = Bytecode::Operand(generator.allocate_register());
generator.emit_iterator_value(current_value, inner_result);
if (is_in_finalizer) {
saved_exception = generator.allocate_register();
generator.emit<Bytecode::Op::Mov>(Bytecode::Operand(*saved_exception), Bytecode::Operand(Bytecode::Register::exception()));
}
generate_yield(generator,
Bytecode::Label { continuation_block },
current_value,
@ -2077,6 +2088,10 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> YieldExpression::ge
generate_yield(generator, Bytecode::Label { continuation_block }, received, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier, AwaitBeforeYield::No);
generator.switch_to_basic_block(continuation_block);
if (is_in_finalizer)
generator.emit<Bytecode::Op::Mov>(Bytecode::Operand(Bytecode::Register::exception()), Bytecode::Operand(*saved_exception));
generator.emit<Bytecode::Op::Mov>(received_completion, Bytecode::Operand(Bytecode::Register(0)));
get_received_completion_type_and_value(generator, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier);
generator.emit<Bytecode::Op::Jump>(Bytecode::Label { loop_block });
@ -2092,8 +2107,18 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> YieldExpression::ge
argument = generator.add_constant(js_undefined());
auto& continuation_block = generator.make_block();
if (is_in_finalizer) {
saved_exception = generator.allocate_register();
generator.emit<Bytecode::Op::Mov>(Bytecode::Operand(*saved_exception), Bytecode::Operand(Bytecode::Register::exception()));
}
generate_yield(generator, Bytecode::Label { continuation_block }, *argument, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier, AwaitBeforeYield::Yes);
generator.switch_to_basic_block(continuation_block);
if (is_in_finalizer)
generator.emit<Bytecode::Op::Mov>(Bytecode::Operand(Bytecode::Register::exception()), Bytecode::Operand(*saved_exception));
generator.emit<Bytecode::Op::Mov>(received_completion, Bytecode::Operand(Bytecode::Register(0)));
get_received_completion_type_and_value(generator, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier);
@ -2190,9 +2215,6 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> IfStatement::genera
Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> ContinueStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional<Bytecode::Operand> preferred_dst) const
{
Bytecode::Generator::SourceLocationScope scope(generator, *this);
// FIXME: Handle finally blocks in a graceful manner
// We need to execute the finally block, but tell it to resume
// execution at the designated block
if (!m_target_label.has_value()) {
generator.generate_continue();
return Optional<Bytecode::Operand> {};