summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-06-11 01:35:01 +0430
committerAndreas Kling <kling@serenityos.org>2021-06-11 00:30:09 +0200
commit4cfdfb6a887f083b7b495350e5ac09d9c2271802 (patch)
treea363605acea9310cd072a9d47186cc4e332968bf
parent7b2c8381623c63c3f5684feff81bbde72ac9457a (diff)
downloadserenity-4cfdfb6a887f083b7b495350e5ac09d9c2271802.zip
LibJS: Automatically split linear bytecode into multiple blocks
...instead of crashing :^)
-rw-r--r--Userland/Libraries/LibJS/Bytecode/BasicBlock.h3
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Generator.cpp1
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Generator.h21
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)...);