Переглянути джерело

LibJS: Make Bytecode::Executable GC-allocated

This is a step towards making ExecutionContext easier to allocate.
Andreas Kling 1 рік тому
батько
коміт
ecfcc9aef3

+ 4 - 4
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<Bytecode::Executable> m_bytecode_executable;
+    Handle<Bytecode::Executable> m_bytecode_executable;
 };
 
 // 14.13 Labelled Statements, https://tc39.es/ecma262/#sec-labelled-statements
@@ -685,7 +685,7 @@ struct FunctionParameter {
     Variant<NonnullRefPtr<Identifier const>, NonnullRefPtr<BindingPattern const>> binding;
     RefPtr<Expression const> default_value;
     bool is_rest { false };
-    RefPtr<Bytecode::Executable> bytecode_executable {};
+    Handle<Bytecode::Executable> bytecode_executable {};
 };
 
 class FunctionNode {

+ 2 - 0
Userland/Libraries/LibJS/Bytecode/Executable.cpp

@@ -13,6 +13,8 @@
 
 namespace JS::Bytecode {
 
+JS_DEFINE_ALLOCATOR(Executable);
+
 Executable::Executable(
     NonnullOwnPtr<IdentifierTable> identifier_table,
     NonnullOwnPtr<StringTable> string_table,

+ 7 - 2
Userland/Libraries/LibJS/Bytecode/Executable.h

@@ -15,6 +15,8 @@
 #include <LibJS/Bytecode/Label.h>
 #include <LibJS/Bytecode/StringTable.h>
 #include <LibJS/Forward.h>
+#include <LibJS/Heap/Cell.h>
+#include <LibJS/Heap/CellAllocator.h>
 #include <LibJS/Runtime/EnvironmentCoordinate.h>
 
 namespace JS::JIT {
@@ -46,7 +48,10 @@ struct SourceRecord {
     u32 source_end_offset {};
 };
 
-class Executable final : public RefCounted<Executable> {
+class Executable final : public Cell {
+    JS_CELL(Executable, Cell);
+    JS_DECLARE_ALLOCATOR(Executable);
+
 public:
     Executable(
         NonnullOwnPtr<IdentifierTable>,
@@ -60,7 +65,7 @@ public:
         Vector<NonnullOwnPtr<BasicBlock>>,
         bool is_strict_mode);
 
-    ~Executable();
+    virtual ~Executable() override;
 
     DeprecatedFlyString name;
     Vector<PropertyLookupCache> property_lookup_caches;

+ 4 - 3
Userland/Libraries/LibJS/Bytecode/Generator.cpp

@@ -11,6 +11,7 @@
 #include <LibJS/Bytecode/Instruction.h>
 #include <LibJS/Bytecode/Op.h>
 #include <LibJS/Bytecode/Register.h>
+#include <LibJS/Runtime/VM.h>
 
 namespace JS::Bytecode {
 
@@ -21,7 +22,7 @@ Generator::Generator()
 {
 }
 
-CodeGenerationErrorOr<NonnullRefPtr<Executable>> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind)
+CodeGenerationErrorOr<NonnullGCPtr<Executable>> 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<NonnullRefPtr<Executable>> Generator::generate(ASTNode con
     else if (is<FunctionExpression>(node))
         is_strict_mode = static_cast<FunctionExpression const&>(node).is_strict_mode();
 
-    auto executable = adopt_ref(*new Executable(
+    auto executable = vm.heap().allocate_without_realm<Executable>(
         move(generator.m_identifier_table),
         move(generator.m_string_table),
         move(generator.m_regex_table),
@@ -67,7 +68,7 @@ CodeGenerationErrorOr<NonnullRefPtr<Executable>> 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;
 }

+ 1 - 1
Userland/Libraries/LibJS/Bytecode/Generator.h

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

+ 1 - 1
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<Executable const> m_executable;
+    GCPtr<Executable const> m_executable;
 };
 
 }

+ 3 - 3
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

@@ -105,7 +105,7 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, JS::GCPtr<Envir
 
     // 13. If result.[[Type]] is normal, then
     if (result.type() == Completion::Type::Normal) {
-        auto executable_result = JS::Bytecode::Generator::generate(script);
+        auto executable_result = JS::Bytecode::Generator::generate(vm, script);
 
         if (executable_result.is_error()) {
             if (auto error_string = executable_result.error().to_string(); error_string.is_error())
@@ -451,9 +451,9 @@ void Interpreter::enter_object_environment(Object& object)
     vm().running_execution_context().lexical_environment = new_object_environment(object, true, old_environment);
 }
 
-ThrowCompletionOr<NonnullRefPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name)
+ThrowCompletionOr<NonnullGCPtr<Bytecode::Executable>> 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<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
 

+ 1 - 1
Userland/Libraries/LibJS/Bytecode/Interpreter.h

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

+ 1 - 1
Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp

@@ -679,7 +679,7 @@ ThrowCompletionOr<Value> 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<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
 

+ 4 - 0
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<PropertyKey>(); property_key_ptr && property_key_ptr->is_symbol())
             visitor.visit(property_key_ptr->as_symbol());

+ 2 - 2
Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h

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

+ 3 - 0
Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp

@@ -6,6 +6,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <LibJS/Bytecode/Executable.h>
 #include <LibJS/Runtime/ExecutionContext.h>
 #include <LibJS/Runtime/FunctionObject.h>
 
@@ -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<Bytecode::Executable*>(instruction_stream_iterator.value().executable()));
     script_or_module.visit(
         [](Empty) {},
         [&](auto& script_or_module) {

+ 1 - 1
Userland/Libraries/LibJS/Runtime/ExecutionContext.h

@@ -55,7 +55,7 @@ public:
     MarkedVector<Value> local_variables;
     bool is_strict_mode { false };
 
-    RefPtr<Bytecode::Executable> executable;
+    GCPtr<Bytecode::Executable> 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.