mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-27 23:09:08 +00:00
LibJS: Generate bytecode in basic blocks instead of one big block
This limits the size of each block (currently set to 1K), and gets us closer to a canonical, more easily analysable bytecode format. As a result of this, "Labels" are now simply entries to basic blocks. Since there is no more 'conditional' jump (as all jumps are always taken), JumpIf{True,False} are unified to JumpConditional, and JumpIfNullish is renamed to JumpNullish. Also fixes #7914 as a result of reimplementing the loop logic.
This commit is contained in:
parent
d7a25cdb82
commit
01e8f0889a
Notes:
sideshowbarker
2024-07-18 12:35:35 +09:00
Author: https://github.com/alimpfard
Commit: 01e8f0889a
Pull-request: https://github.com/SerenityOS/serenity/pull/7934
Issue: https://github.com/SerenityOS/serenity/issues/7914
16 changed files with 392 additions and 174 deletions
72
Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp
Normal file
72
Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Bytecode/BasicBlock.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
NonnullOwnPtr<BasicBlock> BasicBlock::create(String name)
|
||||
{
|
||||
return adopt_own(*new BasicBlock(move(name)));
|
||||
}
|
||||
|
||||
BasicBlock::BasicBlock(String name)
|
||||
: m_name(move(name))
|
||||
{
|
||||
// FIXME: This is not the smartest solution ever. Find something cleverer!
|
||||
// The main issue we're working around here is that we don't want pointers into the bytecode stream to become invalidated
|
||||
// during code generation due to dynamic buffer resizing. Otherwise we could just use a Vector.
|
||||
m_buffer_capacity = 1 * KiB;
|
||||
m_buffer = (u8*)mmap(nullptr, m_buffer_capacity, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
VERIFY(m_buffer != MAP_FAILED);
|
||||
}
|
||||
|
||||
BasicBlock::~BasicBlock()
|
||||
{
|
||||
Bytecode::InstructionStreamIterator it(instruction_stream());
|
||||
while (!it.at_end()) {
|
||||
auto& to_destroy = (*it);
|
||||
++it;
|
||||
Instruction::destroy(const_cast<Instruction&>(to_destroy));
|
||||
}
|
||||
|
||||
munmap(m_buffer, m_buffer_capacity);
|
||||
}
|
||||
|
||||
void BasicBlock::seal()
|
||||
{
|
||||
// FIXME: mprotect the instruction stream as PROT_READ
|
||||
// This is currently not possible because instructions can have destructors (that clean up strings)
|
||||
// Instructions should instead be destructor-less and refer to strings in a string table on the Bytecode::Block.
|
||||
// It also doesn't work because instructions that have String members use RefPtr internally which must be in writable memory.
|
||||
}
|
||||
|
||||
void BasicBlock::dump() const
|
||||
{
|
||||
Bytecode::InstructionStreamIterator it(instruction_stream());
|
||||
if (!m_name.is_empty())
|
||||
warnln("{}:", m_name);
|
||||
while (!it.at_end()) {
|
||||
warnln("[{:4x}] {}", it.offset(), (*it).to_string());
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void BasicBlock::grow(size_t additional_size)
|
||||
{
|
||||
m_buffer_size += additional_size;
|
||||
VERIFY(m_buffer_size <= m_buffer_capacity);
|
||||
}
|
||||
|
||||
void InstructionStreamIterator::operator++()
|
||||
{
|
||||
m_offset += dereference().length();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue