diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index e4f2bb925d..0e00457160 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -1207,10 +1207,13 @@ Bytecode::CodeGenerationErrorOr ReturnStatement::generate_bytecode(Bytecod if (m_argument) TRY(m_argument->generate_bytecode(generator)); - if (generator.is_in_generator_or_async_function()) + if (generator.is_in_generator_or_async_function()) { + generator.perform_needed_unwinds(); generator.emit(nullptr); - else + } else { + generator.perform_needed_unwinds(); generator.emit(); + } return {}; } @@ -1279,6 +1282,7 @@ Bytecode::CodeGenerationErrorOr IfStatement::generate_bytecode(Bytecode::G Bytecode::CodeGenerationErrorOr ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const { + generator.perform_needed_unwinds(); generator.emit().set_targets( generator.nearest_continuable_scope(), {}); @@ -1438,6 +1442,7 @@ Bytecode::CodeGenerationErrorOr ThrowStatement::generate_bytecode(Bytecode Bytecode::CodeGenerationErrorOr BreakStatement::generate_bytecode(Bytecode::Generator& generator) const { + generator.perform_needed_unwinds(true); generator.emit().set_targets( generator.nearest_breakable_scope(), {}); @@ -1502,6 +1507,7 @@ Bytecode::CodeGenerationErrorOr TryStatement::generate_bytecode(Bytecode:: auto& target_block = generator.make_block(); generator.switch_to_basic_block(saved_block); generator.emit(Bytecode::Label { target_block }, handler_target, finalizer_target); + generator.start_boundary(Bytecode::Generator::BlockBoundaryType::Unwind); generator.switch_to_basic_block(target_block); TRY(m_block->generate_bytecode(generator)); @@ -1514,6 +1520,7 @@ Bytecode::CodeGenerationErrorOr TryStatement::generate_bytecode(Bytecode:: next_block = █ } } + generator.end_boundary(Bytecode::Generator::BlockBoundaryType::Unwind); generator.switch_to_basic_block(next_block ? *next_block : saved_block); return {}; diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index f515bd5f13..cc79dde944 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -79,11 +79,13 @@ Label Generator::nearest_continuable_scope() const void Generator::begin_continuable_scope(Label continue_target) { m_continuable_scopes.append(continue_target); + start_boundary(BlockBoundaryType::Continue); } void Generator::end_continuable_scope() { m_continuable_scopes.take_last(); + end_boundary(BlockBoundaryType::Continue); } Label Generator::nearest_breakable_scope() const { @@ -92,11 +94,13 @@ Label Generator::nearest_breakable_scope() const void Generator::begin_breakable_scope(Label breakable_target) { m_breakable_scopes.append(breakable_target); + start_boundary(BlockBoundaryType::Break); } void Generator::end_breakable_scope() { m_breakable_scopes.take_last(); + end_boundary(BlockBoundaryType::Break); } CodeGenerationErrorOr Generator::emit_load_from_reference(JS::ASTNode const& node) diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index e36adb598d..80db80d34f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -171,6 +171,36 @@ public: } } + enum class BlockBoundaryType { + Break, + Continue, + Unwind, + }; + template + void perform_needed_unwinds(bool is_break_node = false) requires(OpType::IsTerminator) + { + Optional boundary_to_stop_at; + if constexpr (IsSame || IsSame) + VERIFY(!is_break_node); + else + boundary_to_stop_at = is_break_node ? BlockBoundaryType::Break : BlockBoundaryType::Continue; + + for (size_t i = m_boundaries.size(); i > 0; --i) { + auto boundary = m_boundaries[i - 1]; + if (boundary_to_stop_at.has_value() && boundary == *boundary_to_stop_at) + break; + if (boundary == BlockBoundaryType::Unwind) + emit(); + } + } + + void start_boundary(BlockBoundaryType type) { m_boundaries.append(type); } + void end_boundary(BlockBoundaryType type) + { + VERIFY(m_boundaries.last() == type); + m_boundaries.take_last(); + } + private: Generator(); ~Generator(); @@ -189,6 +219,7 @@ private: Vector