mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 23:23:28 +00:00
Merge branch 'main' into css_style_declaration
This commit is contained in:
10
.github/actions/install/action.yml
vendored
10
.github/actions/install/action.yml
vendored
@@ -17,7 +17,7 @@ inputs:
|
|||||||
zig-v8:
|
zig-v8:
|
||||||
description: 'zig v8 version to install'
|
description: 'zig v8 version to install'
|
||||||
required: false
|
required: false
|
||||||
default: 'v0.1.23'
|
default: 'v0.1.24'
|
||||||
v8:
|
v8:
|
||||||
description: 'v8 version to install'
|
description: 'v8 version to install'
|
||||||
required: false
|
required: false
|
||||||
@@ -59,11 +59,11 @@ runs:
|
|||||||
- name: install v8
|
- name: install v8
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir -p v8/out/debug/obj/zig/
|
mkdir -p v8/out/${{ inputs.os }}/debug/obj/zig/
|
||||||
ln -s ${{ inputs.cache-dir }}/v8/libc_v8.a v8/out/debug/obj/zig/libc_v8.a
|
ln -s ${{ inputs.cache-dir }}/v8/libc_v8.a v8/out/${{ inputs.os }}/debug/obj/zig/libc_v8.a
|
||||||
|
|
||||||
mkdir -p v8/out/release/obj/zig/
|
mkdir -p v8/out/${{ inputs.os }}/release/obj/zig/
|
||||||
ln -s ${{ inputs.cache-dir }}/v8/libc_v8.a v8/out/release/obj/zig/libc_v8.a
|
ln -s ${{ inputs.cache-dir }}/v8/libc_v8.a v8/out/${{ inputs.os }}/release/obj/zig/libc_v8.a
|
||||||
|
|
||||||
- name: libiconv
|
- name: libiconv
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
2
.github/workflows/e2e-test.yml
vendored
2
.github/workflows/e2e-test.yml
vendored
@@ -88,7 +88,7 @@ jobs:
|
|||||||
- name: run puppeteer
|
- name: run puppeteer
|
||||||
run: |
|
run: |
|
||||||
python3 -m http.server 1234 -d ./public & echo $! > PYTHON.pid
|
python3 -m http.server 1234 -d ./public & echo $! > PYTHON.pid
|
||||||
./lightpanda serve --gc_hints & echo $! > LPD.pid
|
./lightpanda serve & echo $! > LPD.pid
|
||||||
RUNS=100 npm run bench-puppeteer-cdp > puppeteer.out || exit 1
|
RUNS=100 npm run bench-puppeteer-cdp > puppeteer.out || exit 1
|
||||||
cat /proc/`cat LPD.pid`/status |grep VmHWM|grep -oP '\d+' > LPD.VmHWM
|
cat /proc/`cat LPD.pid`/status |grep VmHWM|grep -oP '\d+' > LPD.VmHWM
|
||||||
kill `cat LPD.pid` `cat PYTHON.pid`
|
kill `cat LPD.pid` `cat PYTHON.pid`
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ ARG ZIG=0.14.0
|
|||||||
ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U
|
ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U
|
||||||
ARG ARCH=x86_64
|
ARG ARCH=x86_64
|
||||||
ARG V8=11.1.134
|
ARG V8=11.1.134
|
||||||
ARG ZIG_V8=v0.1.23
|
ARG ZIG_V8=v0.1.24
|
||||||
|
|
||||||
RUN apt-get update -yq && \
|
RUN apt-get update -yq && \
|
||||||
apt-get install -yq xz-utils \
|
apt-get install -yq xz-utils \
|
||||||
@@ -57,8 +57,8 @@ RUN make install-libiconv && \
|
|||||||
|
|
||||||
# download and install v8
|
# download and install v8
|
||||||
RUN curl --fail -L -o libc_v8.a https://github.com/lightpanda-io/zig-v8-fork/releases/download/${ZIG_V8}/libc_v8_${V8}_linux_${ARCH}.a && \
|
RUN curl --fail -L -o libc_v8.a https://github.com/lightpanda-io/zig-v8-fork/releases/download/${ZIG_V8}/libc_v8_${V8}_linux_${ARCH}.a && \
|
||||||
mkdir -p v8/build/${ARCH}-linux/release/ninja/obj/zig/ && \
|
mkdir -p v8/out/linux/release/obj/zig/ && \
|
||||||
mv libc_v8.a v8/build/${ARCH}-linux/release/ninja/obj/zig/libc_v8.a
|
mv libc_v8.a v8/out/linux/release/obj/zig/libc_v8.a
|
||||||
|
|
||||||
# build release
|
# build release
|
||||||
RUN make build
|
RUN make build
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -69,14 +69,19 @@ build:
|
|||||||
## Build in debug mode
|
## Build in debug mode
|
||||||
build-dev:
|
build-dev:
|
||||||
@printf "\e[36mBuilding (debug)...\e[0m\n"
|
@printf "\e[36mBuilding (debug)...\e[0m\n"
|
||||||
@$(ZIG) build -Dgit_commit=$$(git rev-parse --short HEAD) || (printf "\e[33mBuild ERROR\e[0m\n"; exit 1;)
|
@$(ZIG) build -Dgit_commit=$$(git rev-parse --short HEAD) -Dlog_level=debug || (printf "\e[33mBuild ERROR\e[0m\n"; exit 1;)
|
||||||
@printf "\e[33mBuild OK\e[0m\n"
|
@printf "\e[33mBuild OK\e[0m\n"
|
||||||
|
|
||||||
## Run the server in debug mode
|
## Run the server in release mode
|
||||||
run: build
|
run: build
|
||||||
@printf "\e[36mRunning...\e[0m\n"
|
@printf "\e[36mRunning...\e[0m\n"
|
||||||
@./zig-out/bin/lightpanda || (printf "\e[33mRun ERROR\e[0m\n"; exit 1;)
|
@./zig-out/bin/lightpanda || (printf "\e[33mRun ERROR\e[0m\n"; exit 1;)
|
||||||
|
|
||||||
|
## Run the server in debug mode
|
||||||
|
run-debug: build-dev
|
||||||
|
@printf "\e[36mRunning...\e[0m\n"
|
||||||
|
@./zig-out/bin/lightpanda || (printf "\e[33mRun ERROR\e[0m\n"; exit 1;)
|
||||||
|
|
||||||
## Run a JS shell in debug mode
|
## Run a JS shell in debug mode
|
||||||
shell:
|
shell:
|
||||||
@printf "\e[36mBuilding shell...\e[0m\n"
|
@printf "\e[36mBuilding shell...\e[0m\n"
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ For Debian/Ubuntu based Linux:
|
|||||||
sudo apt install xz-utils \
|
sudo apt install xz-utils \
|
||||||
python3 ca-certificates git \
|
python3 ca-certificates git \
|
||||||
pkg-config libglib2.0-dev \
|
pkg-config libglib2.0-dev \
|
||||||
gperf libexpat1-dev unzip \
|
gperf libexpat1-dev unzip rsync \
|
||||||
cmake clang
|
cmake clang
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
30
build.zig
30
build.zig
@@ -170,13 +170,30 @@ fn common(b: *std.Build, opts: *std.Build.Step.Options, step: *std.Build.Step.Co
|
|||||||
mod.addImport("v8", v8_mod);
|
mod.addImport("v8", v8_mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
const lib_path = try std.fmt.allocPrint(
|
|
||||||
mod.owner.allocator,
|
|
||||||
"v8/out/{s}/obj/zig/libc_v8.a",
|
|
||||||
.{if (mod.optimize.? == .Debug) "debug" else "release"},
|
|
||||||
);
|
|
||||||
mod.link_libcpp = true;
|
mod.link_libcpp = true;
|
||||||
mod.addObjectFile(mod.owner.path(lib_path));
|
|
||||||
|
{
|
||||||
|
const release_dir = if (mod.optimize.? == .Debug) "debug" else "release";
|
||||||
|
const os = switch (target.result.os.tag) {
|
||||||
|
.linux => "linux",
|
||||||
|
.macos => "macos",
|
||||||
|
else => return error.UnsupportedPlatform,
|
||||||
|
};
|
||||||
|
var lib_path = try std.fmt.allocPrint(
|
||||||
|
mod.owner.allocator,
|
||||||
|
"v8/out/{s}/{s}/obj/zig/libc_v8.a",
|
||||||
|
.{ os, release_dir },
|
||||||
|
);
|
||||||
|
std.fs.cwd().access(lib_path, .{}) catch {
|
||||||
|
// legacy path
|
||||||
|
lib_path = try std.fmt.allocPrint(
|
||||||
|
mod.owner.allocator,
|
||||||
|
"v8/out/{s}/obj/zig/libc_v8.a",
|
||||||
|
.{release_dir},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
mod.addObjectFile(mod.owner.path(lib_path));
|
||||||
|
}
|
||||||
|
|
||||||
switch (target.result.os.tag) {
|
switch (target.result.os.tag) {
|
||||||
.macos => {
|
.macos => {
|
||||||
@@ -188,7 +205,6 @@ fn common(b: *std.Build, opts: *std.Build.Step.Options, step: *std.Build.Step.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod.addImport("build_config", opts.createModule());
|
mod.addImport("build_config", opts.createModule());
|
||||||
mod.addObjectFile(mod.owner.path(lib_path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn moduleNetSurf(b: *std.Build, step: *std.Build.Step.Compile, target: std.Build.ResolvedTarget) !void {
|
fn moduleNetSurf(b: *std.Build, step: *std.Build.Step.Compile, target: std.Build.ResolvedTarget) !void {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
.hash = "tigerbeetle_io-0.0.0-ViLgxpyRBAB5BMfIcj3KMXfbJzwARs9uSl8aRy2OXULd",
|
.hash = "tigerbeetle_io-0.0.0-ViLgxpyRBAB5BMfIcj3KMXfbJzwARs9uSl8aRy2OXULd",
|
||||||
},
|
},
|
||||||
.v8 = .{
|
.v8 = .{
|
||||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/240140e5b3e5a8e5e51cbdd36bc120bf28ae5c31.tar.gz",
|
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/e38cb27ddb044c6afbf8a938b293721b9804405e.tar.gz",
|
||||||
.hash = "v8-0.0.0-xddH64eyAwBcX7e2x5tv9MhT0MgQbshP2rb19blo06Db",
|
.hash = "v8-0.0.0-xddH6_GzAwCaz83JWuw3sepOGq0I7C_CmfOwA1Gb9q3y",
|
||||||
},
|
},
|
||||||
//.v8 = .{ .path = "../zig-v8-fork" },
|
//.v8 = .{ .path = "../zig-v8-fork" },
|
||||||
//.tigerbeetle_io = .{ .path = "../tigerbeetle-io" },
|
//.tigerbeetle_io = .{ .path = "../tigerbeetle-io" },
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ pub const App = struct {
|
|||||||
|
|
||||||
pub const Config = struct {
|
pub const Config = struct {
|
||||||
run_mode: RunMode,
|
run_mode: RunMode,
|
||||||
gc_hints: bool = false,
|
|
||||||
tls_verify_host: bool = true,
|
tls_verify_host: bool = true,
|
||||||
http_proxy: ?std.Uri = null,
|
http_proxy: ?std.Uri = null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -86,9 +86,7 @@ pub const Browser = struct {
|
|||||||
session.deinit();
|
session.deinit();
|
||||||
self.session = null;
|
self.session = null;
|
||||||
_ = self.session_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
_ = self.session_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
||||||
if (self.app.config.gc_hints) {
|
self.env.lowMemoryNotification();
|
||||||
self.env.lowMemoryNotification();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,14 +49,14 @@ pub const Session = struct {
|
|||||||
// page and start another.
|
// page and start another.
|
||||||
transfer_arena: Allocator,
|
transfer_arena: Allocator,
|
||||||
|
|
||||||
executor: Env.Executor,
|
executor: Env.ExecutionWorld,
|
||||||
storage_shed: storage.Shed,
|
storage_shed: storage.Shed,
|
||||||
cookie_jar: storage.CookieJar,
|
cookie_jar: storage.CookieJar,
|
||||||
|
|
||||||
page: ?Page = null,
|
page: ?Page = null,
|
||||||
|
|
||||||
pub fn init(self: *Session, browser: *Browser) !void {
|
pub fn init(self: *Session, browser: *Browser) !void {
|
||||||
var executor = try browser.env.newExecutor();
|
var executor = try browser.env.newExecutionWorld();
|
||||||
errdefer executor.deinit();
|
errdefer executor.deinit();
|
||||||
|
|
||||||
const allocator = browser.app.allocator;
|
const allocator = browser.app.allocator;
|
||||||
|
|||||||
@@ -372,12 +372,11 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
return error.CurrentlyOnly1IsolatedWorldSupported;
|
return error.CurrentlyOnly1IsolatedWorldSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
var executor = try self.cdp.browser.env.newExecutor();
|
var executor = try self.cdp.browser.env.newExecutionWorld();
|
||||||
errdefer executor.deinit();
|
errdefer executor.deinit();
|
||||||
|
|
||||||
self.isolated_world = .{
|
self.isolated_world = .{
|
||||||
.name = try self.arena.dupe(u8, world_name),
|
.name = try self.arena.dupe(u8, world_name),
|
||||||
.scope = null,
|
|
||||||
.executor = executor,
|
.executor = executor,
|
||||||
.grant_universal_access = grant_universal_access,
|
.grant_universal_access = grant_universal_access,
|
||||||
};
|
};
|
||||||
@@ -511,18 +510,15 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
/// An object id is unique across all contexts, different object ids can refer to the same Node in different contexts.
|
/// An object id is unique across all contexts, different object ids can refer to the same Node in different contexts.
|
||||||
const IsolatedWorld = struct {
|
const IsolatedWorld = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
scope: ?*Env.Scope,
|
executor: Env.ExecutionWorld,
|
||||||
executor: Env.Executor,
|
|
||||||
grant_universal_access: bool,
|
grant_universal_access: bool,
|
||||||
|
|
||||||
pub fn deinit(self: *IsolatedWorld) void {
|
pub fn deinit(self: *IsolatedWorld) void {
|
||||||
self.executor.deinit();
|
self.executor.deinit();
|
||||||
self.scope = null;
|
|
||||||
}
|
}
|
||||||
pub fn removeContext(self: *IsolatedWorld) !void {
|
pub fn removeContext(self: *IsolatedWorld) !void {
|
||||||
if (self.scope == null) return error.NoIsolatedContextToRemove;
|
if (self.executor.scope == null) return error.NoIsolatedContextToRemove;
|
||||||
self.executor.endScope();
|
self.executor.endScope();
|
||||||
self.scope = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The isolate world must share at least some of the state with the related page, specifically the DocumentHTML
|
// The isolate world must share at least some of the state with the related page, specifically the DocumentHTML
|
||||||
@@ -531,8 +527,8 @@ const IsolatedWorld = struct {
|
|||||||
// This also means this pointer becomes invalid after removePage untill a new page is created.
|
// This also means this pointer becomes invalid after removePage untill a new page is created.
|
||||||
// Currently we have only 1 page/frame and thus also only 1 state in the isolate world.
|
// Currently we have only 1 page/frame and thus also only 1 state in the isolate world.
|
||||||
pub fn createContext(self: *IsolatedWorld, page: *Page) !void {
|
pub fn createContext(self: *IsolatedWorld, page: *Page) !void {
|
||||||
if (self.scope != null) return error.Only1IsolatedContextSupported;
|
if (self.executor.scope != null) return error.Only1IsolatedContextSupported;
|
||||||
self.scope = try self.executor.startScope(&page.window, &page.state, {}, false);
|
_ = try self.executor.startScope(&page.window, &page.state, {}, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -262,8 +262,8 @@ fn resolveNode(cmd: anytype) !void {
|
|||||||
var scope = page.scope;
|
var scope = page.scope;
|
||||||
if (params.executionContextId) |context_id| {
|
if (params.executionContextId) |context_id| {
|
||||||
if (scope.context.debugContextId() != context_id) {
|
if (scope.context.debugContextId() != context_id) {
|
||||||
const isolated_world = bc.isolated_world orelse return error.ContextNotFound;
|
var isolated_world = bc.isolated_world orelse return error.ContextNotFound;
|
||||||
scope = isolated_world.scope orelse return error.ContextNotFound;
|
scope = &(isolated_world.executor.scope orelse return error.ContextNotFound);
|
||||||
|
|
||||||
if (scope.context.debugContextId() != context_id) return error.ContextNotFound;
|
if (scope.context.debugContextId() != context_id) return error.ContextNotFound;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ fn createIsolatedWorld(cmd: anytype) !void {
|
|||||||
const world = try bc.createIsolatedWorld(params.worldName, params.grantUniveralAccess);
|
const world = try bc.createIsolatedWorld(params.worldName, params.grantUniveralAccess);
|
||||||
const page = bc.session.currentPage() orelse return error.PageNotLoaded;
|
const page = bc.session.currentPage() orelse return error.PageNotLoaded;
|
||||||
try pageCreated(bc, page);
|
try pageCreated(bc, page);
|
||||||
const scope = world.scope.?;
|
const scope = &world.executor.scope.?;
|
||||||
|
|
||||||
// Create the auxdata json for the contextCreated event
|
// Create the auxdata json for the contextCreated event
|
||||||
// Calling contextCreated will assign a Id to the context and send the contextCreated event
|
// Calling contextCreated will assign a Id to the context and send the contextCreated event
|
||||||
@@ -236,7 +236,7 @@ pub fn pageNavigate(bc: anytype, event: *const Notification.PageNavigate) !void
|
|||||||
const aux_json = try std.fmt.bufPrint(&buffer, "{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}", .{target_id});
|
const aux_json = try std.fmt.bufPrint(&buffer, "{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}", .{target_id});
|
||||||
// Calling contextCreated will assign a new Id to the context and send the contextCreated event
|
// Calling contextCreated will assign a new Id to the context and send the contextCreated event
|
||||||
bc.inspector.contextCreated(
|
bc.inspector.contextCreated(
|
||||||
isolated_world.scope.?,
|
&isolated_world.executor.scope.?,
|
||||||
isolated_world.name,
|
isolated_world.name,
|
||||||
"://",
|
"://",
|
||||||
aux_json,
|
aux_json,
|
||||||
@@ -258,7 +258,7 @@ pub fn pageCreated(bc: anytype, page: *Page) !void {
|
|||||||
try isolated_world.createContext(page);
|
try isolated_world.createContext(page);
|
||||||
|
|
||||||
const polyfill = @import("../../browser/polyfill/polyfill.zig");
|
const polyfill = @import("../../browser/polyfill/polyfill.zig");
|
||||||
try polyfill.load(bc.arena, isolated_world.scope.?);
|
try polyfill.load(bc.arena, &isolated_world.executor.scope.?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
src/main.zig
23
src/main.zig
@@ -70,7 +70,6 @@ pub fn main() !void {
|
|||||||
|
|
||||||
var app = try App.init(alloc, .{
|
var app = try App.init(alloc, .{
|
||||||
.run_mode = args.mode,
|
.run_mode = args.mode,
|
||||||
.gc_hints = args.gcHints(),
|
|
||||||
.http_proxy = args.httpProxy(),
|
.http_proxy = args.httpProxy(),
|
||||||
.tls_verify_host = args.tlsVerifyHost(),
|
.tls_verify_host = args.tlsVerifyHost(),
|
||||||
});
|
});
|
||||||
@@ -129,13 +128,6 @@ const Command = struct {
|
|||||||
mode: Mode,
|
mode: Mode,
|
||||||
exec_name: []const u8,
|
exec_name: []const u8,
|
||||||
|
|
||||||
fn gcHints(self: *const Command) bool {
|
|
||||||
return switch (self.mode) {
|
|
||||||
.serve => |opts| opts.gc_hints,
|
|
||||||
else => false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tlsVerifyHost(self: *const Command) bool {
|
fn tlsVerifyHost(self: *const Command) bool {
|
||||||
return switch (self.mode) {
|
return switch (self.mode) {
|
||||||
inline .serve, .fetch => |opts| opts.tls_verify_host,
|
inline .serve, .fetch => |opts| opts.tls_verify_host,
|
||||||
@@ -161,7 +153,6 @@ const Command = struct {
|
|||||||
host: []const u8,
|
host: []const u8,
|
||||||
port: u16,
|
port: u16,
|
||||||
timeout: u16,
|
timeout: u16,
|
||||||
gc_hints: bool,
|
|
||||||
tls_verify_host: bool,
|
tls_verify_host: bool,
|
||||||
http_proxy: ?std.Uri,
|
http_proxy: ?std.Uri,
|
||||||
};
|
};
|
||||||
@@ -210,9 +201,6 @@ const Command = struct {
|
|||||||
\\--timeout Inactivity timeout in seconds before disconnecting clients
|
\\--timeout Inactivity timeout in seconds before disconnecting clients
|
||||||
\\ Defaults to 3 (seconds)
|
\\ Defaults to 3 (seconds)
|
||||||
\\
|
\\
|
||||||
\\--gc_hints Encourage V8 to cleanup garbage for each new browser context.
|
|
||||||
\\ Defaults to false
|
|
||||||
\\
|
|
||||||
\\--insecure_disable_tls_host_verification
|
\\--insecure_disable_tls_host_verification
|
||||||
\\ Disables host verification on all HTTP requests.
|
\\ Disables host verification on all HTTP requests.
|
||||||
\\ This is an advanced option which should only be
|
\\ This is an advanced option which should only be
|
||||||
@@ -296,10 +284,6 @@ fn inferMode(opt: []const u8) ?App.RunMode {
|
|||||||
return .serve;
|
return .serve;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, opt, "--gc_hints")) {
|
|
||||||
return .serve;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +294,6 @@ fn parseServeArgs(
|
|||||||
var host: []const u8 = "127.0.0.1";
|
var host: []const u8 = "127.0.0.1";
|
||||||
var port: u16 = 9222;
|
var port: u16 = 9222;
|
||||||
var timeout: u16 = 3;
|
var timeout: u16 = 3;
|
||||||
var gc_hints = false;
|
|
||||||
var tls_verify_host = true;
|
var tls_verify_host = true;
|
||||||
var http_proxy: ?std.Uri = null;
|
var http_proxy: ?std.Uri = null;
|
||||||
|
|
||||||
@@ -355,11 +338,6 @@ fn parseServeArgs(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, "--gc_hints", opt)) {
|
|
||||||
gc_hints = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std.mem.eql(u8, "--http_proxy", opt)) {
|
if (std.mem.eql(u8, "--http_proxy", opt)) {
|
||||||
const str = args.next() orelse {
|
const str = args.next() orelse {
|
||||||
log.err("--http_proxy argument requires an value", .{});
|
log.err("--http_proxy argument requires an value", .{});
|
||||||
@@ -377,7 +355,6 @@ fn parseServeArgs(
|
|||||||
.host = host,
|
.host = host,
|
||||||
.port = port,
|
.port = port,
|
||||||
.timeout = timeout,
|
.timeout = timeout,
|
||||||
.gc_hints = gc_hints,
|
|
||||||
.http_proxy = http_proxy,
|
.http_proxy = http_proxy,
|
||||||
.tls_verify_host = tls_verify_host,
|
.tls_verify_host = tls_verify_host,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ pub const Platform = struct {
|
|||||||
|
|
||||||
// The Env maps to a V8 isolate, which represents a isolated sandbox for
|
// The Env maps to a V8 isolate, which represents a isolated sandbox for
|
||||||
// executing JavaScript. The Env is where we'll define our V8 <-> Zig bindings,
|
// executing JavaScript. The Env is where we'll define our V8 <-> Zig bindings,
|
||||||
// and it's where we'll start Executors, which actually execute JavaScript.
|
// and it's where we'll start ExecutionWorlds, which actually execute JavaScript.
|
||||||
// The `S` parameter is arbitrary state. When we start an Executor, an instance
|
// The `S` parameter is arbitrary state. When we start an ExecutionWorld, an instance
|
||||||
// of S must be given. This instance is available to any Zig binding.
|
// of S must be given. This instance is available to any Zig binding.
|
||||||
// The `types` parameter is a tuple of Zig structures we want to bind to V8.
|
// The `types` parameter is a tuple of Zig structures we want to bind to V8.
|
||||||
pub fn Env(comptime State: type, comptime WebApis: type) type {
|
pub fn Env(comptime State: type, comptime WebApis: type) type {
|
||||||
@@ -259,7 +259,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
self.isolate.performMicrotasksCheckpoint();
|
self.isolate.performMicrotasksCheckpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newExecutor(self: *Self) !Executor {
|
pub fn newExecutionWorld(self: *Self) !ExecutionWorld {
|
||||||
return .{
|
return .{
|
||||||
.env = self,
|
.env = self,
|
||||||
.scope = null,
|
.scope = null,
|
||||||
@@ -269,10 +269,9 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// V8 doesn't immediately free memory associated with
|
// V8 doesn't immediately free memory associated with
|
||||||
// a Context, it's managed by the garbage collector. So, when the
|
// a Context, it's managed by the garbage collector. We use the
|
||||||
// `gc_hints` option is enabled, we'll use the `lowMemoryNotification`
|
// `lowMemoryNotification` call on the isolate to encourage v8 to free
|
||||||
// call on the isolate to encourage v8 to free any contexts which
|
// any contexts which have been freed.
|
||||||
// have been freed.
|
|
||||||
pub fn lowMemoryNotification(self: *Self) void {
|
pub fn lowMemoryNotification(self: *Self) void {
|
||||||
var handle_scope: v8.HandleScope = undefined;
|
var handle_scope: v8.HandleScope = undefined;
|
||||||
v8.HandleScope.init(&handle_scope, self.isolate);
|
v8.HandleScope.init(&handle_scope, self.isolate);
|
||||||
@@ -280,32 +279,35 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
self.isolate.lowMemoryNotification();
|
self.isolate.lowMemoryNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Executor = struct {
|
// ExecutionWorld closely models a JS World.
|
||||||
|
// https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/core/v8/V8BindingDesign.md#World
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/ExecutionWorld
|
||||||
|
pub const ExecutionWorld = struct {
|
||||||
env: *Self,
|
env: *Self,
|
||||||
|
|
||||||
// Arena whose lifetime is for a single getter/setter/function/etc.
|
// Arena whose lifetime is for a single getter/setter/function/etc.
|
||||||
// Largely used to get strings out of V8, like a stack trace from
|
// Largely used to get strings out of V8, like a stack trace from
|
||||||
// a TryCatch. The allocator will be owned by the Scope, but the
|
// a TryCatch. The allocator will be owned by the Scope, but the
|
||||||
// arena itself is owned by the Executor so that we can re-use it
|
// arena itself is owned by the ExecutionWorld so that we can re-use it
|
||||||
// from scope to scope.
|
// from scope to scope.
|
||||||
call_arena: ArenaAllocator,
|
call_arena: ArenaAllocator,
|
||||||
|
|
||||||
// Arena whose lifetime is for a single page load, aka a Scope. Where
|
// Arena whose lifetime is for a single page load, aka a Scope. Where
|
||||||
// the call_arena lives for a single function call, the scope_arena
|
// the call_arena lives for a single function call, the scope_arena
|
||||||
// lives for the lifetime of the entire page. The allocator will be
|
// lives for the lifetime of the entire page. The allocator will be
|
||||||
// owned by the Scope, but the arena itself is owned by the Executor
|
// owned by the Scope, but the arena itself is owned by the ExecutionWorld
|
||||||
// so that we can re-use it from scope to scope.
|
// so that we can re-use it from scope to scope.
|
||||||
scope_arena: ArenaAllocator,
|
scope_arena: ArenaAllocator,
|
||||||
|
|
||||||
// A Scope maps to a Browser's Page. Here though, it's only a
|
// A Scope maps to a Browser's Page. Here though, it's only a
|
||||||
// mechanism to organization page-specific memory. The Executor
|
// mechanism to organization page-specific memory. The ExecutionWorld
|
||||||
// does all the work, but having all page-specific data structures
|
// does all the work, but having all page-specific data structures
|
||||||
// grouped together helps keep things clean.
|
// grouped together helps keep things clean.
|
||||||
scope: ?Scope = null,
|
scope: ?Scope = null,
|
||||||
|
|
||||||
// no init, must be initialized via env.newExecutor()
|
// no init, must be initialized via env.newExecutionWorld()
|
||||||
|
|
||||||
pub fn deinit(self: *Executor) void {
|
pub fn deinit(self: *ExecutionWorld) void {
|
||||||
if (self.scope != null) {
|
if (self.scope != null) {
|
||||||
self.endScope();
|
self.endScope();
|
||||||
}
|
}
|
||||||
@@ -320,7 +322,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
// when the handle_scope is freed.
|
// when the handle_scope is freed.
|
||||||
// We also maintain our own "scope_arena" which allows us to have
|
// We also maintain our own "scope_arena" which allows us to have
|
||||||
// all page related memory easily managed.
|
// all page related memory easily managed.
|
||||||
pub fn startScope(self: *Executor, global: anytype, state: State, module_loader: anytype, enter: bool) !*Scope {
|
pub fn startScope(self: *ExecutionWorld, global: anytype, state: State, module_loader: anytype, enter: bool) !*Scope {
|
||||||
std.debug.assert(self.scope == null);
|
std.debug.assert(self.scope == null);
|
||||||
|
|
||||||
const ModuleLoader = switch (@typeInfo(@TypeOf(module_loader))) {
|
const ModuleLoader = switch (@typeInfo(@TypeOf(module_loader))) {
|
||||||
@@ -338,9 +340,9 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
const Global = @TypeOf(global.*);
|
const Global = @TypeOf(global.*);
|
||||||
|
|
||||||
var context: v8.Context = blk: {
|
var context: v8.Context = blk: {
|
||||||
var handle_scope: v8.HandleScope = undefined;
|
var temp_scope: v8.HandleScope = undefined;
|
||||||
v8.HandleScope.init(&handle_scope, isolate);
|
v8.HandleScope.init(&temp_scope, isolate);
|
||||||
defer handle_scope.deinit();
|
defer temp_scope.deinit();
|
||||||
|
|
||||||
const js_global = v8.FunctionTemplate.initDefault(isolate);
|
const js_global = v8.FunctionTemplate.initDefault(isolate);
|
||||||
attachClass(Global, isolate, js_global);
|
attachClass(Global, isolate, js_global);
|
||||||
@@ -466,7 +468,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endScope(self: *Executor) void {
|
pub fn endScope(self: *ExecutionWorld) void {
|
||||||
self.scope.?.deinit();
|
self.scope.?.deinit();
|
||||||
self.scope = null;
|
self.scope = null;
|
||||||
_ = self.scope_arena.reset(.{ .retain_with_limit = SCOPE_ARENA_RETAIN });
|
_ = self.scope_arena.reset(.{ .retain_with_limit = SCOPE_ARENA_RETAIN });
|
||||||
@@ -1517,7 +1519,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the RemoteObject for a given value.
|
// Retrieves the RemoteObject for a given value.
|
||||||
// The value is loaded through the Executor's mapZigInstanceToJs function,
|
// The value is loaded through the ExecutionWorld's mapZigInstanceToJs function,
|
||||||
// just like a method return value. Therefore, if we've mapped this
|
// just like a method return value. Therefore, if we've mapped this
|
||||||
// value before, we'll get the existing JS PersistedObject and if not
|
// value before, we'll get the existing JS PersistedObject and if not
|
||||||
// we'll create it and track it for cleanup when the scope ends.
|
// we'll create it and track it for cleanup when the scope ends.
|
||||||
@@ -2198,7 +2200,7 @@ fn isEmpty(comptime T: type) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Responsible for calling Zig functions from JS invokations. This could
|
// Responsible for calling Zig functions from JS invokations. This could
|
||||||
// probably just contained in Executor, but having this specific logic, which
|
// probably just contained in ExecutionWorld, but having this specific logic, which
|
||||||
// is somewhat repetitive between constructors, functions, getters, etc contained
|
// is somewhat repetitive between constructors, functions, getters, etc contained
|
||||||
// here does feel like it makes it clenaer.
|
// here does feel like it makes it clenaer.
|
||||||
fn Caller(comptime E: type, comptime State: type) type {
|
fn Caller(comptime E: type, comptime State: type) type {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub fn Runner(comptime State: type, comptime Global: type, comptime types: anyty
|
|||||||
return struct {
|
return struct {
|
||||||
env: *Env,
|
env: *Env,
|
||||||
scope: *Env.Scope,
|
scope: *Env.Scope,
|
||||||
executor: Env.Executor,
|
executor: Env.ExecutionWorld,
|
||||||
|
|
||||||
pub const Env = js.Env(State, struct {
|
pub const Env = js.Env(State, struct {
|
||||||
pub const Interfaces = AdjustedTypes;
|
pub const Interfaces = AdjustedTypes;
|
||||||
@@ -45,7 +45,7 @@ pub fn Runner(comptime State: type, comptime Global: type, comptime types: anyty
|
|||||||
self.env = try Env.init(allocator, .{});
|
self.env = try Env.init(allocator, .{});
|
||||||
errdefer self.env.deinit();
|
errdefer self.env.deinit();
|
||||||
|
|
||||||
self.executor = try self.env.newExecutor();
|
self.executor = try self.env.newExecutionWorld();
|
||||||
errdefer self.executor.deinit();
|
errdefer self.executor.deinit();
|
||||||
|
|
||||||
self.scope = try self.executor.startScope(
|
self.scope = try self.executor.startScope(
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ pub const JsRunner = struct {
|
|||||||
renderer: Renderer,
|
renderer: Renderer,
|
||||||
http_client: HttpClient,
|
http_client: HttpClient,
|
||||||
scope: *Env.Scope,
|
scope: *Env.Scope,
|
||||||
executor: Env.Executor,
|
executor: Env.ExecutionWorld,
|
||||||
storage_shelf: storage.Shelf,
|
storage_shelf: storage.Shelf,
|
||||||
cookie_jar: storage.CookieJar,
|
cookie_jar: storage.CookieJar,
|
||||||
|
|
||||||
@@ -435,7 +435,7 @@ pub const JsRunner = struct {
|
|||||||
.tls_verify_host = false,
|
.tls_verify_host = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.executor = try self.env.newExecutor();
|
self.executor = try self.env.newExecutionWorld();
|
||||||
errdefer self.executor.deinit();
|
errdefer self.executor.deinit();
|
||||||
|
|
||||||
self.scope = try self.executor.startScope(&self.window, &self.state, {}, true);
|
self.scope = try self.executor.startScope(&self.window, &self.state, {}, true);
|
||||||
|
|||||||
Submodule tests/wpt updated: ea16a1e361...3a362d3f23
Reference in New Issue
Block a user