Merge pull request #1885 from lightpanda-io/danling_context_fallback

Fallback to the Incumbent Context when the Current Context is dangling
This commit is contained in:
Karl Seguin
2026-03-18 19:41:38 +08:00
committed by GitHub
3 changed files with 29 additions and 16 deletions

View File

@@ -40,8 +40,8 @@ prev_context: *Context,
// Takes the raw v8 isolate and extracts the context from it.
pub fn init(self: *Caller, v8_isolate: *v8.Isolate) void {
const v8_context = v8.v8__Isolate__GetCurrentContext(v8_isolate).?;
initWithContext(self, Context.fromC(v8_context), v8_context);
const ctx, const v8_context = Context.fromIsolate(.{ .handle = v8_isolate });
initWithContext(self, ctx, v8_context);
}
fn initWithContext(self: *Caller, ctx: *Context, v8_context: *const v8.Context) void {
@@ -537,9 +537,7 @@ pub const Function = struct {
pub fn call(comptime T: type, info_handle: *const v8.FunctionCallbackInfo, func: anytype, comptime opts: Opts) void {
const v8_isolate = v8.v8__FunctionCallbackInfo__GetIsolate(info_handle).?;
const v8_context = v8.v8__Isolate__GetCurrentContext(v8_isolate).?;
const ctx = Context.fromC(v8_context);
const ctx, const v8_context = Context.fromIsolate(.{ .handle = v8_isolate });
const info = FunctionCallbackInfo{ .handle = info_handle };
var hs: js.HandleScope = undefined;

View File

@@ -119,12 +119,22 @@ const ModuleEntry = struct {
resolver_promise: ?js.Promise.Global = null,
};
pub fn fromC(c_context: *const v8.Context) *Context {
pub fn fromC(c_context: *const v8.Context) ?*Context {
return @ptrCast(@alignCast(v8.v8__Context__GetAlignedPointerFromEmbedderData(c_context, 1)));
}
pub fn fromIsolate(isolate: js.Isolate) *Context {
return fromC(v8.v8__Isolate__GetCurrentContext(isolate.handle).?);
/// Returns the Context and v8::Context for the given isolate.
/// If the current context is from a destroyed Context (e.g., navigated-away iframe),
/// falls back to the incumbent context (the calling context).
pub fn fromIsolate(isolate: js.Isolate) struct { *Context, *const v8.Context } {
const v8_context = v8.v8__Isolate__GetCurrentContext(isolate.handle).?;
if (fromC(v8_context)) |ctx| {
return .{ ctx, v8_context };
}
// The current context's Context struct has been freed (e.g., iframe navigated away).
// Fall back to the incumbent context (the calling context).
const v8_incumbent = v8.v8__Isolate__GetIncumbentContext(isolate.handle).?;
return .{ fromC(v8_incumbent).?, v8_incumbent };
}
pub fn deinit(self: *Context) void {
@@ -155,6 +165,11 @@ pub fn deinit(self: *Context) void {
self.session.releaseOrigin(self.origin);
// Clear the embedder data so that if V8 keeps this context alive
// (because objects created in it are still referenced), we don't
// have a dangling pointer to our freed Context struct.
v8.v8__Context__SetAlignedPointerInEmbedderData(entered.handle, 1, null);
v8.v8__Global__Reset(&self.handle);
env.isolate.notifyContextDisposed();
// There can be other tasks associated with this context that we need to
@@ -255,7 +270,7 @@ pub fn toLocal(self: *Context, global: anytype) js.Local.ToLocalReturnType(@Type
}
pub fn getIncumbent(self: *Context) *Page {
return fromC(v8.v8__Isolate__GetIncumbentContext(self.env.isolate.handle).?).page;
return fromC(v8.v8__Isolate__GetIncumbentContext(self.env.isolate.handle).?).?.page;
}
pub fn stringToPersistedFunction(
@@ -479,7 +494,7 @@ fn resolveModuleCallback(
) callconv(.c) ?*const v8.Module {
_ = import_attributes;
const self = fromC(c_context.?);
const self = fromC(c_context.?).?;
const local = js.Local{
.ctx = self,
.handle = c_context.?,
@@ -512,7 +527,7 @@ pub fn dynamicModuleCallback(
_ = host_defined_options;
_ = import_attrs;
const self = fromC(c_context.?);
const self = fromC(c_context.?).?;
const local = js.Local{
.ctx = self,
.handle = c_context.?,
@@ -559,7 +574,7 @@ pub fn dynamicModuleCallback(
pub fn metaObjectCallback(c_context: ?*v8.Context, c_module: ?*v8.Module, c_meta: ?*v8.Value) callconv(.c) void {
// @HandleScope implement this without a fat context/local..
const self = fromC(c_context.?);
const self = fromC(c_context.?).?;
var local = js.Local{
.ctx = self,
.handle = c_context.?,

View File

@@ -497,13 +497,13 @@ pub fn terminate(self: *const Env) void {
fn promiseRejectCallback(message_handle: v8.PromiseRejectMessage) callconv(.c) void {
const promise_handle = v8.v8__PromiseRejectMessage__GetPromise(&message_handle).?;
const v8_isolate = v8.v8__Object__GetIsolate(@ptrCast(promise_handle)).?;
const js_isolate = js.Isolate{ .handle = v8_isolate };
const ctx = Context.fromIsolate(js_isolate);
const isolate = js.Isolate{ .handle = v8_isolate };
const ctx, const v8_context = Context.fromIsolate(isolate);
const local = js.Local{
.ctx = ctx,
.isolate = js_isolate,
.handle = v8.v8__Isolate__GetCurrentContext(v8_isolate).?,
.isolate = isolate,
.handle = v8_context,
.call_arena = ctx.call_arena,
};