LibJS: Make Executable ref-counted and let instruction iterator co-own it

This ensures that the instruction stream pointed at by the instruction
iterator remains valid as long as the iterator exists.
This commit is contained in:
Andreas Kling 2023-10-03 08:18:10 +02:00
parent b1ee5c8738
commit c14db6ab12
9 changed files with 61 additions and 26 deletions

View file

@ -5,9 +5,34 @@
*/
#include <LibJS/Bytecode/Executable.h>
#include <LibJS/SourceCode.h>
namespace JS::Bytecode {
Executable::Executable(
NonnullOwnPtr<IdentifierTable> identifier_table,
NonnullOwnPtr<StringTable> string_table,
NonnullOwnPtr<RegexTable> regex_table,
NonnullRefPtr<SourceCode const> source_code,
size_t number_of_property_lookup_caches,
size_t number_of_global_variable_caches,
size_t number_of_registers,
Vector<NonnullOwnPtr<BasicBlock>> basic_blocks,
bool is_strict_mode)
: basic_blocks(move(basic_blocks))
, string_table(move(string_table))
, identifier_table(move(identifier_table))
, regex_table(move(regex_table))
, source_code(move(source_code))
, number_of_registers(number_of_registers)
, is_strict_mode(is_strict_mode)
{
property_lookup_caches.resize(number_of_property_lookup_caches);
global_variable_caches.resize(number_of_global_variable_caches);
}
Executable::~Executable() = default;
void Executable::dump() const
{
dbgln("\033[33;1mJS::Bytecode::Executable\033[0m ({})", name);

View file

@ -31,7 +31,21 @@ struct SourceRecord {
u32 source_end_offset {};
};
struct Executable {
class Executable final : public RefCounted<Executable> {
public:
Executable(
NonnullOwnPtr<IdentifierTable>,
NonnullOwnPtr<StringTable>,
NonnullOwnPtr<RegexTable>,
NonnullRefPtr<SourceCode const>,
size_t number_of_property_lookup_caches,
size_t number_of_global_variable_caches,
size_t number_of_registers,
Vector<NonnullOwnPtr<BasicBlock>>,
bool is_strict_mode);
~Executable();
DeprecatedFlyString name;
Vector<PropertyLookupCache> property_lookup_caches;
Vector<GlobalVariableCache> global_variable_caches;

View file

@ -20,7 +20,7 @@ Generator::Generator()
{
}
CodeGenerationErrorOr<NonnullOwnPtr<Executable>> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind)
CodeGenerationErrorOr<NonnullRefPtr<Executable>> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind)
{
Generator generator;
generator.switch_to_basic_block(generator.make_block());
@ -56,24 +56,18 @@ CodeGenerationErrorOr<NonnullOwnPtr<Executable>> Generator::generate(ASTNode con
else if (is<FunctionExpression>(node))
is_strict_mode = static_cast<FunctionExpression const&>(node).is_strict_mode();
Vector<PropertyLookupCache> property_lookup_caches;
property_lookup_caches.resize(generator.m_next_property_lookup_cache);
auto executable = adopt_ref(*new Executable(
move(generator.m_identifier_table),
move(generator.m_string_table),
move(generator.m_regex_table),
node.source_code(),
generator.m_next_property_lookup_cache,
generator.m_next_global_variable_cache,
generator.m_next_register,
move(generator.m_root_basic_blocks),
is_strict_mode));
Vector<GlobalVariableCache> global_variable_caches;
global_variable_caches.resize(generator.m_next_global_variable_cache);
return adopt_own(*new Executable {
.name = {},
.property_lookup_caches = move(property_lookup_caches),
.global_variable_caches = move(global_variable_caches),
.basic_blocks = move(generator.m_root_basic_blocks),
.string_table = move(generator.m_string_table),
.identifier_table = move(generator.m_identifier_table),
.regex_table = move(generator.m_regex_table),
.source_code = node.source_code(),
.number_of_registers = generator.m_next_register,
.is_strict_mode = is_strict_mode,
});
return executable;
}
void Generator::grow(size_t additional_size)

View file

@ -30,7 +30,7 @@ public:
Function,
Block,
};
static CodeGenerationErrorOr<NonnullOwnPtr<Executable>> generate(ASTNode const&, FunctionKind = FunctionKind::Normal);
static CodeGenerationErrorOr<NonnullRefPtr<Executable>> generate(ASTNode const&, FunctionKind = FunctionKind::Normal);
Register allocate_register();

View file

@ -178,13 +178,15 @@ public:
UnrealizedSourceRange source_range() const;
RefPtr<SourceCode> source_code() const;
Executable const* executable() const { return m_executable; }
private:
Instruction const& dereference() const { return *reinterpret_cast<Instruction const*>(m_ptr); }
u8 const* m_begin { nullptr };
u8 const* m_end { nullptr };
u8 const* m_ptr { nullptr };
Executable const* m_executable { nullptr };
RefPtr<Executable const> m_executable;
};
}

View file

@ -407,7 +407,7 @@ void Interpreter::leave_unwind_context()
unwind_contexts().take_last();
}
ThrowCompletionOr<NonnullOwnPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name)
ThrowCompletionOr<NonnullRefPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name)
{
auto executable_result = Bytecode::Generator::generate(node, kind);
if (executable_result.is_error())

View file

@ -110,6 +110,6 @@ private:
extern bool g_dump_bytecode;
ThrowCompletionOr<NonnullOwnPtr<Bytecode::Executable>> compile(VM&, ASTNode const& no, JS::FunctionKind kind, DeprecatedFlyString const& name);
ThrowCompletionOr<NonnullRefPtr<Bytecode::Executable>> compile(VM&, ASTNode const& no, JS::FunctionKind kind, DeprecatedFlyString const& name);
}

View file

@ -302,7 +302,7 @@ class MarkedVector;
namespace Bytecode {
class BasicBlock;
struct Executable;
class Executable;
class Generator;
class Instruction;
class Interpreter;

View file

@ -111,8 +111,8 @@ private:
ThrowCompletionOr<void> function_declaration_instantiation();
DeprecatedFlyString m_name;
OwnPtr<Bytecode::Executable> m_bytecode_executable;
Vector<OwnPtr<Bytecode::Executable>> m_default_parameter_bytecode_executables;
RefPtr<Bytecode::Executable> m_bytecode_executable;
Vector<NonnullRefPtr<Bytecode::Executable>> m_default_parameter_bytecode_executables;
i32 m_function_length { 0 };
Vector<DeprecatedFlyString> m_local_variables_names;