LibJS: Don't make extra copies of every JS function's source code

Instead, let functions have a view into the AST's SourceCode object's
underlying string data. The source string is kept alive by the AST, so
it's fine to have views into it as long as the AST exists.

Reduces memory footprint on my x.com home feed by 65 MiB.
This commit is contained in:
Andreas Kling
2025-12-20 14:23:47 -06:00
committed by Andreas Kling
parent 9c8322d1b3
commit 63eccc5640
Notes: github-actions[bot] 2025-12-21 16:07:21 +00:00
9 changed files with 120 additions and 42 deletions

View File

@@ -30,8 +30,16 @@ class JS_API ECMAScriptFunctionObject final : public FunctionObject {
GC_DECLARE_ALLOCATOR(ECMAScriptFunctionObject);
public:
static GC::Ref<ECMAScriptFunctionObject> create(Realm&, Utf16FlyString name, ByteString source_text, Statement const& ecmascript_code, NonnullRefPtr<FunctionParameters const> parameters, i32 function_length, Vector<LocalVariable> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
static GC::Ref<ECMAScriptFunctionObject> create(Realm&, Utf16FlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, NonnullRefPtr<FunctionParameters const> parameters, i32 function_length, Vector<LocalVariable> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
static GC::Ref<ECMAScriptFunctionObject> create(Realm&, Utf16FlyString name, Utf16String source_text, Statement const& ecmascript_code, NonnullRefPtr<FunctionParameters const> parameters, i32 function_length, Vector<LocalVariable> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
static GC::Ref<ECMAScriptFunctionObject> create(Realm&, Utf16FlyString name, Utf16View source_text, Statement const& ecmascript_code, NonnullRefPtr<FunctionParameters const> parameters, i32 function_length, Vector<LocalVariable> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
static GC::Ref<ECMAScriptFunctionObject> create(Realm&, Utf16FlyString name, Object& prototype, Utf16View source_text, Statement const& ecmascript_code, NonnullRefPtr<FunctionParameters const> parameters, i32 function_length, Vector<LocalVariable> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
[[nodiscard]] static GC::Ref<ECMAScriptFunctionObject> create_from_function_data(
GC::Ref<Realm>,
GC::Ref<SharedFunctionInstanceData>,
GC::Ptr<Environment>,
GC::Ptr<PrivateEnvironment>,
Object& prototype);
[[nodiscard]] static GC::Ref<ECMAScriptFunctionObject> create_from_function_node(
FunctionNode const&,
@@ -79,8 +87,8 @@ public:
Object* home_object() const { return m_home_object; }
void set_home_object(Object* home_object) { m_home_object = home_object; }
[[nodiscard]] ByteString const& source_text() const { return shared_data().m_source_text; }
void set_source_text(ByteString source_text) { const_cast<SharedFunctionInstanceData&>(shared_data()).m_source_text = move(source_text); }
[[nodiscard]] Utf16View source_text() const { return shared_data().m_source_text; }
void set_source_text(Utf16View source_text) { const_cast<SharedFunctionInstanceData&>(shared_data()).m_source_text = move(source_text); }
Vector<ClassFieldDefinition> const& fields() const { return ensure_class_data().fields; }
void add_field(ClassFieldDefinition field) { ensure_class_data().fields.append(move(field)); }