Move runMicrotask from Context to Local

This ensures that there's always a HandleScope avaialble when running microtasks
This commit is contained in:
Karl Seguin
2026-01-21 15:40:32 +08:00
parent c27ab35600
commit 8b8bee4e9c
7 changed files with 27 additions and 26 deletions

View File

@@ -137,7 +137,10 @@ pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) !void
var was_handled = false; var was_handled = false;
defer if (was_handled) { defer if (was_handled) {
self.page.js.runMicrotasks(); var ls: js.Local.Scope = undefined;
self.page.js.localScope(&ls);
defer ls.deinit();
ls.local.runMicrotasks();
}; };
switch (target._type) { switch (target._type) {
@@ -180,7 +183,10 @@ pub fn dispatchWithFunction(self: *EventManager, target: *EventTarget, event: *E
var was_dispatched = false; var was_dispatched = false;
defer if (was_dispatched) { defer if (was_dispatched) {
self.page.js.runMicrotasks(); var ls: js.Local.Scope = undefined;
self.page.js.localScope(&ls);
defer ls.deinit();
ls.local.runMicrotasks();
}; };
if (function_) |func| { if (function_) |func| {

View File

@@ -205,9 +205,14 @@ pub fn deinit(self: *Page) void {
// stats.print(&stream) catch unreachable; // stats.print(&stream) catch unreachable;
} }
{
// some MicroTasks might be referencing the page, we need to drain it while // some MicroTasks might be referencing the page, we need to drain it while
// the page still exists // the page still exists
self.js.runMicrotasks(); var ls: JS.Local.Scope = undefined;
self.js.localScope(&ls);
defer ls.deinit();
ls.local.runMicrotasks();
}
const session = self._session; const session = self._session;
session.executor.removeContext(); session.executor.removeContext();
@@ -958,16 +963,6 @@ fn printWaitAnalysis(self: *Page) void {
} }
} }
pub fn tick(self: *Page) void {
if (comptime IS_DEBUG) {
log.debug(.page, "tick", .{});
}
_ = self.scheduler.run() catch |err| {
log.err(.page, "tick", .{ .err = err });
};
self.js.runMicrotasks();
}
pub fn isGoingAway(self: *const Page) bool { pub fn isGoingAway(self: *const Page) bool {
return self._queued_navigation != null; return self._queued_navigation != null;
} }

View File

@@ -843,7 +843,7 @@ pub const Script = struct {
defer { defer {
// We should run microtasks even if script execution fails. // We should run microtasks even if script execution fails.
page.js.runMicrotasks(); local.runMicrotasks();
_ = page.scheduler.run() catch |err| { _ = page.scheduler.run() catch |err| {
log.err(.page, "scheduler", .{ .err = err }); log.err(.page, "scheduler", .{ .err = err });
}; };

View File

@@ -384,10 +384,6 @@ fn newFunctionWithData(local: *const js.Local, comptime callback: *const fn (?*c
}; };
} }
pub fn runMicrotasks(self: *Context) void {
self.isolate.performMicrotasksCheckpoint();
}
// == Callbacks == // == Callbacks ==
// Callback from V8, asking us to load a module. The "specifier" is // Callback from V8, asking us to load a module. The "specifier" is
// the src of the module to load. // the src of the module to load.
@@ -669,7 +665,7 @@ fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptM
} }
fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, module_entry: ModuleEntry, local: *const js.Local) void { fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, module_entry: ModuleEntry, local: *const js.Local) void {
defer self.runMicrotasks(); defer local.runMicrotasks();
// we can only be here if the module has been evaluated and if // we can only be here if the module has been evaluated and if
// we have a resolve loading this asynchronously. // we have a resolve loading this asynchronously.
@@ -706,7 +702,7 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
return; return;
} }
const l = c.local; const l = c.local;
defer l.ctx.runMicrotasks(); defer l.runMicrotasks();
const namespace = l.toLocal(s.module.?).getModuleNamespace(); const namespace = l.toLocal(s.module.?).getModuleNamespace();
_ = l.toLocal(s.resolver).resolve("resolve namespace", namespace); _ = l.toLocal(s.resolver).resolve("resolve namespace", namespace);
} }
@@ -728,7 +724,7 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
return; return;
} }
defer ctx.runMicrotasks(); defer l.runMicrotasks();
_ = l.toLocal(s.resolver).reject("catch callback", js.Value{ _ = l.toLocal(s.resolver).reject("catch callback", js.Value{
.local = l, .local = l,
.handle = v8.v8__FunctionCallbackInfo__Data(callback_handle).?, .handle = v8.v8__FunctionCallbackInfo__Data(callback_handle).?,

View File

@@ -72,6 +72,10 @@ pub fn newArray(self: *const Local, len: u32) js.Array {
}; };
} }
pub fn runMicrotasks(self: *const Local) void {
self.isolate.performMicrotasksCheckpoint();
}
// == Executors == // == Executors ==
pub fn eval(self: *const Local, src: []const u8, name: ?[]const u8) !void { pub fn eval(self: *const Local, src: []const u8, name: ?[]const u8) !void {
_ = try self.exec(src, name); _ = try self.exec(src, name);

View File

@@ -54,7 +54,7 @@ fn _resolve(self: PromiseResolver, value: anytype) !void {
if (!out.has_value or !out.value) { if (!out.has_value or !out.value) {
return error.FailedToResolvePromise; return error.FailedToResolvePromise;
} }
local.ctx.runMicrotasks(); local.runMicrotasks();
} }
pub fn reject(self: PromiseResolver, comptime source: []const u8, value: anytype) void { pub fn reject(self: PromiseResolver, comptime source: []const u8, value: anytype) void {
@@ -72,7 +72,7 @@ fn _reject(self: PromiseResolver, value: anytype) !void {
if (!out.has_value or !out.value) { if (!out.has_value or !out.value) {
return error.FailedToRejectPromise; return error.FailedToRejectPromise;
} }
local.ctx.runMicrotasks(); local.runMicrotasks();
} }
pub fn persist(self: PromiseResolver) !Global { pub fn persist(self: PromiseResolver) !Global {

View File

@@ -586,7 +586,7 @@ const ScheduleCallback = struct {
defer self.deinit(); defer self.deinit();
_ = page.window._timers.remove(self.timer_id); _ = page.window._timers.remove(self.timer_id);
page.js.runMicrotasks(); ls.local.runMicrotasks();
return null; return null;
} }
}; };