change hash generation of global event handlers

Small change inspired from #1475.
This commit is contained in:
Halil Durak
2026-02-06 22:35:35 +03:00
parent 7c4c80fe4a
commit 6d2ef9be5d
2 changed files with 42 additions and 23 deletions

View File

@@ -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, .{
const gop = try self._element_attr_listeners.getOrPut(self.arena, key); .target = element.asEventTarget(),
.handler = listener_type,
});
gop.value_ptr.* = listener_callback; gop.value_ptr.* = listener_callback;
} }
@@ -1257,8 +1259,10 @@ pub fn getAttrListener(
element: *Element, element: *Element,
listener_type: GlobalEventHandler, listener_type: GlobalEventHandler,
) ?JS.Function.Global { ) ?JS.Function.Global {
const key = global_event_handlers.calculateKey(element.asEventTarget(), listener_type); return self._element_attr_listeners.get(.{
return self._element_attr_listeners.get(key); .target = element.asEventTarget(),
.handler = listener_type,
});
} }
pub fn registerPerformanceObserver(self: *Page, observer: *PerformanceObserver) !void { pub fn registerPerformanceObserver(self: *Page, observer: *PerformanceObserver) !void {

View File

@@ -23,13 +23,41 @@ const js = @import("../js/js.zig");
const EventTarget = @import("EventTarget.zig"); const EventTarget = @import("EventTarget.zig");
/// Better to discriminate it since not directly a pointer int. const Key = struct {
/// target: *EventTarget,
/// See `calculateKey` to obtain one. handler: Handler,
const Key = u64;
/// Use `calculateKey` to create a key. /// Fuses `target` pointer and `handler` enum; used at hashing.
pub const Lookup = std.AutoHashMapUnmanaged(Key, js.Function.Global); /// 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) /// Enum of known event listeners; increasing the size of it (u7)
/// can cause `Key` to behave incorrectly. /// can cause `Key` to behave incorrectly.
@@ -130,16 +158,3 @@ pub const Handler = enum(u7) {
onwaiting, onwaiting,
onwheel, 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);
}