From 4bdfe738955c8de70c6266ab58addec7ef41b31e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 6 Jun 2021 13:33:02 +0200 Subject: [PATCH] LibJS: Add basic support for "continue" in the bytecode VM Unlike the convoluted unwind-until-scope-type mechanism in the AST interpreter, "continue" maps to a simple Bytecode::Op::Jump here. :^) We know where to jump based on a stack of "continuable scopes" that we now maintain on the Bytecode::Generator as we go. Note that this only supports bare "continue", not continue-with-label. --- Userland/Libraries/LibJS/AST.h | 1 + Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 10 ++++++++++ Userland/Libraries/LibJS/Bytecode/Generator.cpp | 15 +++++++++++++++ Userland/Libraries/LibJS/Bytecode/Generator.h | 6 ++++++ 4 files changed, 32 insertions(+) diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 5dc8e73911..b1f5332600 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; + virtual Optional generate_bytecode(Bytecode::Generator&) const override; const FlyString& target_label() const { return m_target_label; } diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index e53658f2ca..6bb367186b 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -110,6 +110,7 @@ Optional AssignmentExpression::generate_bytecode(Bytecode::G Optional WhileStatement::generate_bytecode(Bytecode::Generator& generator) const { + generator.begin_continuable_scope(); auto test_label = generator.make_label(); auto test_result_reg = m_test->generate_bytecode(generator); VERIFY(test_result_reg.has_value()); @@ -117,13 +118,16 @@ Optional WhileStatement::generate_bytecode(Bytecode::Generat auto body_result_reg = m_body->generate_bytecode(generator); generator.emit(test_label); test_jump.set_target(generator.make_label()); + generator.end_continuable_scope(); return body_result_reg; } Optional DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const { + generator.begin_continuable_scope(); auto head_label = generator.make_label(); auto body_result_reg = m_body->generate_bytecode(generator); + generator.end_continuable_scope(); auto test_result_reg = m_test->generate_bytecode(generator); VERIFY(test_result_reg.has_value()); generator.emit(*test_result_reg, head_label); @@ -209,4 +213,10 @@ Optional IfStatement::generate_bytecode(Bytecode::Generator& return {}; } +Optional ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + generator.emit(generator.nearest_continuable_scope()); + return {}; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 824f9de063..8a58af5b09 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -47,4 +47,19 @@ Label Generator::make_label() const return Label { m_block->instructions().size() }; } +Label Generator::nearest_continuable_scope() const +{ + return m_continuable_scopes.last(); +} + +void Generator::begin_continuable_scope() +{ + m_continuable_scopes.append(make_label()); +} + +void Generator::end_continuable_scope() +{ + m_continuable_scopes.take_last(); +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index e0b4ab8509..3a19525e47 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -29,6 +29,11 @@ public: Label make_label() const; + void begin_continuable_scope(); + void end_continuable_scope(); + + Label nearest_continuable_scope() const; + private: Generator(); ~Generator(); @@ -37,6 +42,7 @@ private: OwnPtr m_block; u32 m_next_register { 1 }; + Vector