Skip to content

Compiled executables: alias embedded bytecode instead of copying it; smaller, page-friendly bytecode (WebKit#494) - #40201

Merged
Jarred-Sumner merged 48 commits into
mainfrom
claude/bytecode-cache-borrow
Aug 24, 2026
Merged

Jarred-Sumner merged 48 commits into
mainfrom
claude/bytecode-cache-borrow

Conversation

@Jarred-Sumner

@Jarred-Sumner Jarred-Sumner commented Aug 23, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

bun build --compile --bytecode executables get a smaller, faster bytecode section that JSC reads in place instead of copying.

Bun side:

  • ZigSourceProvider marks standalone-executable bytecode persistent so decoded instruction streams and expression info alias the mmapped section instead of heap copies.
  • One EncoderStringTable shared by every chunk and every embedded internal module: each ≥4-char non-symbol string is a 4-byte ordinal in every payload; the characters are written once as a graph section (Flags::HAS_BYTECODE_STRING_TABLE). DecoderStringTable on JSVMClientData reads it with a demand-zero atom slot per ordinal.
  • Flags::HAS_SOURCE_HASHES: each module's SourceCodeKey hash is baked in so a bytecode launch never pages in source text just to hash it.
  • The executable also carries ahead-of-time bytecode for the internal modules (node:*, bun:*, internal:*) the bundle imports and everything they eagerly require(); InternalModuleRegistry decodes instead of parsing.
  • Chunk names inside an executable are numbered (./_12.js) instead of chunk-<hash>.js.

WebKit side (oven-sh/WebKit c148a12dd82b):

Measured

57 npm packages (typescript, three, echarts, mathjs, tfjs, aws-sdk, firebase, antd, mui, prettier, babel, …) bundled with --minify to 36 MB, --compile --bytecode, importing 38 of them and running every module initializer. Medians; footprint = Bun.unsafe.memoryFootprint().

macOS arm64, 1.4.0 vs this PR:

--bytecode build payload startup footprint
cjs 1.4.0 16.7 s 295 MB 224 ms 223 MB
cjs this PR 2.4 s 168 MB 184 ms 203 MB
esm 1.4.0 17.0 s 295 MB 215 ms 236 MB
esm this PR 2.4 s 168 MB 181 ms 216 MB
esm --splitting 1.4.0 2.7 s 283 MB 176 ms 197 MB
esm --splitting this PR 2.3 s 164 MB 149 ms 177 MB

Linux x64, 1.4.0 vs this PR:

--bytecode build payload startup footprint
cjs 1.4.0 157 s 366 MB 620 ms 528 MB
cjs this PR 7.5 s 211 MB 489 ms 304 MB
esm 1.4.0 158 s 366 MB 604 ms 535 MB
esm this PR 7.7 s 211 MB 478 ms 332 MB
esm --splitting 1.4.0 13.5 s 351 MB 458 ms 383 MB
esm --splitting this PR 6.6 s 207 MB 382 ms 260 MB

macOS phys_footprint counts anonymous memory only; the file-backed win is separate — vmmap shows the mmapped __BUN section resident at 129 MB on main vs 41 MB on this PR (0 dirty in both).

Where the startup time went

samply main-thread profile of the esm+split executable, main vs this PR (absolute samples at 8 kHz):

main this PR
unlinkedCodeBlockFor (decode + fallback parse) 394 208
identifier atomization (hash + compare + add) 103 33
CachedVector<CachedFunctionExecutable> 55 0
Lexer::lex (parse fallback) 45 0
CachedPtr<CachedInstructionStream> (copy) 18 0
regionChecksumMatches 0 0¹
VarintReader::u32 0 25

¹ skipped for persistent payloads as of this PR; before the skip it was 21.

How did you verify your code works?

  • test/bundler/bundler_compile.test.ts, test/bundler/bundler_compile_splitting.test.ts — every --compile --bytecode matrix cell.
  • New: a --compile --bytecode --splitting executable with 4,000 functions reports its Anonymous: from smaps_rollup; the same binary with BUN_JSC_useBorrowedBytecodeFromCache=0 is the control and must be several MB higher.
  • WebKit: JSTests/stress through the disk cache with the persistent-payload switch on and off, unchanged vs main.

Jarred-Sumner and others added 2 commits August 23, 2026 11:35
…aliases it instead of copying

Pins WebKit to oven-sh/WebKit#494. The executable's bytecode section is mapped for the life
of the process, so decoded instruction streams and expression info can point into it; the
same PR lays the cache out so decoding pages in only what it reads and shrinks it ~36%.
Adds a test that a --compile --bytecode executable's anonymous memory drops when the
aliasing is on versus off in the same binary.
@robobun

robobun commented Aug 23, 2026 •

Copy link
Copy Markdown
Collaborator
Updated 3:51 AM PT - Aug 24th, 2026

✅ @Jarred-Sumner, your commit 22432d8aab781ca747141cbd3be7944ee13a57eb passed in Build #104804! 🎉


🧪   To try this PR locally:

bunx bun-pr 40201

That installs a local version of the PR into your bun-40201 executable, so you can run:

bun-40201 --bun

… persistent regardless of isBuiltin; pin WebKit#494 head; test captures stderr
Jarred-Sumner and others added 14 commits August 23, 2026 12:26
… from bytecode never reads the source text

JSC keys the bytecode lookup on SourceCodeKey, whose hash is StringImpl::hash() of the whole
module source; computing it faulted every source page back in right after the standalone
graph madvised them out. The graph now carries the hash per module (Flags::HAS_SOURCE_HASHES,
a u32 array after the module table; older payloads simply lack it) and Zig::SourceProvider
returns it. Test: a compiled executable that imports a 4,000-function module without calling
anything keeps under a quarter of its payload mapping resident (was ~95%).
… absolute 20 MB (the new cache format halves the bytecode)
…apping depends on the agent's page-cache folio policy (dirty folios mapped wholesale on the ASAN agent), not on what the process reads; the anonymous-memory test covers the copy path
@Jarred-Sumner
Jarred-Sumner marked this pull request as ready for review August 23, 2026 17:05

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beyond the inline nit, I also checked: bytecodeIsEmbeddedInExecutable is captured before the needsDeref = false mutation, and the only site that populates bytecode_cache with source_code_needs_deref: false is the standalone-graph path in jsc_hooks.rs (process-lifetime section bytes), so setPayloadIsPersistent() can't fire on a heap-owned buffer. The build-time hash uses output_file.value gated on module.encoding == Latin1, which is the same byte view to_wtf_string() hands JSC, and HAS_SOURCE_HASHES gates the read side so older graphs skip it.

Extended reasoning...

Verified the persistent-payload gate and the source-hash plumbing don't have lifetime or encoding mismatches; the reported finding is a stray comment left by e61ee8f. This is a coordinated WebKit bump with a bytecode-format change and new aliasing semantics, so a human should still look at it.

Comment thread test/bundler/bun-build-compile.test.ts Outdated
Comment thread src/jsc/bindings/ZigSourceProvider.cpp Outdated
…ecutable section, retired compile-cache blob) instead of inferring it from needsDeref
Comment thread src/runtime/jsc_hooks.rs Outdated
@coderabbitai

coderabbitai Bot commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8028e0a4-2deb-4aca-a42e-37dc688976de

📥 Commits

Reviewing files that changed from the base of the PR and between cfbc61a and 0e1a0d0.

📒 Files selected for processing (3)
  • scripts/build/deps/webkit.ts
  • src/bundler/linker_context/generateChunksInParallel.rs
  • src/standalone_graph/StandaloneModuleGraph.rs

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.


Walkthrough

Changes

The bundler generates bytecode for reachable internal modules and emits it in executable builds. Standalone graphs serialize source hashes and builtin bytecode. Runtime loading uses embedded bytecode when available and falls back to source compilation. Tests cover execution and memory behavior.

Builtin bytecode pipeline

Layer / File(s) Summary
Registry metadata and bytecode contracts
src/codegen/bundle-modules.ts, src/bundler/lib.rs, src/jsc/ResolvedSource.rs, src/jsc/bindings/headers-handwritten.h, src/bundler/LinkerContext.rs, src/bundler/options.rs, src/runtime/api/js_bundle_completion_task.rs, src/runtime/cli/build_command.rs, src/jsc/bindings/ZigSourceProvider.cpp, src/jsc/bindings/InternalModuleRegistry.h
Generated registry data includes module IDs, source stamps, and dependency tables. Output, source, bytecode-cache, and compile-target contracts include builtin-bytecode metadata.
Bytecode generation and bundler outputs
src/jsc/CachedBytecode.rs, src/jsc/bindings/InternalModuleRegistry.cpp, src/js/builtins/BunBuiltinNames.h, src/bundler/bundle_v2.rs, src/bundler/linker_context/generateChunksInParallel.rs
The bundler requests bytecode for reachable builtins and appends numeric builtin-bytecode outputs. JSC resolves transitive dependencies and returns generated payloads. Executable chunk names use compact numeric paths in the default case.
Standalone storage and runtime loading
src/standalone_graph/StandaloneModuleGraph.rs, src/resolver/standalone_module_graph.rs, src/jsc/VirtualMachine.rs, src/jsc/bindings/ZigSourceProvider.cpp, src/jsc/NodeCompileCache.rs, src/runtime/jsc_hooks.rs, src/js/internal-for-testing.ts, src/runtime/bake/production.rs, src/runtime/cli/build_command.rs, test/bundler/bun-build-compile.test.ts
Standalone graphs serialize and restore source hashes and builtin bytecode. Runtime loading decodes persistent embedded bytecode or compiles source. Tests validate execution, loading counts, and memory usage.

WebKit autobuild update

Layer / File(s) Summary
WebKit release selection
scripts/build/deps/webkit.ts
The build script now selects the ab29fdebb46292014bf2db3171fa49ab88d83e0e WebKit commit.

Suggested reviewers: robobun, dylan-conway

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly describes the main change: compiled executables alias embedded bytecode to reduce memory use.
Description check ✅ Passed The description includes both required sections and provides a detailed change summary plus verification methods and results.

Comment @coderabbitai help to get the list of available commands.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 2384d71 addresses the last inline finding — all three node_compile_cache::fetch() sites and the standalone-graph path now set bytecode_cache_is_static. This run found no further issues, but given the change is memory-safety-adjacent (aliasing decoded instruction streams into a buffer that must outlive them) and is coupled to an unmerged WebKit bump, a human look is still warranted before landing.

Checked this run:

  • ResolvedSource layout matches between ResolvedSource.rs and headers-handwritten.h (new fields appended, same order/types).
  • Every site that sets bytecode_cache_is_static: true points at process-lifetime memory (executable section or RETIRED_BLOBS compile-cache blob); default is the safe false.
  • HAS_SOURCE_HASHES read path in from_bytes is gated on the flag, so old binaries without the hash table still parse.
  • Sidecar .jsc bytecode paths were checked and correctly leave the flag false (those buffers are freed via destructorPtr).
Extended reasoning...

Overview

This PR wires Bun to WebKit#494's persistent-payload bytecode cache: adds bytecode_cache_is_static and source_code_hash to the ResolvedSource FFI struct (Rust + C++ header), calls CachedBytecode::setPayloadIsPersistent() in ZigSourceProvider::create when the flag is set, exports Bun__WTFStringHashLatin1 so bun build --compile can precompute the source hash, extends the standalone-module-graph binary format with a per-module hash table behind a new HAS_SOURCE_HASHES flag bit, sets the new static flag at four jsc_hooks.rs sites, bumps WEBKIT_VERSION to a #494 preview build, and adds a Linux-only anonymous-memory delta test.

Over three prior review rounds I flagged (1) a stray comment left after the dropped residency test, (2) the !needsDeref heuristic being narrower than its name/comment, and (3) two sibling compile-cache sites missing the flag. All three were addressed (commits 2de1d82, 4861e28, 2384d71). This run's finder pass raised only the sidecar .jsc path as a candidate, which verifiers refuted — those buffers are heap-owned with a real destructor, so false is correct there.

Security risks

None identified. The change is a performance optimization on trusted data (bytecode Bun itself generated at build time, or compile-cache blobs Bun itself wrote). No new user-controlled input reaches a parser or allocation.

Level of scrutiny

High. setPayloadIsPersistent() makes JSC alias decoded InstructionStream/ExpressionInfo directly into the payload rather than copying — a wrong true is a use-after-free of executable bytecode. The flag defaults to false (safe) and every true site was traced to process-lifetime memory, but this is exactly the class of change REVIEW.md's memory-safety section calls out for careful ownership audit. The FFI struct-layout change and the module-graph binary-format change are additional ABI surfaces where a mismatch fails silently.

Other factors

The PR is explicitly a draft pending the WebKit#494 merge (WEBKIT_VERSION currently points at a preview artifact; the description says to swap for the merge SHA before landing). The new test depends on a JSC option (BUN_JSC_useBorrowedBytecodeFromCache) that only exists in that WebKit build. A maintainer should confirm the WebKit side has landed and the version pin is finalized before merging. The change itself looks correct after the three fix-up commits, but the coupling to an external PR and the memory-aliasing nature put it outside what should merge without human sign-off.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this revision and found no new issues — the three earlier findings (orphaned test comment, needsDeref-inferred predicate, missing bytecode_cache_is_static on the two sibling compile-cache paths) are all addressed. Because this bumps the WebKit engine version and gates JSC's alias-instead-of-copy path on a new process-lifetime invariant, a human look is still worthwhile before landing.

What was reviewed:

  • ResolvedSource FFI struct: new source_code_hash/bytecode_cache_is_static fields appended in the same order/types on both the Rust (ResolvedSource.rs) and C++ (headers-handwritten.h) sides; Default sets both to safe fall-throughs.
  • All four bytecode_cache_is_static: true sites traced to process-lifetime storage (executable section; RETIRED_BLOBS for the three node_compile_cache::fetch paths).
  • to_bytes/from_bytes: hash table written contiguously after the module table (capacity reservation uses output_files.len() ≥ modules.len(); debug_assert_eq! on offset), read back via slice_to gated on HAS_SOURCE_HASHES; modules/module_files are pushed in lockstep so the .zip() is aligned.
  • m_hash already defaults to 0 and hash() already falls through on 0, so writing source_code_hash = 0 is a no-op; Bun__WTFStringHashLatin1 matches what StringImpl::hash() computes for an 8-bit string.
Extended reasoning...

Overview

Bun-side integration for oven-sh/WebKit#494: bumps WEBKIT_VERSION, adds ResolvedSource::{source_code_hash, bytecode_cache_is_static} (Rust + C++ mirror), calls CachedBytecode::setPayloadIsPersistent() when the flag is set so JSC aliases instruction streams / expression info into the mapped payload instead of copying, exposes Bun__WTFStringHashLatin1 for build-time source hashing, extends the standalone-module-graph format with a per-module source-hash table behind a new HAS_SOURCE_HASHES flag, wires the flag/hash through the standalone-executable load path in jsc_hooks.rs, sets the static flag on all three NODE_COMPILE_CACHE fetch paths, and adds a Linux-only anonymous-memory delta test.

Security risks

None identified. Inputs are trusted (the process's own executable section and compile-cache blobs it produced). The memory-safety concern is lifetime, not adversarial input: setPayloadIsPersistent() promises JSC the payload outlives every decoded instruction stream. I traced each of the four true sites — the standalone-graph blob is a section of the running executable; the three compile-cache blobs are owned by NodeCompileCache's entry map and moved to RETIRED_BLOBS (never freed) on displacement. Default is false, so any un-audited construction site copies as before.

Level of scrutiny

High. This is (a) a JS-engine dependency bump whose payload-format changes I cannot review here, (b) a change that hands JSC a "you may alias this forever" promise where a wrong true is a latent UAF, and (c) a serialized-format extension to the compiled-executable graph. None of it is mechanical.

Other factors

Three earlier review rounds each produced a finding that was addressed (orphaned comment removed; implicit !needsDeref predicate replaced by an explicit field; the two sibling compile-cache paths now set the flag). The new test is a self-controlled A/B on the same binary via BUN_JSC_useBorrowedBytecodeFromCache=0, which sidesteps the ASAN/debug RSS-threshold flakiness that killed the earlier residency test. The PR description notes the WebKit hash may still need swapping for the merged SHA — worth confirming before merge.

This was referenced Aug 24, 2026
sosukesuzuki pushed a commit that referenced this pull request Aug 25, 2026
### Problem
- Bun's WebKit pin `aea1f010b6` is 412 upstream commits behind
`8c4fd56347`, 90 of them in JavaScriptCore, WTF or bmalloc.
oven-sh/WebKit#503 merges that range into the fork.
- Upstream removed the `@newPromiseCapability` private builtin
(`38027ff0ec`). Six call sites in Bun's bundled modules use it, so
`node:events`, `node:util`, `node:dgram` and the HTTP server fail to
load (`Private symbol not found: newPromiseCapability`).
- #40263 and oven-sh/WebKit#501 were a parallel attempt at `55d9d9007f`,
one WebCore-only commit ahead. Both are closed in favor of this pair.

### Fix
- oven-sh/WebKit#503 is merged. `WEBKIT_VERSION` is
`cb61607f1a4bae79d7701965062634dee9efb349`, its merge commit on the
fork's main (release
`autobuild-cb61607f1a4bae79d7701965062634dee9efb349`, 42 tarballs). That
commit is the preview build this PR was tested against (`d2654c3b`) plus
oven-sh/WebKit `a0a80b2276` (an optional depth bound on
`recursivelyGenerateUnlinkedCodeBlockForProgram/ForModuleProgram`).
- The six call sites create their promise with `$newPromise()` and
settle it with `$resolvePromise` / `$rejectPromise`, or the
`...WithFirstResolvingFunctionCallCheck` variants where a second settle
is possible. `builtins.d.ts` follows.
- `EncodeURIComponent.cpp` includes `<wtf/HexNumber.h>` itself (upstream
`314133b7a6` no longer does).
- Verified: `test/js/bun/jsc/webkit-upgrade-8c4fd56347.test.ts` pins
four JavaScript-visible engine changes that fail at the current pin. The
events, util and dgram tests cover the ported settlement paths.

### Background
- Bun links a prebuilt JavaScriptCore from oven-sh/WebKit releases.
`scripts/build/deps/webkit.ts` names the release tag.
- Built-in modules (`src/js/`) go through JavaScriptCore's builtin
compiler. A `$name` call becomes the private name `@name`, which has to
exist in the engine.
- `$newPromise` creates a pending promise. `$resolvePromise` /
`$rejectPromise` settle it and require it to be pending. The
`...WithFirstResolvingFunctionCallCheck` variants ignore calls after the
first, like a Promise executor's functions.

<details><summary>Notes</summary>

- Duplicate resolution: oven-sh/WebKit#501 and #503 have the same
structure (main at `62f427b86f`, then #488's head `d0fae3b3c9`, then
upstream/main) and the same `CachedTypes.cpp` resolution (the two files
differ in comments and an unused alias). WTF and bmalloc are identical.
The only upstream difference is WebCore's `55d9d9007f`
(`MediaElementAudioSourceNode` use-after-free), which the JSCOnly port
does not compile. #503 was kept because this PR's CI run was green
(Build #104490). The test file `webkit-upgrade-8c4fd56347.test.ts` is
carried over from #40263.
- oven-sh/WebKit#488 (upstream `baf4a9a7ec0b`) stopped merging after the
fork's bytecode cache rework (#490, #493, #494, #497). The per-commit
review of the upstream range (API and ABI changes, behavior changes,
performance) and the conflict resolutions are in oven-sh/WebKit#503. The
new conflict in this round is `CachedTypes.cpp`: the fork's new code
block record layout against upstream moving the global-only fields
(`features`, `lineCount`, source URL directives) to
`UnlinkedGlobalCodeBlock` and deleting `m_jumpTargets`.
- The ported call sites (the changes of #40054, carried over):
`node:events` (`once`), `node:util` (`aborted`), `node:dgram`
(`Symbol.asyncDispose`) and the HTTP server (CONNECT, Upgrade, the
per-request completion promise). `builtins.d.ts` declares `$newPromise`,
`$resolvePromiseWithFirstResolvingFunctionCallCheck` and
`$rejectPromiseWithFirstResolvingFunctionCallCheck` and drops
`$newPromiseCapability`. `@newPromise` is a bytecode intrinsic and
`@resolvePromise` / `@rejectPromise` are link-time constants, so they
exist in every engine build. `util.aborted` registers and unregisters
its `FinalizationRegistry` entry with the same token (the promise).
- Behavior changes in the upstream range that are visible from
JavaScript: `Promise.try` follows the updated spec (`PromiseResolve`
instead of `NewPromiseCapability`); the module map no longer caches
fetch failures, so a second `import()` of a specifier whose load failed
re-runs Bun's module loader instead of rejecting with the cached error;
`Uint8Array.prototype.setFromBase64` on a zero-length target returns `{
read: 0, written: 0 }` without validating the input;
`WebAssembly.Module.imports()/exports()` descriptors drop the
non-standard `type` field; re-exported imported Wasm globals and tags
keep object identity; a DFG `++`/`--` on an `int32` that overflows with
an unused result now deoptimizes instead of wrapping (`7711916200`). The
first, third, fourth and last of these are pinned by
`test/js/bun/jsc/webkit-upgrade-8c4fd56347.test.ts`.
- Performance changes of note: `SymbolTableEntry` no longer allocates a
`WatchpointSet` per watched variable until the DFG watches it
(`cea233cede`); `Object.assign` with several sources clones the first
one through `objectCloneFast` (`96ca975b2a`); `JSON.parse` allocates
arrays once at their final size; `TypedArray.prototype.sort()` without a
comparator uses a radix sort for 2/4/8-byte element types; `Map`/`Set`
`forEach` is inlined in the DFG and FTL; `RegExp` cells shrink from 96
to 80 bytes; `UnlinkedFunctionCodeBlock` shrinks from 216 to 192 bytes.
- `src/jsc/bindings/NodeVMSyntheticModule.cpp` calls
`SymbolTable::set(NoLockingNecessary, ...)`. After `cea233cede` only the
locked overload exists. `NoLockingNecessary` converts to a
`ConcurrentJSLocker`, so the call compiles unchanged.
- The upstream change to Linux thread scheduling (per-QOS
`sched_setattr` on every WTF thread, `SCHED_BATCH` compiler threads on
hosts with 4 or fewer cores) is gated off for Bun in the fork: Bun's
threads keep inheriting the process scheduling attributes.
- Suites run on a local debug + ASAN build against the merged WebKit
(`bun run build:local`): `test/js/bun/jsc`, `bun/jsc-stress` (116/116),
`node/events`, `node/util`, `node/dgram`, `node/vm`, `node/module`,
`bun/resolve`, `node/worker_threads`, `bun/wasm`, `web/url`,
`web/atomics`, `node/http/node-http-connect`, `node/async_hooks`,
`node/string_decoder`, `bundler/bundler_compile`,
`bundler/bun-build-api`: 3,548 pass. The failures are 5 s timeouts under
debug + ASAN, this machine's IPv6 multicast `ENODEV`, and one test that
fails the same way at the current pin. `bun build --bytecode` output
from that build loads and runs. A debug + ASAN build against the
`autobuild-preview-pr-503-311eab61` prebuilt runs
`test/js/bun/jsc/webkit-upgrade-8c4fd56347.test.ts`,
`test/js/bun/jsc/webkit-upgrade-3722912f.test.ts`,
`node/events/event-emitter.test.ts` and
`node/util/test-aborted.test.ts`: 106 pass.
- Every push to oven-sh/WebKit#503 produces a new preview tag
(`autobuild-preview-pr-503-<first 8 of the head sha>`), and this PR's
`WEBKIT_VERSION` follows it. CI lanes that fetch the prebuilt fail on
the download until that tag's Actions run has published the release.
- Rebase over #40201: Bun main moved its pin to the fork's
`c148a12dd82b` and calls the bytecode APIs that release added
(`EncoderStringTable`, persistent payloads). The `311eab61` preview
predates them, so the branch could not rebase until oven-sh/WebKit#503
merged the fork's main (head `d2654c3b`, 0 commits behind). The rebase
itself conflicted only on the `WEBKIT_VERSION` line. A debug + ASAN
build against `autobuild-preview-pr-503-d2654c3b` passes
`webkit-upgrade-8c4fd56347.test.ts`,
`node/events/event-emitter.test.ts`, `node/util/test-aborted.test.ts`,
`node/dgram` (except the IPv6 multicast `ENODEV` of this machine),
`node/http/node-http-connect.test.ts`, `web/atomics`, `web/url`,
`node/string_decoder` and `test/js/bun/jsc`. The compiled-executable
bytecode paths of #40201 work against it: the aliasing run keeps 12 MB
of instruction streams out of anonymous memory and 45 internal modules
load from embedded bytecode. The failures on this machine are the DOMJIT
hot loops and two `bun-build-compile` tests that exceed their timeouts
under debug + ASAN (the compile alone takes 5 to 47 s here), and the
nested `node-http-connect.node.mts` run that takes 5.0 s against a 5 s
limit.
- The `$newPromiseCapability` call in `src/node-fallbacks/events.js`
(the browser polyfill, not a JSC builtin) is a pre-existing bug and was
reported separately by #40054.
</details>

<!-- robobun:evidence:begin -->

---

**no test proof** · iteration 2 · platform-specific test(s) that do not
run on this machine, deferring to CI, which covers all platforms:
test/js/node/dgram/node-dgram.test.js

<!-- robobun:evidence:end -->
Jarred-Sumner added a commit that referenced this pull request Aug 25, 2026
### What does this PR do?

Reverts the numbered `./_N.js` chunk naming that #40201 introduced for
chunks inside a compiled executable. Chunks use the same
`chunk-<hash>.js` names as a normal build again.

### How did you verify your code works?

Built an executable with two entry points and `splitting: true`; the
embedded chunk names are `chunk-<hash>.js`. Ran
`test/bundler/bun-build-compile.test.ts` locally; the only failures are
the local ASAN `asan-dyld-shim.dylib` load errors when the compiled
binary runs, which are unrelated to this change.
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