From 7a5cade51029b72a3e5c3a2ee2f1d35ef7257f5c Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Thu, 13 Nov 2025 20:30:02 +0800 Subject: [PATCH] remove 16 bytes from Element --- src/browser/Page.zig | 12 +++++++--- src/browser/webapi/Element.zig | 26 +++++++++++---------- src/browser/webapi/element/DOMStringMap.zig | 2 +- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index fa1c9fdd..47d5f123 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -63,8 +63,11 @@ _attribute_lookup: std.AutoHashMapUnmanaged(usize, *Element.Attribute), // the return of elements.attributes. _attribute_named_node_map_lookup: std.AutoHashMapUnmanaged(usize, *Element.Attribute.NamedNodeMap), -// element.dataset -> DOMStringMap -_element_datasets: std.AutoHashMapUnmanaged(*Element, *Element.DOMStringMap), +// Lazily-created style, classList, and dataset objects. Only stored for elements +// that actually access these features via JavaScript, saving 24 bytes per element. +_element_styles: Element.StyleLookup = .{}, +_element_datasets: Element.DatasetLookup = .{}, +_element_class_lists: Element.ClassListLookup = .{}, _script_manager: ScriptManager, @@ -155,7 +158,6 @@ fn reset(self: *Page, comptime initializing: bool) !void { self._load_state = .parsing; self._attribute_lookup = .empty; self._attribute_named_node_map_lookup = .empty; - self._element_datasets = .empty; self._event_manager = EventManager.init(self); self._script_manager = ScriptManager.init(self); @@ -164,6 +166,10 @@ fn reset(self: *Page, comptime initializing: bool) !void { self.js = try self._session.executor.createContext(self, true, JS.GlobalMissingCallback.init(&self._polyfill_loader)); errdefer self.js.deinit(); + self._element_styles = .{}; + self._element_datasets = .{}; + self._element_class_lists = .{}; + try polyfill.preload(self.arena, self.js); try self.registerBackgroundTasks(); } diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index 7849e3e3..c29ad4c7 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -21,6 +21,10 @@ pub const Html = @import("element/Html.zig"); const Element = @This(); +pub const DatasetLookup = std.AutoHashMapUnmanaged(*Element, *DOMStringMap); +pub const StyleLookup = std.AutoHashMapUnmanaged(*Element, *CSSStyleProperties); +pub const ClassListLookup = std.AutoHashMapUnmanaged(*Element, *collections.DOMTokenList); + pub const Namespace = enum(u8) { html, svg, @@ -41,8 +45,6 @@ _type: Type, _proto: *Node, _namespace: Namespace = .html, _attributes: ?*Attribute.List = null, -_style: ?*CSSStyleProperties = null, -_class_list: ?*collections.DOMTokenList = null, pub const Type = union(enum) { html: *Html, @@ -333,22 +335,22 @@ pub fn getAttributeNamedNodeMap(self: *Element, page: *Page) !*Attribute.NamedNo } pub fn getStyle(self: *Element, page: *Page) !*CSSStyleProperties { - return self._style orelse blk: { - const s = try CSSStyleProperties.init(self, page); - self._style = s; - break :blk s; - }; + const gop = try page._element_styles.getOrPut(page.arena, self); + if (!gop.found_existing) { + gop.value_ptr.* = try CSSStyleProperties.init(self, page); + } + return gop.value_ptr.*; } pub fn getClassList(self: *Element, page: *Page) !*collections.DOMTokenList { - return self._class_list orelse blk: { - const cl = try page._factory.create(collections.DOMTokenList{ + const gop = try page._element_class_lists.getOrPut(page.arena, self); + if (!gop.found_existing) { + gop.value_ptr.* = try page._factory.create(collections.DOMTokenList{ ._element = self, ._attribute_name = "class", }); - self._class_list = cl; - break :blk cl; - }; + } + return gop.value_ptr.*; } pub fn getDataset(self: *Element, page: *Page) !*DOMStringMap { diff --git a/src/browser/webapi/element/DOMStringMap.zig b/src/browser/webapi/element/DOMStringMap.zig index b2aa8bab..4fd02955 100644 --- a/src/browser/webapi/element/DOMStringMap.zig +++ b/src/browser/webapi/element/DOMStringMap.zig @@ -83,5 +83,5 @@ pub const JsApi = struct { pub var class_id: bridge.ClassId = undefined; }; - pub const @"[]" = bridge.namedIndexed(_getProperty, _setProperty, _deleteProperty, .{.null_as_undefined = true}); + pub const @"[]" = bridge.namedIndexed(_getProperty, _setProperty, _deleteProperty, .{ .null_as_undefined = true }); };