mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 09:35:59 -04:00
Better handle v8 callback with no valid context
In https://github.com/lightpanda-io/browser/pull/1885 we added fallback to the incumbent context when the current context had be released (by us, but not by v8). This now handles the case where there is no incumbent context. It's not clear exactly why this can happen, but we do see it in some WPT tests (e.g. /html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.html)
This commit is contained in:
@@ -39,9 +39,22 @@ prev_local: ?*const js.Local,
|
||||
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 ctx, const v8_context = Context.fromIsolate(.{ .handle = v8_isolate });
|
||||
// Returns false if the context has been destroyed (e.g., navigated-away iframe),
|
||||
// in which case a JS exception has been thrown and the caller should return immediately.
|
||||
pub fn init(self: *Caller, v8_isolate: *v8.Isolate) bool {
|
||||
const ctx, const v8_context = Context.fromIsolate(.{ .handle = v8_isolate }) orelse {
|
||||
throwDetachedError(v8_isolate);
|
||||
return false;
|
||||
};
|
||||
initWithContext(self, ctx, v8_context);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn throwDetachedError(isolate: *v8.Isolate) void {
|
||||
const message = "Cannot execute in detached context (e.g., navigated-away iframe)";
|
||||
const v8_message = v8.v8__String__NewFromUtf8(isolate, message.ptr, v8.kNormal, @intCast(message.len));
|
||||
const js_exception = v8.v8__Exception__Error(v8_message);
|
||||
_ = v8.v8__Isolate__ThrowException(isolate, js_exception);
|
||||
}
|
||||
|
||||
fn initWithContext(self: *Caller, ctx: *Context, v8_context: *const v8.Context) void {
|
||||
@@ -60,9 +73,9 @@ fn initWithContext(self: *Caller, ctx: *Context, v8_context: *const v8.Context)
|
||||
ctx.local = &self.local;
|
||||
}
|
||||
|
||||
pub fn initFromHandle(self: *Caller, handle: ?*const v8.FunctionCallbackInfo) void {
|
||||
pub fn initFromHandle(self: *Caller, handle: ?*const v8.FunctionCallbackInfo) bool {
|
||||
const isolate = v8.v8__FunctionCallbackInfo__GetIsolate(handle).?;
|
||||
self.init(isolate);
|
||||
return self.init(isolate);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Caller) void {
|
||||
@@ -538,7 +551,10 @@ 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 ctx, const v8_context = Context.fromIsolate(.{ .handle = v8_isolate });
|
||||
const ctx, const v8_context = Context.fromIsolate(.{ .handle = v8_isolate }) orelse {
|
||||
throwDetachedError(v8_isolate);
|
||||
return;
|
||||
};
|
||||
const info = FunctionCallbackInfo{ .handle = info_handle };
|
||||
|
||||
var hs: js.HandleScope = undefined;
|
||||
|
||||
@@ -138,7 +138,8 @@ pub fn fromC(c_context: *const v8.Context) ?*Context {
|
||||
/// 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 } {
|
||||
/// Returns null if neither context has a valid Context struct (both were destroyed).
|
||||
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 };
|
||||
@@ -146,7 +147,8 @@ pub fn fromIsolate(isolate: js.Isolate) struct { *Context, *const 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 };
|
||||
const ctx = fromC(v8_incumbent) orelse return null;
|
||||
return .{ ctx, v8_incumbent };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Context) void {
|
||||
@@ -806,7 +808,9 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
||||
const then_callback = newFunctionWithData(local, struct {
|
||||
pub fn callback(callback_handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void {
|
||||
var c: Caller = undefined;
|
||||
c.initFromHandle(callback_handle);
|
||||
if (!c.initFromHandle(callback_handle)) {
|
||||
return;
|
||||
}
|
||||
defer c.deinit();
|
||||
|
||||
const info = Caller.FunctionCallbackInfo{ .handle = callback_handle.? };
|
||||
@@ -830,7 +834,7 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
||||
const catch_callback = newFunctionWithData(local, struct {
|
||||
pub fn callback(callback_handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void {
|
||||
var c: Caller = undefined;
|
||||
c.initFromHandle(callback_handle);
|
||||
if (!c.initFromHandle(callback_handle)) return;
|
||||
defer c.deinit();
|
||||
|
||||
const info = Caller.FunctionCallbackInfo{ .handle = callback_handle.? };
|
||||
|
||||
@@ -519,7 +519,7 @@ fn promiseRejectCallback(message_handle: v8.PromiseRejectMessage) callconv(.c) v
|
||||
const promise_handle = v8.v8__PromiseRejectMessage__GetPromise(&message_handle).?;
|
||||
const v8_isolate = v8.v8__Object__GetIsolate(@ptrCast(promise_handle)).?;
|
||||
const isolate = js.Isolate{ .handle = v8_isolate };
|
||||
const ctx, const v8_context = Context.fromIsolate(isolate);
|
||||
const ctx, const v8_context = Context.fromIsolate(isolate) orelse return;
|
||||
|
||||
const local = js.Local{
|
||||
.ctx = ctx,
|
||||
|
||||
@@ -116,7 +116,9 @@ pub const Constructor = struct {
|
||||
fn wrap(handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void {
|
||||
const v8_isolate = v8.v8__FunctionCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
caller.constructor(T, func, handle.?, .{
|
||||
@@ -216,7 +218,9 @@ pub const Indexed = struct {
|
||||
fn wrap(idx: u32, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.getIndex(T, getter, idx, handle.?, .{
|
||||
@@ -232,7 +236,9 @@ pub const Indexed = struct {
|
||||
fn wrap(handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
return caller.getEnumerator(T, enumerator, handle.?, .{});
|
||||
}
|
||||
@@ -258,7 +264,9 @@ pub const NamedIndexed = struct {
|
||||
fn wrap(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.getNamedIndex(T, getter, c_name.?, handle.?, .{
|
||||
@@ -272,7 +280,9 @@ pub const NamedIndexed = struct {
|
||||
fn wrap(c_name: ?*const v8.Name, c_value: ?*const v8.Value, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.setNamedIndex(T, setter, c_name.?, c_value.?, handle.?, .{
|
||||
@@ -286,7 +296,9 @@ pub const NamedIndexed = struct {
|
||||
fn wrap(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.deleteNamedIndex(T, deleter, c_name.?, handle.?, .{
|
||||
@@ -387,7 +399,9 @@ pub const Property = struct {
|
||||
pub fn unknownWindowPropertyCallback(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
const local = &caller.local;
|
||||
@@ -465,7 +479,9 @@ pub fn unknownObjectPropertyCallback(comptime JsApi: type) *const fn (?*const v8
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
|
||||
var caller: Caller = undefined;
|
||||
caller.init(v8_isolate);
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return 0;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
const local = &caller.local;
|
||||
|
||||
Reference in New Issue
Block a user