diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index f99363a96b..24cb119328 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -1300,6 +1300,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; const FlyString& target_label() const { return m_target_label; } + virtual void generate_bytecode(Bytecode::Generator&) const override; private: FlyString m_target_label; diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 2b8a566ab0..5ceaefd069 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -376,13 +376,14 @@ void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(body_block); generator.begin_continuable_scope(Bytecode::Label { test_block }); + generator.begin_breakable_scope(Bytecode::Label { end_block }); m_body->generate_bytecode(generator); if (!generator.is_current_block_terminated()) { generator.emit().set_targets( Bytecode::Label { test_block }, {}); generator.end_continuable_scope(); - + generator.end_breakable_scope(); generator.switch_to_basic_block(end_block); generator.emit(result_reg); } @@ -418,13 +419,14 @@ void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(body_block); generator.begin_continuable_scope(Bytecode::Label { test_block }); + generator.begin_breakable_scope(Bytecode::Label { end_block }); m_body->generate_bytecode(generator); if (!generator.is_current_block_terminated()) { generator.emit().set_targets( Bytecode::Label { test_block }, {}); generator.end_continuable_scope(); - + generator.end_breakable_scope(); generator.switch_to_basic_block(end_block); generator.emit(result_reg); } @@ -484,6 +486,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(*body_block_ptr); generator.begin_continuable_scope(Bytecode::Label { *update_block_ptr }); + generator.begin_breakable_scope(Bytecode::Label { end_block }); m_body->generate_bytecode(generator); generator.end_continuable_scope(); @@ -501,6 +504,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const Bytecode::Label { *test_block_ptr }, {}); + generator.end_breakable_scope(); generator.switch_to_basic_block(end_block); generator.emit(result_reg); } @@ -787,4 +791,11 @@ void ThrowStatement::generate_bytecode(Bytecode::Generator& generator) const generator.emit(); } +void BreakStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + generator.emit().set_targets( + generator.nearest_breakable_scope(), + {}); +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 51dd218852..db5f6805b7 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -62,5 +62,17 @@ void Generator::end_continuable_scope() { m_continuable_scopes.take_last(); } - +Label Generator::nearest_breakable_scope() const +{ + return m_breakable_scopes.last(); +} +void Generator::begin_breakable_scope(Label breakable_target) +{ + m_breakable_scopes.append(breakable_target); +} + +void Generator::end_breakable_scope() +{ + m_breakable_scopes.take_last(); +} } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 6cfe411a44..ed425e2c22 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -57,8 +57,11 @@ public: void begin_continuable_scope(Label continue_target); void end_continuable_scope(); + void begin_breakable_scope(Label breakable_target); + void end_breakable_scope(); [[nodiscard]] Label nearest_continuable_scope() const; + [[nodiscard]] Label nearest_breakable_scope() const; void switch_to_basic_block(BasicBlock& block) { @@ -97,6 +100,7 @@ private: u32 m_next_register { 1 }; u32 m_next_block { 1 }; Vector