Commit Graph

29 Commits

Author SHA1 Message Date
Karl Seguin
9092651b5b Merge branch 'main' into fix_context_lifetime 2026-01-20 08:50:41 +08:00
Karl Seguin
9b000a002e Hook v8 crashes into new crash handler 2026-01-19 07:37:10 +08:00
Karl Seguin
62aa564df1 Remove Global v8::Local<V8::Context>
When we create a js.Context, we create the underlying v8.Context and store it
for the duration of the page lifetime. This works because we have a global
HandleScope - the v8.Context (which is really a v8::Local<v8::Context>) is that
to the global HandleScope, effectively making it a global.

If we want to remove our global HandleScope, then we can no longer pin the
v8.Context in our js.Context. Our js.Context now only holds a v8.Global of the
v8.Context (v8::Global<v8::Context).

This PR introduces a new type, js.Local, which takes over a lot of the
functionality previously found in either js.Caller or js.Context. The simplest
way to think about it is:

1 - For v8 -> zig calls, we create a js.Caller (as always)
2 - For zig -> v8 calls, we go through the js.Context (as always)
3 - The shared functionality, which works on a v8.Context, now belongs to js.Local

For #1 (v8 -> zig), creating a js.Local for a js.Caller is really simple and
centralized. v8 largely gives us everything we need from the
FunctionCallbackInfo or PropertyCallbackInfo.  For #2, it's messier, because we
can only create a local v8::Context if we have a HandleScope, which we may or
may not.

Unfortunately, in many cases, what to do becomes the responsibility of the caller
and much of the code has to become aware of this local-ness. What does it means
for our code? The impact is on WebAPIs that store .Global. Because the global
can't do anything. You always need to convert that .Global to a local
(e.g. js.Function.Global -> js.Function).

If you're 100% sure the WebAPI is only being invoked by a v8 callback, you can
use `page.js.local.?.toLocal(some_global).call(...)` to get the local value.

If you're 100% sure the WebAPI is only being invoked by Zig, you need to create
 `js.Local.Scope` to get access to a local:

```zig
var ls: js.Local.Scope = undefined;
page.js.localScope(&ls);
defer ls.deinit();
ls.toLocal(some_global).call(...)
// can also access `&ls.local` for APIs that require a *const js.Local
```
For functions that can be invoked by either V8 or Zig, you should generally push
the responsibility to the caller by accepting a `local: *const js.Local`. If the
caller is a v8 callback, it can pass `page.js.local.?`. If the caller is a Zig
callback, it can create a `Local.Scope`.

As an alternative, it is possible to simply pass the *Page, and check
`if page.js.local == null` and, if so, create a Local.Scope. But this should only
be done for performance reasons. We currently only do this in 1 place, and it's
because the Zig caller doesn't know whether a Local will actually be needed and
it's potentially called on every element creating from the parser.
2026-01-19 07:28:33 +08:00
Karl Seguin
4e4a615df8 Move Env's FunctionTemplate from Global -> Eternal
(we'll move more to Eternal's, this is just a first teaser)
2026-01-13 12:58:31 +08:00
Karl Seguin
86f4ea108d Store snapshot templates in isolate, not context.
This lets us load the isolate without having to create a temp/dummy context
just to get the templates.

Call ContextDisposedNotification when a context is removed. Supposedly this can
help/hint to the isolate about memory management.
2026-01-13 12:58:30 +08:00
Karl Seguin
f2a9125b99 js.v8 is not equal to js.v8.c
This means the C funtions/types now sit in the root of v8.
2026-01-13 12:58:30 +08:00
Karl Seguin
8438b7d561 remove remaining direct v8 references 2026-01-13 12:58:30 +08:00
Karl Seguin
bc11a48e6b migrate most cases, merge Caller into bridge 2026-01-13 12:57:06 +08:00
Karl Seguin
363b95bdef Isolate and HandleScope 2026-01-13 12:57:06 +08:00
Karl Seguin
6ecf52cc03 port Platform and Inspector to use v8's C handles/functions directly 2026-01-13 12:56:07 +08:00
Karl Seguin
087086c308 remove some unused imports 2025-12-26 12:40:20 +08:00
Karl Seguin
e3265d400e Update src/browser/js/Env.zig
Co-authored-by: Pierre Tachoire <pierre@lightpanda.io>
2025-12-22 16:44:33 +08:00
Karl Seguin
b3a0aaaeea Enable v8 snapshots
There are two layers here. The first is that, on startup, a v8 SnapshotCreator
is created, and a snapshot-specific isolate/context is setup with our browser
environment. This contains most of what was in Env.init and a good chunk of
what was in ExecutionWorld.createContext. From this, we create a v8.StartupData
which is used for the creation of all subsequent contexts. The snapshot sits
at the application level, above the Env - it's re-used for all envs/isolates, so
this gives a nice performance boost for both 1 connection opening multiple pages
or multiple connections opening 1 page.

The second layer is that the Snapshot data can be embedded into the binary, so
that it doesn't have to be created on startup, but rather created at build-time.
This improves the startup time (though, I'm not really sure how to measure that
accurately...).

The first layer is the big win (and just works as-is without any build / usage
changes).

with snapshot
total runs 1000
total duration (ms) 7527
avg run duration (ms) 7
min run duration (ms) 5
max run duration (ms) 41

without snapshot
total runs 1000
total duration (ms) 9350
avg run duration (ms) 9
min run duration (ms) 8
max run duration (ms) 42

To embed a snapshot into the binary, we first need to create the snapshot file:

zig build -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin

And then build using the new snapshot_path argument:

zig build -Dsnapshot_path=../../snapshot.bin -Doptimize=ReleaseFast

The paths are weird, I know...since it's embedded, it needs to be inside the
project path, hence we put it in src/snapshot.bin. And since it's embedded
relative to the embedder (src/browser/js/Snapshot.zig) the path has to be
relative to that, hence ../../snapshot.bin. I'm open to suggestions on
improving this.
2025-12-18 20:10:38 +08:00
Karl Seguin
1639ff1b98 improve XMLHTTPRequest. Legacy xhr.html pass 2025-12-15 17:56:23 +08:00
Karl Seguin
92ae2c46b6 ReadableStream 2025-12-01 15:16:33 +08:00
Karl Seguin
819424fd3b Support Image constructor (i.e. new Image(..)) 2025-11-27 18:16:03 +08:00
Karl Seguin
0d57356c11 Response constructor, window.CSS 2025-11-27 15:13:16 +08:00
Karl Seguin
e1d9732a60 PerformanceObserver.supportedEntryTypes 2025-11-26 07:42:19 +08:00
Halil Durak
1aca22f219 JS API table changes for zigdom
Applies the `rework-types` changes to zigdom branch.
2025-11-20 13:49:36 +03:00
Karl Seguin
7ab88e9a71 add legacy tests, optimize empty types 2025-11-14 15:55:02 +08:00
Karl Seguin
32bad5f8bb Element.matches, Element.hasAttributes and DOMStringMap (Element.dataset) 2025-11-13 20:09:38 +08:00
Karl Seguin
21d008c6c2 class_index => class_id 2025-11-01 20:37:45 +08:00
Karl Seguin
c966211481 HTMLAllCollection 2025-10-30 11:30:06 +08:00
Karl Seguin
fb9cce747d Scripts now properly block rendering
Re-enabled CDP tests

Fixed more tests
2025-10-29 16:37:11 +08:00
Karl Seguin
cdd31353c5 get fetch campire working 2025-10-28 11:24:29 +08:00
Karl Seguin
b047cb6dc1 remove libdom 2025-10-27 22:14:59 +08:00
Karl Seguin
381a18a40e Move the call_arena to the page.
The call_arena was previously owned by the js.Context, but it has to exist on
the page, and the page is created before the context, so it's set to undefined
on the page. While this has never caused an issue, there's no reason for the
page not to own this, and the context to simply reference it.

Also, renamed the js.Context.context_arena to simply `arena`, which is more
consistent with other arena names (e.g. page.arena).
2025-10-06 15:52:56 +08:00
Karl Seguin
2e734fae57 This is the last of the big changes to the js code
This Pr largely tightens up a lot of the code. 'v8' is no longer imported
outside of js. A number of helper functions have been moved to the js.Context.
For example, js.Function.getName used to call:

```zig
return js.valueToString(allocator, name, self.context.isolate, self.context.v8_context);
```

It now calls:

```zig
return self.context.valueToString(name, .{ .allocator = allocator });
```

Page.main_context has been renamed to `Page.js`. This, in combination with new
promise helpers, turns:

```zig
const resolver = page.main_context.createPromiseResolver();
try resolver.resolve({});
return resolver.promise();
```

into:

```zig
return page.js.resolvePromise({});
```
2025-10-03 15:06:16 +08:00
Karl Seguin
dab8012b6a Start extract JS structs into their own files
Renames JsContext -> js.Context, JsObject -> js.Object and JsThis -> js.This
which is more consistent with the other types. The JsObject -> js.Object is
the reason so many files were touched.

This is still a [messy] transition, with more refactoring planned to clean it
up.
2025-10-02 12:48:50 +08:00