BasicBlock.cpp 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/String.h>
  7. #include <LibJS/Bytecode/BasicBlock.h>
  8. #include <LibJS/Bytecode/Op.h>
  9. #include <sys/mman.h>
  10. namespace JS::Bytecode {
  11. NonnullOwnPtr<BasicBlock> BasicBlock::create(String name, size_t size)
  12. {
  13. return adopt_own(*new BasicBlock(move(name), max(size, static_cast<size_t>(4 * KiB))));
  14. }
  15. BasicBlock::BasicBlock(String name, size_t size)
  16. : m_name(move(name))
  17. {
  18. // FIXME: This is not the smartest solution ever. Find something cleverer!
  19. // The main issue we're working around here is that we don't want pointers into the bytecode stream to become invalidated
  20. // during code generation due to dynamic buffer resizing. Otherwise we could just use a Vector.
  21. m_buffer_capacity = size;
  22. m_buffer = (u8*)mmap(nullptr, m_buffer_capacity, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  23. VERIFY(m_buffer != MAP_FAILED);
  24. }
  25. BasicBlock::~BasicBlock()
  26. {
  27. Bytecode::InstructionStreamIterator it(instruction_stream());
  28. while (!it.at_end()) {
  29. auto& to_destroy = (*it);
  30. ++it;
  31. Instruction::destroy(const_cast<Instruction&>(to_destroy));
  32. }
  33. munmap(m_buffer, m_buffer_capacity);
  34. }
  35. void BasicBlock::seal()
  36. {
  37. // FIXME: mprotect the instruction stream as PROT_READ
  38. // This is currently not possible because instructions can have destructors (that clean up strings)
  39. // Instructions should instead be destructor-less and refer to strings in a string table on the Bytecode::Block.
  40. // It also doesn't work because instructions that have String members use RefPtr internally which must be in writable memory.
  41. }
  42. void BasicBlock::dump(Bytecode::Executable const& executable) const
  43. {
  44. Bytecode::InstructionStreamIterator it(instruction_stream());
  45. if (!m_name.is_empty())
  46. warnln("{}:", m_name);
  47. while (!it.at_end()) {
  48. warnln("[{:4x}] {}", it.offset(), (*it).to_string(executable));
  49. ++it;
  50. }
  51. }
  52. void BasicBlock::grow(size_t additional_size)
  53. {
  54. m_buffer_size += additional_size;
  55. VERIFY(m_buffer_size <= m_buffer_capacity);
  56. }
  57. void InstructionStreamIterator::operator++()
  58. {
  59. VERIFY(!at_end());
  60. m_offset += dereference().length();
  61. }
  62. }