UnifySameBlocks.cpp 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  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. #include <string.h>
  8. namespace JS::Bytecode::Passes {
  9. void UnifySameBlocks::perform(PassPipelineExecutable& executable)
  10. {
  11. started();
  12. VERIFY(executable.cfg.has_value());
  13. VERIFY(executable.inverted_cfg.has_value());
  14. auto cfg = executable.cfg.release_value();
  15. auto inverted_cfg = executable.inverted_cfg.release_value();
  16. HashMap<BasicBlock const*, BasicBlock const*> equal_blocks;
  17. for (size_t i = 0; i < executable.executable.basic_blocks.size(); ++i) {
  18. auto& block = executable.executable.basic_blocks[i];
  19. auto block_bytes = block.instruction_stream();
  20. for (auto& candidate_block : executable.executable.basic_blocks.span().slice(i + 1)) {
  21. // FIXME: This can probably be relaxed a bit...
  22. if (candidate_block->size() != block.size())
  23. continue;
  24. auto candidate_bytes = candidate_block->instruction_stream();
  25. // FIXME: NewBigInt's value is not correctly reflected by its encoding in memory,
  26. // this will yield false negatives for blocks containing that
  27. if (memcmp(candidate_bytes.data(), block_bytes.data(), candidate_block->size()) == 0)
  28. equal_blocks.set(&*candidate_block, &block);
  29. }
  30. }
  31. auto replace_blocks = [&](auto& match, auto& replacement) {
  32. Optional<size_t> first_successor_position;
  33. auto it = executable.executable.basic_blocks.find_if([match](auto& block) { return match == block; });
  34. VERIFY(!it.is_end());
  35. executable.executable.basic_blocks.remove(it.index());
  36. if (!first_successor_position.has_value())
  37. first_successor_position = it.index();
  38. for (auto& block : executable.executable.basic_blocks) {
  39. InstructionStreamIterator it { block.instruction_stream() };
  40. while (!it.at_end()) {
  41. auto& instruction = *it;
  42. ++it;
  43. const_cast<Instruction&>(instruction).replace_references(*match, replacement);
  44. }
  45. }
  46. return first_successor_position;
  47. };
  48. for (auto& entry : equal_blocks)
  49. (void)replace_blocks(entry.key, *entry.value);
  50. finished();
  51. }
  52. }