mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Previously, we used a boolean, `_v8_handoff` to detect whether or not an event
was handed off to v8. When it _was_ handed off, then we relied on the Global
finalizer (or context shutdown) to cleanup the instance. When it wasn't handed
off, we could immediately free the instance.
The issue is that, under pressure, v8 might finalize the event _before_ we've
checked the handoff flag. This was the old code:
```zig
const event = try Event.initTrusted(.wrap("DOMContentLoaded"), .{ .bubbles = true }, self);
defer if (!event._v8_handoff) event.deinit(false);
try self._event_manager.dispatch(
self.document.asEventTarget(),
event,
);
```
But what happens if, during the call to dispatch, v8 finalizes the event? The
defer statement will access event after its been freed.
Rather than a boolean, we now track a basic reference count. deinit decreases
the reference count, and only frees the object when it reaches 0. Any handoff
to v8 automatically increases the reference count by 1. The above code becomes
a simpler:
```zig
const event = try Event.initTrusted(.wrap("DOMContentLoaded"), .{ .bubbles = true }, self);
defer event.deinit(false);
try self._event_manager.dispatch(
self.document.asEventTarget(),
event,
);
```
The deinit is un-conditional. The dispatch function itself increases the RC by 1,
and then the v8 handoff increases it to 2. On v8 finalization the RC is
decreased to 1. The defer deinit decreases it to 0, at which point it is freed.
Fixes WPT /css/css-transitions/properties-value-003.html