diff options
author | Marcin Gasperowicz <xnooga@gmail.com> | 2021-06-11 00:36:16 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-11 13:12:26 +0200 |
commit | a64089092fa894161442599675843dfa757b98f4 (patch) | |
tree | 638134be308834bf49f3ec403f00baa97708c0f7 | |
parent | fbb54efd288436a437e0f68ea0ad64eb3b24c3c1 (diff) | |
download | serenity-a64089092fa894161442599675843dfa757b98f4.zip |
LibJS: Implement bytecode generation for switch
-rw-r--r-- | Userland/Libraries/LibJS/AST.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 58 |
2 files changed, 59 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 25ba50f0c9..a1dfab7f39 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -1309,6 +1309,7 @@ public: virtual void dump(int indent) const override; virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_discriminant; diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index e9e82a6484..c7439d26b5 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2,10 +2,12 @@ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021, Linus Groh <linusg@serenityos.org> * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org> + * Copyright (c) 2021, Marcin Gasperowicz <xnooga@gmail.com> * * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/Format.h> #include <LibJS/AST.h> #include <LibJS/Bytecode/Generator.h> #include <LibJS/Bytecode/Instruction.h> @@ -968,4 +970,60 @@ void TryStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(next_block ? *next_block : saved_block); } +void SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + auto discriminant_reg = generator.allocate_register(); + m_discriminant->generate_bytecode(generator); + generator.emit<Bytecode::Op::Store>(discriminant_reg); + Vector<Bytecode::BasicBlock&> case_blocks; + Bytecode::BasicBlock* default_block { nullptr }; + Bytecode::BasicBlock* next_test_block = &generator.make_block(); + generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { *next_test_block }, {}); + for (auto& switch_case : m_cases) { + auto& case_block = generator.make_block(); + if (switch_case.test()) { + generator.switch_to_basic_block(*next_test_block); + switch_case.test()->generate_bytecode(generator); + generator.emit<Bytecode::Op::TypedEquals>(discriminant_reg); + next_test_block = &generator.make_block(); + generator.emit<Bytecode::Op::JumpConditional>().set_targets(Bytecode::Label { case_block }, Bytecode::Label { *next_test_block }); + } else { + default_block = &case_block; + } + case_blocks.append(case_block); + } + generator.switch_to_basic_block(*next_test_block); + auto& end_block = generator.make_block(); + + if (default_block != nullptr) { + generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { *default_block }, {}); + } else { + generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); + generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { end_block }, {}); + } + auto current_block = case_blocks.begin(); + generator.begin_breakable_scope(Bytecode::Label { end_block }); + for (auto& switch_case : m_cases) { + generator.switch_to_basic_block(*current_block); + + generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); + for (auto& statement : switch_case.consequent()) { + statement.generate_bytecode(generator); + } + if (!generator.is_current_block_terminated()) { + auto next_block = current_block; + next_block++; + if (next_block.is_end()) { + generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { end_block }, {}); + } else { + generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { *next_block }, {}); + } + } + current_block++; + } + generator.end_breakable_scope(); + + generator.switch_to_basic_block(end_block); +} + } |