From ecfcc9aef3633c25dc3bc58ec9149a60e1f3a38b Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 27 Nov 2023 13:23:59 +0100 Subject: [PATCH] LibJS: Make Bytecode::Executable GC-allocated This is a step towards making ExecutionContext easier to allocate. --- Userland/Libraries/LibJS/AST.h | 8 ++++---- Userland/Libraries/LibJS/Bytecode/Executable.cpp | 2 ++ Userland/Libraries/LibJS/Bytecode/Executable.h | 9 +++++++-- Userland/Libraries/LibJS/Bytecode/Generator.cpp | 7 ++++--- Userland/Libraries/LibJS/Bytecode/Generator.h | 2 +- Userland/Libraries/LibJS/Bytecode/Instruction.h | 2 +- Userland/Libraries/LibJS/Bytecode/Interpreter.cpp | 6 +++--- Userland/Libraries/LibJS/Bytecode/Interpreter.h | 2 +- Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | 2 +- .../Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp | 4 ++++ .../Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h | 4 ++-- Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp | 3 +++ Userland/Libraries/LibJS/Runtime/ExecutionContext.h | 2 +- 13 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index a0144c2121..1936e86f65 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -155,11 +155,11 @@ public: { } - Bytecode::Executable const* bytecode_executable() const { return m_bytecode_executable; } - void set_bytecode_executable(Bytecode::Executable const* bytecode_executable) { m_bytecode_executable = bytecode_executable; } + Bytecode::Executable* bytecode_executable() const { return m_bytecode_executable; } + void set_bytecode_executable(Bytecode::Executable* bytecode_executable) { m_bytecode_executable = make_handle(bytecode_executable); } private: - RefPtr m_bytecode_executable; + Handle m_bytecode_executable; }; // 14.13 Labelled Statements, https://tc39.es/ecma262/#sec-labelled-statements @@ -685,7 +685,7 @@ struct FunctionParameter { Variant, NonnullRefPtr> binding; RefPtr default_value; bool is_rest { false }; - RefPtr bytecode_executable {}; + Handle bytecode_executable {}; }; class FunctionNode { diff --git a/Userland/Libraries/LibJS/Bytecode/Executable.cpp b/Userland/Libraries/LibJS/Bytecode/Executable.cpp index 392a1f4d86..4dbc254e89 100644 --- a/Userland/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Executable.cpp @@ -13,6 +13,8 @@ namespace JS::Bytecode { +JS_DEFINE_ALLOCATOR(Executable); + Executable::Executable( NonnullOwnPtr identifier_table, NonnullOwnPtr string_table, diff --git a/Userland/Libraries/LibJS/Bytecode/Executable.h b/Userland/Libraries/LibJS/Bytecode/Executable.h index e201dd3bef..d7bbdbb033 100644 --- a/Userland/Libraries/LibJS/Bytecode/Executable.h +++ b/Userland/Libraries/LibJS/Bytecode/Executable.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include namespace JS::JIT { @@ -46,7 +48,10 @@ struct SourceRecord { u32 source_end_offset {}; }; -class Executable final : public RefCounted { +class Executable final : public Cell { + JS_CELL(Executable, Cell); + JS_DECLARE_ALLOCATOR(Executable); + public: Executable( NonnullOwnPtr, @@ -60,7 +65,7 @@ public: Vector>, bool is_strict_mode); - ~Executable(); + virtual ~Executable() override; DeprecatedFlyString name; Vector property_lookup_caches; diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 044d3622df..fc98bc04ae 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace JS::Bytecode { @@ -21,7 +22,7 @@ Generator::Generator() { } -CodeGenerationErrorOr> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind) +CodeGenerationErrorOr> Generator::generate(VM& vm, ASTNode const& node, FunctionKind enclosing_function_kind) { Generator generator; generator.switch_to_basic_block(generator.make_block()); @@ -57,7 +58,7 @@ CodeGenerationErrorOr> Generator::generate(ASTNode con else if (is(node)) is_strict_mode = static_cast(node).is_strict_mode(); - auto executable = adopt_ref(*new Executable( + auto executable = vm.heap().allocate_without_realm( move(generator.m_identifier_table), move(generator.m_string_table), move(generator.m_regex_table), @@ -67,7 +68,7 @@ CodeGenerationErrorOr> Generator::generate(ASTNode con generator.m_next_environment_variable_cache, generator.m_next_register, move(generator.m_root_basic_blocks), - is_strict_mode)); + is_strict_mode); return executable; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 30c122e6a2..56032c35c2 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -30,7 +30,7 @@ public: Function, Block, }; - static CodeGenerationErrorOr> generate(ASTNode const&, FunctionKind = FunctionKind::Normal); + static CodeGenerationErrorOr> generate(VM&, ASTNode const&, FunctionKind = FunctionKind::Normal); Register allocate_register(); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 8b8a6e8ab9..2a0f6c5adc 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -187,7 +187,7 @@ private: u8 const* m_begin { nullptr }; u8 const* m_end { nullptr }; u8 const* m_ptr { nullptr }; - RefPtr m_executable; + GCPtr m_executable; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index eda879143f..2b5b8a5b20 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -105,7 +105,7 @@ ThrowCompletionOr Interpreter::run(Script& script_record, JS::GCPtr> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name) +ThrowCompletionOr> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name) { - auto executable_result = Bytecode::Generator::generate(node, kind); + auto executable_result = Bytecode::Generator::generate(vm, node, kind); if (executable_result.is_error()) return vm.throw_completion(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string())); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 192784ced0..e45c9ece63 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -115,6 +115,6 @@ private: extern bool g_dump_bytecode; -ThrowCompletionOr> compile(VM&, ASTNode const& no, JS::FunctionKind kind, DeprecatedFlyString const& name); +ThrowCompletionOr> compile(VM&, ASTNode const& no, JS::FunctionKind kind, DeprecatedFlyString const& name); } diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index c40b551f65..6356649349 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -679,7 +679,7 @@ ThrowCompletionOr perform_eval(VM& vm, Value x, CallerMode strict_caller, // 29. If result.[[Type]] is normal, then // a. Set result to the result of evaluating body. - auto executable_result = Bytecode::Generator::generate(program); + auto executable_result = Bytecode::Generator::generate(vm, program); if (executable_result.is_error()) return vm.throw_completion(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string())); diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 6b254fa34f..a87077153d 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -527,6 +527,10 @@ void ECMAScriptFunctionObject::visit_edges(Visitor& visitor) visitor.visit(m_realm); visitor.visit(m_home_object); + visitor.visit(m_bytecode_executable); + for (auto& executable : m_default_parameter_bytecode_executables) + visitor.visit(executable); + for (auto& field : m_fields) { if (auto* property_key_ptr = field.name.get_pointer(); property_key_ptr && property_key_ptr->is_symbol()) visitor.visit(property_key_ptr->as_symbol()); diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index c61cac27d5..401b3f970d 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -112,8 +112,8 @@ private: ThrowCompletionOr function_declaration_instantiation(); DeprecatedFlyString m_name; - RefPtr m_bytecode_executable; - Vector> m_default_parameter_bytecode_executables; + GCPtr m_bytecode_executable; + Vector> m_default_parameter_bytecode_executables; i32 m_function_length { 0 }; Vector m_local_variables_names; diff --git a/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp b/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp index a9d6d6aa52..1964cf5cf5 100644 --- a/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp +++ b/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp @@ -6,6 +6,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -50,6 +51,8 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor) visitor.visit(private_environment); visitor.visit(context_owner); visitor.visit(this_value); + if (instruction_stream_iterator.has_value()) + visitor.visit(const_cast(instruction_stream_iterator.value().executable())); script_or_module.visit( [](Empty) {}, [&](auto& script_or_module) { diff --git a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h index 9c710e8ecb..f9f0d9197a 100644 --- a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h @@ -55,7 +55,7 @@ public: MarkedVector local_variables; bool is_strict_mode { false }; - RefPtr executable; + GCPtr executable; // https://html.spec.whatwg.org/multipage/webappapis.html#skip-when-determining-incumbent-counter // FIXME: Move this out of LibJS (e.g. by using the CustomData concept), as it's used exclusively by LibWeb.