summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Gasperowicz <xnooga@gmail.com>2021-06-11 00:36:16 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-11 13:12:26 +0200
commita64089092fa894161442599675843dfa757b98f4 (patch)
tree638134be308834bf49f3ec403f00baa97708c0f7
parentfbb54efd288436a437e0f68ea0ad64eb3b24c3c1 (diff)
downloadserenity-a64089092fa894161442599675843dfa757b98f4.zip
LibJS: Implement bytecode generation for switch
-rw-r--r--Userland/Libraries/LibJS/AST.h1
-rw-r--r--Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp58
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);
+}
+
}