From a64089092fa894161442599675843dfa757b98f4 Mon Sep 17 00:00:00 2001 From: Marcin Gasperowicz Date: Fri, 11 Jun 2021 00:36:16 +0200 Subject: LibJS: Implement bytecode generation for switch --- Userland/Libraries/LibJS/AST.h | 1 + Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 58 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) 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 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 * Copyright (c) 2021, Linus Groh * Copyright (c) 2021, Gunnar Beutner + * Copyright (c) 2021, Marcin Gasperowicz * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -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(discriminant_reg); + Vector case_blocks; + Bytecode::BasicBlock* default_block { nullptr }; + Bytecode::BasicBlock* next_test_block = &generator.make_block(); + generator.emit().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(discriminant_reg); + next_test_block = &generator.make_block(); + generator.emit().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().set_targets(Bytecode::Label { *default_block }, {}); + } else { + generator.emit(js_undefined()); + generator.emit().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(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().set_targets(Bytecode::Label { end_block }, {}); + } else { + generator.emit().set_targets(Bytecode::Label { *next_block }, {}); + } + } + current_block++; + } + generator.end_breakable_scope(); + + generator.switch_to_basic_block(end_block); +} + } -- cgit v1.2.3