Skip to content

Conversation

@mrdimidium
Copy link

Provides a proof of concept on how to use snapshots for #1176. Depends on PR in v8 repository.: lightpanda-io/zig-v8-fork#110

As stated in the documentation, snapshots are serialized state of the V8 heap. We simply execute JavaScript code and save the snapshot (it can be saved to disk if desired). In the PR above, you can see how a snapshot is created at browser startup, which provides the LightpandaSnapshotPoC function, later accessible in tests.

Since the polyfill is still JavaScript code, it can only be executed and serialized along with the initialization of window* and other global objects, like this:

  • at browser startup, create a clean context
  • add global WebAPIs to the context
  • add the polyfills to the context
  • serialize the snapshot for subsequent pages
  • (optional) save the snapshot to disk

Currently, this isn't very convenient to do in code, as the snapshot must be ready before creating the Env. I'd like to discuss the implementation in advance:

  • when creating the first page, save a snapshot for subsequent pages in env;
  • change Env so that it proactively prepares a snapshot at startup, and only loads Page from the snapshot and completely skips preparing window*

@krichprollsch, wdyt?

@github-actions
Copy link

github-actions bot commented Oct 28, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@mrdimidium
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

@mrdimidium
Copy link
Author

@krichprollsch, to pass the build and tests, need to build with PR in v8 repo

@krichprollsch
Copy link
Member

krichprollsch commented Oct 29, 2025

@mrdimidium,
Thanks for the PR.

(it can be saved to disk if desired)

Do you know if the data is independent from the platform? Could we generate the blob in a file and commit it along the project?

Regarding the loading strategy, what about changing the polyfill to be independent from any global object, and only run a small JS when need to create what we need with global objects? I didn't look at the JS code for now, so idk if it's hard to do, but it could worth the try.

WDYT?

@mrdimidium
Copy link
Author

@krichprollsch, it's not portable across platforms, but it can be generated during the build. For example, Chromium builds the snapshot in GN and packages it into an apk/dmg/apk. This also allows them to avoid having to include extra snapshot generation code at runtime.

I was thinking about changing the JS, but I couldn't immediately figure out how to handle the "something in the window was accessed" event before the window actually appears. Maybe something with globalThis?

It will also be slower. If we take a snapshot after the JS has executed, we'll get an already initialized window in the snapshot. If we use JS wrappers, it will need to be executed at runtime on the page.

@krichprollsch
Copy link
Member

krichprollsch commented Oct 29, 2025

Got it. I'm not sure about the good balance here. I'm afraid we will have to generate the snapshot too often according the way we are creating js env & globals right now. But in the other hand that could force us to refacto for a better way.

@krichprollsch
Copy link
Member

Thinking a bit more about that, I'm not sure it worth it, I'm afraid we will have to generate the snapshot at the same moment we currently inject the polyfill. So there will be no gain at all.

@mrdimidium
Copy link
Author

I think this could work if the global API preparation were separated from the page. In that case, a snapshot with the WebAPI (including polyfills) could be prepared in advance. This should be done once during the build and completely removed from runtime.

But it seems like this would require significant refactoring.

@krichprollsch
Copy link
Member

krichprollsch commented Oct 29, 2025

I think I will take a look a the polyfill first to see if we can extract the global deps first.

@krichprollsch
Copy link
Member

I tried the branch locally (ubuntu x86_64), the webcomponent test is working correctly.

$ F='Browser: Polyfill.WebComponents' make test
Browser: Polyfill.WebComponents (113.85ms)

1 of 1 test passed

Slowest 1 test:
  113.85ms      Browser: Polyfill.WebComponents


Build Summary: 7/7 steps succeeded
test success
└─ run test success 154ms MaxRSS:62M
   └─ compile test Debug native cached 15ms MaxRSS:39M
      ├─ options cached
      ├─ WriteFile ada_c.h cached
      ├─ compile lib ada Debug native cached 20ms MaxRSS:38M
      ├─ compile lib ada Debug native (reused)
      └─ options cached

But I have a crash when running the whole test suite 🤔

Client: http invalid request (0.47ms)
Client: http invalid handshake (2.01ms)


#
# Fatal error in ../../../src/src/heap/read-only-spaces.cc, line 96
# Check failed: read_only_blob_checksum_ == snapshot_checksum (<unprintable> vs. 987505134).
#
#
#
#FailureMessage Object: 0x732cebff4500
==== C stack trace ===============================

    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3ecc943]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3eca91d]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3f3e3d4]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x4f735db]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x41c4b36]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x408d4a3]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x408ef71]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x4f574bb]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x4f5d121]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3fd4798]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3ec1826]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x32fd130]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328165e]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x327602e]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3287525]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3287aa0]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x32889f4]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328a28d]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328b426]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328bd2c]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328bee0]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328c696]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x328d4fd]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3cb714d]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3cb2fe3]
    ./.zig-cache/o/82a9ee220bf2145336ad999ef7b4f2bc/test() [0x3cb0bd4]
    /lib/x86_64-linux-gnu/libc.so.6(+0x9caa4) [0x732cf709caa4]
    /lib/x86_64-linux-gnu/libc.so.6(+0x129c6c) [0x732cf7129c6c]
test
└─ run test failure

@mrdimidium
Copy link
Author

Interesting, It's an debug assert, but I don't see it. @krichprollsch, are you building on a Mac or Linux?

@krichprollsch
Copy link
Member

linux, x86_64 (ubuntu 24.04)

@mrdimidium
Copy link
Author

Give me some time to figure this out. You can temporarily disable dcheck in args.gn.

@krichprollsch
Copy link
Member

Regarding decoupling the polyfill from window, this experiment is working: 5a1564d
But it has drawbacks:

  • I still have to use the lazy loading to pass tests, not sure why, but it's not relative to snapshot/decouple from window changes, b/c loading the original polyfill all the time doesn't work either
  • we expose the __polyfillWebcomponents function in the global state

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants