From 6d2ef9be5d6c14533a731c9481e08f2953ce4abe Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Fri, 6 Feb 2026 22:35:35 +0300 Subject: [PATCH 1/2] change hash generation of global event handlers Small change inspired from #1475. --- src/browser/Page.zig | 12 +++-- src/browser/webapi/global_event_handlers.zig | 53 +++++++++++++------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index f07e0fb3..4996d3ef 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -1246,8 +1246,10 @@ pub fn setAttrListener( }); } - const key = global_event_handlers.calculateKey(element.asEventTarget(), listener_type); - const gop = try self._element_attr_listeners.getOrPut(self.arena, key); + const gop = try self._element_attr_listeners.getOrPut(self.arena, .{ + .target = element.asEventTarget(), + .handler = listener_type, + }); gop.value_ptr.* = listener_callback; } @@ -1257,8 +1259,10 @@ pub fn getAttrListener( element: *Element, listener_type: GlobalEventHandler, ) ?JS.Function.Global { - const key = global_event_handlers.calculateKey(element.asEventTarget(), listener_type); - return self._element_attr_listeners.get(key); + return self._element_attr_listeners.get(.{ + .target = element.asEventTarget(), + .handler = listener_type, + }); } pub fn registerPerformanceObserver(self: *Page, observer: *PerformanceObserver) !void { diff --git a/src/browser/webapi/global_event_handlers.zig b/src/browser/webapi/global_event_handlers.zig index 251fa8c6..e92dad6f 100644 --- a/src/browser/webapi/global_event_handlers.zig +++ b/src/browser/webapi/global_event_handlers.zig @@ -23,13 +23,41 @@ const js = @import("../js/js.zig"); const EventTarget = @import("EventTarget.zig"); -/// Better to discriminate it since not directly a pointer int. -/// -/// See `calculateKey` to obtain one. -const Key = u64; +const Key = struct { + target: *EventTarget, + handler: Handler, -/// Use `calculateKey` to create a key. -pub const Lookup = std.AutoHashMapUnmanaged(Key, js.Function.Global); + /// Fuses `target` pointer and `handler` enum; used at hashing. + /// NEVER use a fusion to retrieve a pointer back. Portability is not guaranteed. + /// See `Context.hash`. + fn fuse(self: *const Key) u64 { + // Check if we have 3 bits available from alignment of 8. + lp.assert(@alignOf(EventTarget) == 8, "Key.fuse: incorrect alignment", .{ + .event_target_alignment = @alignOf(EventTarget), + }); + + const ptr = @intFromPtr(self.target) >> 3; + lp.assert(ptr < (1 << 57), "Key.fuse: pointer overflow", .{ .ptr = ptr }); + return ptr | (@as(u64, @intFromEnum(self.handler)) << 57); + } +}; + +const Context = struct { + pub fn hash(_: @This(), key: Key) u64 { + return std.hash.int(key.fuse()); + } + + pub fn eql(_: @This(), a: Key, b: Key) bool { + return a.fuse() == b.fuse(); + } +}; + +pub const Lookup = std.HashMapUnmanaged( + Key, + js.Function.Global, + Context, + std.hash_map.default_max_load_percentage, +); /// Enum of known event listeners; increasing the size of it (u7) /// can cause `Key` to behave incorrectly. @@ -130,16 +158,3 @@ pub const Handler = enum(u7) { onwaiting, onwheel, }; - -/// Calculates a lookup key to use with lookup for event target. -/// NEVER use generated key to retrieve a pointer back. Portability is not guaranteed. -pub fn calculateKey(event_target: *EventTarget, handler_type: Handler) Key { - // Check if we have 3 bits available from alignment of 8. - lp.assert(@alignOf(EventTarget) == 8, "calculateKey: incorrect alignment", .{ - .event_target_alignment = @alignOf(EventTarget), - }); - - const ptr = @intFromPtr(event_target) >> 3; - lp.assert(ptr < (1 << 57), "calculateKey: pointer overflow", .{ .ptr = ptr }); - return ptr | (@as(Key, @intFromEnum(handler_type)) << 57); -} From ea69b3b4e3d6dd015634e95cb8193f084c78f304 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Wed, 11 Feb 2026 16:45:31 +0300 Subject: [PATCH 2/2] wrap assertions with `comptime if` --- src/browser/webapi/global_event_handlers.zig | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/browser/webapi/global_event_handlers.zig b/src/browser/webapi/global_event_handlers.zig index e92dad6f..44123a50 100644 --- a/src/browser/webapi/global_event_handlers.zig +++ b/src/browser/webapi/global_event_handlers.zig @@ -23,6 +23,8 @@ const js = @import("../js/js.zig"); const EventTarget = @import("EventTarget.zig"); +const IS_DEBUG = @import("builtin").mode == .Debug; + const Key = struct { target: *EventTarget, handler: Handler, @@ -32,12 +34,16 @@ const Key = struct { /// See `Context.hash`. fn fuse(self: *const Key) u64 { // Check if we have 3 bits available from alignment of 8. - lp.assert(@alignOf(EventTarget) == 8, "Key.fuse: incorrect alignment", .{ - .event_target_alignment = @alignOf(EventTarget), - }); + if (comptime IS_DEBUG) { + lp.assert(@alignOf(EventTarget) == 8, "Key.fuse: incorrect alignment", .{ + .event_target_alignment = @alignOf(EventTarget), + }); + } const ptr = @intFromPtr(self.target) >> 3; - lp.assert(ptr < (1 << 57), "Key.fuse: pointer overflow", .{ .ptr = ptr }); + if (comptime IS_DEBUG) { + lp.assert(ptr < (1 << 57), "Key.fuse: pointer overflow", .{ .ptr = ptr }); + } return ptr | (@as(u64, @intFromEnum(self.handler)) << 57); } };