123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- /*
- * 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 GenerateCFG::perform(PassPipelineExecutable& executable)
- {
- started();
- executable.cfg = HashMap<BasicBlock const*, HashTable<BasicBlock const*>> {};
- executable.inverted_cfg = HashMap<BasicBlock const*, HashTable<BasicBlock const*>> {};
- executable.exported_blocks = HashTable<BasicBlock const*> {};
- Vector<InstructionStreamIterator> iterators;
- Vector<BasicBlock const&> entered_blocks;
- HashTable<BasicBlock const*> seen_blocks;
- auto enter_label = [&](auto const& label, auto& entering_block, bool exported = false) {
- auto& entry = executable.cfg->ensure(&entering_block);
- entry.set(&label->block());
- auto& inverse_entry = executable.inverted_cfg->ensure(&label->block());
- inverse_entry.set(&entering_block);
- if (exported)
- executable.exported_blocks->set(&label->block());
- if (!seen_blocks.contains(&label->block())) {
- seen_blocks.set(&label->block());
- entered_blocks.append(label->block());
- iterators.empend(label->block().instruction_stream());
- }
- };
- seen_blocks.set(&executable.executable.basic_blocks.first());
- entered_blocks.append(executable.executable.basic_blocks.first());
- iterators.empend(executable.executable.basic_blocks.first().instruction_stream());
- while (!entered_blocks.is_empty()) {
- if (iterators.last().at_end()) {
- entered_blocks.take_last();
- iterators.take_last();
- continue;
- }
- auto const& instruction = *iterators.last();
- ++iterators.last();
- if (!instruction.is_terminator())
- continue;
- auto const& current_block = entered_blocks.last();
- using enum Instruction::Type;
- switch (instruction.type()) {
- case Jump: {
- auto const& true_target = static_cast<Op::Jump const&>(instruction).true_target();
- enter_label(true_target, current_block);
- continue;
- }
- case JumpConditional:
- case JumpNullish:
- case JumpUndefined: {
- auto const& true_target = static_cast<Op::Jump const&>(instruction).true_target();
- enter_label(true_target, current_block);
- auto const& false_target = static_cast<Op::Jump const&>(instruction).false_target();
- enter_label(false_target, current_block);
- continue;
- }
- case Yield: {
- auto const& continuation = static_cast<Op::Yield const&>(instruction).continuation();
- if (continuation.has_value())
- enter_label(continuation, current_block, true);
- continue;
- }
- case EnterUnwindContext: {
- auto const& entry_point = static_cast<Op::EnterUnwindContext const&>(instruction).entry_point();
- auto const& handler_target = static_cast<Op::EnterUnwindContext const&>(instruction).handler_target();
- auto const& finalizer_target = static_cast<Op::EnterUnwindContext const&>(instruction).finalizer_target();
- enter_label(&entry_point, current_block);
- if (handler_target.has_value())
- enter_label(handler_target, current_block);
- if (finalizer_target.has_value())
- enter_label(finalizer_target, current_block);
- continue;
- }
- case ContinuePendingUnwind: {
- auto const& resume_target = static_cast<Op::ContinuePendingUnwind const&>(instruction).resume_target();
- enter_label(&resume_target, current_block);
- continue;
- }
- case FinishUnwind: {
- auto const& next_target = static_cast<Op::FinishUnwind const&>(instruction).next_target();
- enter_label(&next_target, current_block);
- continue;
- }
- default:
- // Otherwise, pop the current block off, it doesn't jump anywhere.
- iterators.take_last();
- entered_blocks.take_last();
- continue;
- }
- }
- finished();
- }
- }
|