LibJS: Automatically split linear bytecode into multiple blocks

...instead of crashing :^)
This commit is contained in:
Ali Mohammad Pur 2021-06-11 01:35:01 +04:30 committed by Andreas Kling
parent 7b2c838162
commit 4cfdfb6a88
Notes: sideshowbarker 2024-07-18 12:28:06 +09:00
3 changed files with 25 additions and 0 deletions

View file

@ -44,6 +44,8 @@ struct UnwindInfo {
};
class BasicBlock {
AK_MAKE_NONCOPYABLE(BasicBlock);
public:
static NonnullOwnPtr<BasicBlock> create(String name);
~BasicBlock();
@ -54,6 +56,7 @@ public:
ReadonlyBytes instruction_stream() const { return ReadonlyBytes { m_buffer, m_buffer_size }; }
void* next_slot() { return m_buffer + m_buffer_size; }
bool can_grow(size_t additional_size) const { return m_buffer_size + additional_size <= m_buffer_capacity; }
void grow(size_t additional_size);
void terminate(Badge<Generator>) { m_is_terminated = true; }

View file

@ -8,6 +8,7 @@
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Generator.h>
#include <LibJS/Bytecode/Instruction.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Bytecode/Register.h>
#include <LibJS/Forward.h>

View file

@ -11,6 +11,7 @@
#include <AK/SinglyLinkedList.h>
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Label.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Bytecode/Register.h>
#include <LibJS/Bytecode/StringTable.h>
#include <LibJS/Forward.h>
@ -31,10 +32,26 @@ public:
Register allocate_register();
void ensure_enough_space(size_t size)
{
// Make sure there's always enough space for a single jump at the end.
if (!m_current_basic_block->can_grow(size + sizeof(Op::Jump))) {
auto& new_block = make_block();
emit<Op::Jump>().set_targets(
Label { new_block },
{});
switch_to_basic_block(new_block);
}
}
template<typename OpType, typename... Args>
OpType& emit(Args&&... args)
{
VERIFY(!is_current_block_terminated());
// If the block doesn't have enough space, switch to another block
if constexpr (!OpType::IsTerminator)
ensure_enough_space(sizeof(OpType));
void* slot = next_slot();
grow(sizeof(OpType));
new (slot) OpType(forward<Args>(args)...);
@ -47,6 +64,10 @@ public:
OpType& emit_with_extra_register_slots(size_t extra_register_slots, Args&&... args)
{
VERIFY(!is_current_block_terminated());
// If the block doesn't have enough space, switch to another block
if constexpr (!OpType::IsTerminator)
ensure_enough_space(sizeof(OpType) + extra_register_slots * sizeof(Register));
void* slot = next_slot();
grow(sizeof(OpType) + extra_register_slots * sizeof(Register));
new (slot) OpType(forward<Args>(args)...);