diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-06-11 01:35:01 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-11 00:30:09 +0200 |
commit | 4cfdfb6a887f083b7b495350e5ac09d9c2271802 (patch) | |
tree | a363605acea9310cd072a9d47186cc4e332968bf | |
parent | 7b2c8381623c63c3f5684feff81bbde72ac9457a (diff) | |
download | serenity-4cfdfb6a887f083b7b495350e5ac09d9c2271802.zip |
LibJS: Automatically split linear bytecode into multiple blocks
...instead of crashing :^)
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/BasicBlock.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.cpp | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.h | 21 |
3 files changed, 25 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index 384e373d0c..08912e1a6d 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -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; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index db5f6805b7..c7e394ef2f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -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> diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 7410ff1918..1ae3e0ab94 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -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)...); |