summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp')
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp54
1 files changed, 54 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp
new file mode 100644
index 0000000000..4a320ac470
--- /dev/null
+++ b/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Bytecode/PassManager.h>
+
+namespace JS::Bytecode::Passes {
+
+void PlaceBlocks::perform(PassPipelineExecutable& executable)
+{
+ started();
+
+ VERIFY(executable.cfg.has_value());
+ auto cfg = executable.cfg.release_value();
+
+ Vector<BasicBlock&> replaced_blocks;
+ HashTable<BasicBlock const*> reachable_blocks;
+
+ // Visit the blocks in CFG order
+ AK::Function<void(BasicBlock const*)> visit = [&](auto* block) {
+ if (reachable_blocks.contains(block))
+ return;
+
+ reachable_blocks.set(block);
+ replaced_blocks.append(*const_cast<BasicBlock*>(block));
+
+ for (auto& entry : cfg.get(block).value_or({}))
+ visit(entry);
+ };
+
+ // Make sure to visit the entry block first
+ visit(&executable.executable.basic_blocks.first());
+
+ for (auto& entry : cfg)
+ visit(entry.key);
+
+ // Put the unreferenced blocks back in at the end
+ for (auto& entry : static_cast<Vector<NonnullOwnPtr<BasicBlock>>&>(executable.executable.basic_blocks)) {
+ if (reachable_blocks.contains(entry.ptr()))
+ (void)entry.leak_ptr();
+ else
+ replaced_blocks.append(*entry.leak_ptr()); // Don't try to do DCE here.
+ }
+
+ executable.executable.basic_blocks.clear();
+ for (auto& block : replaced_blocks)
+ executable.executable.basic_blocks.append(adopt_own(block));
+
+ finished();
+}
+
+}