LibJS/Bytecode: Store labels as basic block index during compilation

Instead of storing a BasicBlock* and forcing the size of Label to be
sizeof(BasicBlock*), we now store the basic block index as a u32.

This means the final version of the bytecode is able to keep labels
at sizeof(u32), shrinking the size of many instructions. :^)
This commit is contained in:
Andreas Kling 2024-05-06 08:06:56 +02:00
commit 3a73eb99ac
Notes: sideshowbarker 2024-07-16 21:42:29 +09:00
7 changed files with 40 additions and 22 deletions

View file

@ -10,13 +10,14 @@
namespace JS::Bytecode { namespace JS::Bytecode {
NonnullOwnPtr<BasicBlock> BasicBlock::create(String name) NonnullOwnPtr<BasicBlock> BasicBlock::create(u32 index, String name)
{ {
return adopt_own(*new BasicBlock(move(name))); return adopt_own(*new BasicBlock(index, move(name)));
} }
BasicBlock::BasicBlock(String name) BasicBlock::BasicBlock(u32 index, String name)
: m_name(move(name)) : m_index(index)
, m_name(move(name))
{ {
} }

View file

@ -25,9 +25,11 @@ class BasicBlock {
AK_MAKE_NONCOPYABLE(BasicBlock); AK_MAKE_NONCOPYABLE(BasicBlock);
public: public:
static NonnullOwnPtr<BasicBlock> create(String name); static NonnullOwnPtr<BasicBlock> create(u32 index, String name);
~BasicBlock(); ~BasicBlock();
u32 index() const { return m_index; }
ReadonlyBytes instruction_stream() const { return m_buffer.span(); } ReadonlyBytes instruction_stream() const { return m_buffer.span(); }
u8* data() { return m_buffer.data(); } u8* data() { return m_buffer.data(); }
u8 const* data() const { return m_buffer.data(); } u8 const* data() const { return m_buffer.data(); }
@ -50,8 +52,9 @@ public:
void add_source_map_entry(size_t bytecode_offset, SourceRecord const& source_record) { m_source_map.set(bytecode_offset, source_record); } void add_source_map_entry(size_t bytecode_offset, SourceRecord const& source_record) { m_source_map.set(bytecode_offset, source_record); }
private: private:
explicit BasicBlock(String name); explicit BasicBlock(u32 index, String name);
u32 m_index { 0 };
Vector<u8> m_buffer; Vector<u8> m_buffer;
BasicBlock const* m_handler { nullptr }; BasicBlock const* m_handler { nullptr };
BasicBlock const* m_finalizer { nullptr }; BasicBlock const* m_finalizer { nullptr };

View file

@ -135,7 +135,7 @@ CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::generate(VM& vm, ASTN
} }
for (auto label_offset : label_offsets) { for (auto label_offset : label_offsets) {
auto& label = *reinterpret_cast<Label*>(bytecode.data() + label_offset); auto& label = *reinterpret_cast<Label*>(bytecode.data() + label_offset);
auto* block = &label.block(); auto* block = generator.m_root_basic_blocks[label.basic_block_index()].ptr();
label.set_address(block_offsets.get(block).value()); label.set_address(block_offsets.get(block).value());
} }

View file

@ -150,12 +150,12 @@ public:
{ {
if (name.is_empty()) if (name.is_empty())
name = MUST(String::number(m_next_block++)); name = MUST(String::number(m_next_block++));
auto block = BasicBlock::create(name); auto block = BasicBlock::create(m_root_basic_blocks.size(), name);
if (auto const* context = m_current_unwind_context) { if (auto const* context = m_current_unwind_context) {
if (context->handler().has_value()) if (context->handler().has_value())
block->set_handler(context->handler().value().block()); block->set_handler(*m_root_basic_blocks[context->handler().value().basic_block_index()]);
if (m_current_unwind_context->finalizer().has_value()) if (m_current_unwind_context->finalizer().has_value())
block->set_finalizer(context->finalizer().value().block()); block->set_finalizer(*m_root_basic_blocks[context->finalizer().value().basic_block_index()]);
} }
m_root_basic_blocks.append(move(block)); m_root_basic_blocks.append(move(block));
return *m_root_basic_blocks.last(); return *m_root_basic_blocks.last();

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2024, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Label.h>
namespace JS::Bytecode {
Label::Label(Bytecode::BasicBlock const& basic_block)
: m_address_or_basic_block_index(basic_block.index())
{
}
}

View file

@ -14,27 +14,23 @@ class BasicBlock;
class Label { class Label {
public: public:
explicit Label(BasicBlock const& block) explicit Label(BasicBlock const&);
: m_block(&block)
explicit Label(u32 basic_block_index)
: m_address_or_basic_block_index(basic_block_index)
{ {
} }
// Used while compiling. // Used while compiling.
BasicBlock const& block() const { return *m_block; } size_t basic_block_index() const { return m_address_or_basic_block_index; }
// Used after compiling. // Used after compiling.
size_t address() const { return m_address; } size_t address() const { return m_address_or_basic_block_index; }
void set_address(size_t address) { m_address = address; } void set_address(size_t address) { m_address_or_basic_block_index = address; }
private: private:
union { u32 m_address_or_basic_block_index { 0 };
// Relevant while compiling.
BasicBlock const* m_block { nullptr };
// Relevant after compiling.
size_t m_address;
};
}; };
} }

View file

@ -9,6 +9,7 @@ set(SOURCES
Bytecode/IdentifierTable.cpp Bytecode/IdentifierTable.cpp
Bytecode/Instruction.cpp Bytecode/Instruction.cpp
Bytecode/Interpreter.cpp Bytecode/Interpreter.cpp
Bytecode/Label.cpp
Bytecode/RegexTable.cpp Bytecode/RegexTable.cpp
Bytecode/StringTable.cpp Bytecode/StringTable.cpp
Console.cpp Console.cpp