mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-26 02:12:50 -04:00
History: We started with 1 context and thus only had 1 identity map. Frames were added, and we tried to stick with 1 identity map per context. That didn't work - it breaks cross-frame scripting. We introduced "Origin" so that all frames on the same origin share the same objects. That almost worked, by the v8::Inspector isn't bound by a Context's SecurityToken. So we tried 1 global identity map. But that doesn't work. CDP IsolateWorlds do, in fact, need some isolation. They need new v8::Objects created in their context, even if the object already exists in the main context. In the end, you end up with something like this: A page (and all its frames) needs 1 view of the data. And each IsolateWorld needs it own view. This commit introduces a js.Identity which is referenced by the context. The Session has a js.Identity (used by all pages), and each IsolateWorld has its own js.Identity. As a bonus, the arena pool memory-leak detection has been moved out of the session and into the ArenaPool. This means _all_ arena pool access is audited (in debug mode). This seems superfluous, but it's actually necessary since IsolateWorlds (which now own their own identity) can outlive the Page so there's no clear place to "check" for leaks - except on ArenaPool deinit.
109 lines
3.1 KiB
Zig
109 lines
3.1 KiB
Zig
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
|
//
|
|
// Francis Bouvier <francis@lightpanda.io>
|
|
// Pierre Tachoire <pierre@lightpanda.io>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
const std = @import("std");
|
|
const js = @import("js.zig");
|
|
const v8 = js.v8;
|
|
|
|
const Session = @import("../Session.zig");
|
|
|
|
const Promise = @This();
|
|
|
|
local: *const js.Local,
|
|
handle: *const v8.Promise,
|
|
|
|
pub fn toObject(self: Promise) js.Object {
|
|
return .{
|
|
.local = self.local,
|
|
.handle = @ptrCast(self.handle),
|
|
};
|
|
}
|
|
|
|
pub fn toValue(self: Promise) js.Value {
|
|
return .{
|
|
.local = self.local,
|
|
.handle = @ptrCast(self.handle),
|
|
};
|
|
}
|
|
|
|
pub fn thenAndCatch(self: Promise, on_fulfilled: js.Function, on_rejected: js.Function) !Promise {
|
|
if (v8.v8__Promise__Then2(self.handle, self.local.handle, on_fulfilled.handle, on_rejected.handle)) |handle| {
|
|
return .{
|
|
.local = self.local,
|
|
.handle = handle,
|
|
};
|
|
}
|
|
return error.PromiseChainFailed;
|
|
}
|
|
|
|
pub fn persist(self: Promise) !Global {
|
|
return self._persist(true);
|
|
}
|
|
|
|
pub fn temp(self: Promise) !Temp {
|
|
return self._persist(false);
|
|
}
|
|
|
|
fn _persist(self: *const Promise, comptime is_global: bool) !(if (is_global) Global else Temp) {
|
|
var ctx = self.local.ctx;
|
|
|
|
var global: v8.Global = undefined;
|
|
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
|
if (comptime is_global) {
|
|
try ctx.trackGlobal(global);
|
|
return .{ .handle = global, .temps = {} };
|
|
}
|
|
try ctx.trackTemp(global);
|
|
return .{ .handle = global, .temps = &ctx.identity.temps };
|
|
}
|
|
|
|
pub const Temp = G(.temp);
|
|
pub const Global = G(.global);
|
|
|
|
const GlobalType = enum(u8) {
|
|
temp,
|
|
global,
|
|
};
|
|
|
|
fn G(comptime global_type: GlobalType) type {
|
|
return struct {
|
|
handle: v8.Global,
|
|
temps: if (global_type == .temp) *std.AutoHashMapUnmanaged(usize, v8.Global) else void,
|
|
|
|
const Self = @This();
|
|
|
|
pub fn deinit(self: *Self) void {
|
|
v8.v8__Global__Reset(&self.handle);
|
|
}
|
|
|
|
pub fn local(self: *const Self, l: *const js.Local) Promise {
|
|
return .{
|
|
.local = l,
|
|
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, l.isolate.handle)),
|
|
};
|
|
}
|
|
|
|
pub fn release(self: *const Self) void {
|
|
if (self.temps.fetchRemove(self.handle.data_ptr)) |kv| {
|
|
var g = kv.value;
|
|
v8.v8__Global__Reset(&g);
|
|
}
|
|
}
|
|
};
|
|
}
|