GenerateCFG.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Bytecode/PassManager.h>
  7. namespace JS::Bytecode::Passes {
  8. void GenerateCFG::perform(PassPipelineExecutable& executable)
  9. {
  10. started();
  11. executable.cfg = HashMap<BasicBlock const*, HashTable<BasicBlock const*>> {};
  12. executable.inverted_cfg = HashMap<BasicBlock const*, HashTable<BasicBlock const*>> {};
  13. executable.exported_blocks = HashTable<BasicBlock const*> {};
  14. Vector<InstructionStreamIterator> iterators;
  15. Vector<BasicBlock const&> entered_blocks;
  16. HashTable<BasicBlock const*> seen_blocks;
  17. auto enter_label = [&](auto const& label, auto& entering_block, bool exported = false) {
  18. auto& entry = executable.cfg->ensure(&entering_block);
  19. entry.set(&label->block());
  20. auto& inverse_entry = executable.inverted_cfg->ensure(&label->block());
  21. inverse_entry.set(&entering_block);
  22. if (exported)
  23. executable.exported_blocks->set(&label->block());
  24. if (!seen_blocks.contains(&label->block())) {
  25. seen_blocks.set(&label->block());
  26. entered_blocks.append(label->block());
  27. iterators.empend(label->block().instruction_stream());
  28. }
  29. };
  30. seen_blocks.set(&executable.executable.basic_blocks.first());
  31. entered_blocks.append(executable.executable.basic_blocks.first());
  32. iterators.empend(executable.executable.basic_blocks.first().instruction_stream());
  33. while (!entered_blocks.is_empty()) {
  34. if (iterators.last().at_end()) {
  35. entered_blocks.take_last();
  36. iterators.take_last();
  37. continue;
  38. }
  39. auto const& instruction = *iterators.last();
  40. ++iterators.last();
  41. if (!instruction.is_terminator())
  42. continue;
  43. auto const& current_block = entered_blocks.last();
  44. using enum Instruction::Type;
  45. switch (instruction.type()) {
  46. case Jump: {
  47. auto const& true_target = static_cast<Op::Jump const&>(instruction).true_target();
  48. enter_label(true_target, current_block);
  49. continue;
  50. }
  51. case JumpConditional:
  52. case JumpNullish:
  53. case JumpUndefined: {
  54. auto const& true_target = static_cast<Op::Jump const&>(instruction).true_target();
  55. enter_label(true_target, current_block);
  56. auto const& false_target = static_cast<Op::Jump const&>(instruction).false_target();
  57. enter_label(false_target, current_block);
  58. continue;
  59. }
  60. case Yield: {
  61. auto const& continuation = static_cast<Op::Yield const&>(instruction).continuation();
  62. if (continuation.has_value())
  63. enter_label(continuation, current_block, true);
  64. continue;
  65. }
  66. case EnterUnwindContext: {
  67. auto const& entry_point = static_cast<Op::EnterUnwindContext const&>(instruction).entry_point();
  68. auto const& handler_target = static_cast<Op::EnterUnwindContext const&>(instruction).handler_target();
  69. auto const& finalizer_target = static_cast<Op::EnterUnwindContext const&>(instruction).finalizer_target();
  70. enter_label(&entry_point, current_block);
  71. if (handler_target.has_value())
  72. enter_label(handler_target, current_block);
  73. if (finalizer_target.has_value())
  74. enter_label(finalizer_target, current_block);
  75. continue;
  76. }
  77. case ContinuePendingUnwind: {
  78. auto const& resume_target = static_cast<Op::ContinuePendingUnwind const&>(instruction).resume_target();
  79. enter_label(&resume_target, current_block);
  80. continue;
  81. }
  82. case FinishUnwind: {
  83. auto const& next_target = static_cast<Op::FinishUnwind const&>(instruction).next_target();
  84. enter_label(&next_target, current_block);
  85. continue;
  86. }
  87. default:
  88. // Otherwise, pop the current block off, it doesn't jump anywhere.
  89. iterators.take_last();
  90. entered_blocks.take_last();
  91. continue;
  92. }
  93. }
  94. finished();
  95. }
  96. }