MarshallOfSound

#51602: perf: push sandboxed renderer startup data via mojo and cache preload bytecode

Merged
Created: May 13, 2026, 2:53:49 PM
Merged: May 19, 2026, 10:38:10 AM
5 comments
Target: main

Description of Change

Replaces the BROWSER_SANDBOX_LOAD sync IPC with browser→renderer mojo pushes and adds a persistent V8 code cache for preload scripts. Removes the largest renderer-side FCP cost that isn't present in stock Chromium.

The sync IPC fired from DidCreateScriptContext — before the HTML parser starts — and the browser-side handler awaited reading each preload file, yielding the UI thread back to whatever else the main process was doing at startup. Under cold-launch contention the renderer parked for ~5–8× the UI-thread busy-chunk size waiting on the reply. With two ~150 KB preloads and 20 ms busy chunks, FCP went from ~244 ms to ~140 ms.

UI busy chunk sync IPC pull mojo push
idle ~24 ms ~22 ms
10 ms ~84 ms ~22 ms
20 ms ~134 ms ~22 ms
40 ms ~230 ms ~25 ms

Three pushes replace it, one per place a preload can run:

  • Framesmojom::ElectronFrameStartup.SetStartupData() from ReadyToCommitNavigation(), on the same associated channel as CommitNavigation, so it's ordered ahead of the document needing it.
  • window.open() popups — the synchronous about:blank document is created before any async push can land, so the data rides the CreateNewWindowReply (new Chromium patch + ContentBrowserClient/ContentRendererClient hooks). Verified against stock Electron 42 that setWindowOpenHandler-overridden preloads behave identically.
  • Service-worker preload realmsmojom::ElectronWorkerStartup per-process push from RenderProcessReady(), behind a WaitableEvent for the worker thread.

Then it caches the preload's compiled V8 bytecode (userData/Code Cache/electron-preload/<sha256(id)>.cache), produced after the first compile and shipped with the push thereafter. Compilation moved to ScriptCompiler::CompileFunction() with a ScriptOrigin, which keeps the contents and cache bytes in native buffers (no V8 string churn) and fixes preload stack traces to show the real file and line number instead of <anonymous> and off-by-one. V8's CachedData validation self-heals stale blobs across upgrades.

The cache is two-tiered (in-memory per launch + disk per userData), so the win lands on every navigation after the first and on every launch after the first:

navigation pre-parse blocking vs no cache
baseline (no cache feature) ~22.0 ms
first-ever (cold compile + produce + ship) 27.2 ms +5.2 ms once
same launch, navs 1+ (in-memory hit) 17.6 ms −4.4 ms
next launch, nav 0 (disk hit) 18.0 ms −4.0 ms
next launch, navs 1+ 17.2 ms −4.8 ms

Behavior notes:

  • process.env is captured fresh per push (uv_os_environ()), same timing as the legacy spread.
  • process.versions/arch/platform/execPath are now filled renderer-side and are read-only (the legacy structured clone left them writable; mutating them now no-ops).
  • The disk cache has the same threat model as Chromium's userData/Code Cache/js. Could gate it on embeddedAsarIntegrityValidation if reviewers prefer.
  • PreloadScriptData.contents is array<uint8> not BigBuffer so it flat-serializes into the popup reply blob — one extra ~150 KB memcpy/nav.

Checklist

Release Notes

Notes: Improved sandboxed renderer startup performance — preload scripts and process info are now pushed ahead of navigation instead of fetched via blocking IPC, and preload compilation results are cached on disk. Preload stack traces now show the correct file path and line number.

Backports

42-x-y
Merged
PR Number
#51831
Merged At
Jun 3, 2026, 1:22:49 AM
Released In
v42.3.3
Release Date
Jun 3, 2026, 2:18:37 PM
43-x-y
Merged
PR Number
#51792
Merged At
Jun 1, 2026, 11:28:12 AM
Released In
v43.0.0-beta.1
Release Date
Jun 4, 2026, 3:31:55 PM

Semver Impact

Major
Breaking changes
Minor
New features
Patch
Bug fixes
None
Docs, tests, etc.

Semantic Versioning helps users understand the impact of updates:

  • Major (X.y.z): Breaking changes that may require code modifications
  • Minor (x.Y.z): New features that maintain backward compatibility
  • Patch (x.y.Z): Bug fixes that don't change the API
  • None: Changes that don't affect using facing parts of Electron