From 5aa1d7837fe37dd203763178df3325ff8b24abbd Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 10 Nov 2024 13:03:38 +0100 Subject: [PATCH] LibJS: Don't leak class field initializers We were storing these in Handle (strong GC roots) hanging off of ECMAScriptFunctionObject which effectively turned into world leaks. --- Libraries/LibJS/AST.cpp | 4 ++-- Libraries/LibJS/Runtime/ClassFieldDefinition.h | 4 ++-- Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp | 1 + Libraries/LibJS/Runtime/Object.cpp | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index c188c8577d2..919b90e2245 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -227,7 +227,7 @@ ThrowCompletionOr ClassField::class_element_evaluation auto& realm = *vm.current_realm(); auto property_key_or_private_name = TRY(class_key_to_property_name(vm, *m_key, property_key)); - Handle initializer {}; + GCPtr initializer; if (m_initializer) { auto copy_initializer = m_initializer; auto name = property_key_or_private_name.visit( @@ -370,7 +370,7 @@ ThrowCompletionOr ClassExpression::create_class_const ConservativeVector static_private_methods(vm.heap()); ConservativeVector instance_private_methods(vm.heap()); - Vector instance_fields; + ConservativeVector instance_fields(vm.heap()); Vector static_elements; for (size_t element_index = 0; element_index < m_elements.size(); element_index++) { diff --git a/Libraries/LibJS/Runtime/ClassFieldDefinition.h b/Libraries/LibJS/Runtime/ClassFieldDefinition.h index aa03b111c8e..6e97461aed4 100644 --- a/Libraries/LibJS/Runtime/ClassFieldDefinition.h +++ b/Libraries/LibJS/Runtime/ClassFieldDefinition.h @@ -17,8 +17,8 @@ using ClassElementName = Variant; // 6.2.10 The ClassFieldDefinition Record Specification Type, https://tc39.es/ecma262/#sec-classfielddefinition-record-specification-type struct ClassFieldDefinition { - ClassElementName name; // [[Name]] - Handle initializer; // [[Initializer]] + ClassElementName name; // [[Name]] + GCPtr initializer; // [[Initializer]] }; } diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index c6123c4389c..793f5f6a1b0 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -544,6 +544,7 @@ void ECMAScriptFunctionObject::visit_edges(Visitor& visitor) visitor.visit(m_bytecode_executable); for (auto& field : m_fields) { + visitor.visit(field.initializer); 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/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index fa5a26bf4b6..7297744d86c 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -663,9 +663,9 @@ ThrowCompletionOr Object::define_field(ClassFieldDefinition const& field) auto init_value = js_undefined(); // 3. If initializer is not empty, then - if (!initializer.is_null()) { + if (initializer) { // a. Let initValue be ? Call(initializer, receiver). - init_value = TRY(call(vm, initializer.cell(), this)); + init_value = TRY(call(vm, initializer, this)); } // 4. Else, let initValue be undefined.