Conversation
Upstream JavaScriptCore removed the @newPromiseCapability private builtin (WebKit/WebKit 38027ff0ec). The six call sites in node:events, node:util, node:dgram and the HTTP server use @newPromise plus the @resolvePromise and @rejectPromise family instead, which settles the promise without allocating the capability record. (cherry picked from commit 17c8bf7)
The abort listener unregistered the FinalizationRegistry entry with the promise while the entry was registered with the listener function, so the entry stayed alive until the resource was collected. The promise is now the token on both sides. (cherry picked from commit 7effb1d)
…ram disposal These are the call sites that moved off @newPromiseCapability. Without the port, node:events fails to load against the new WebKit (Private symbol not found: newPromiseCapability). (cherry picked from commit 1412855)
(cherry picked from commit 1ea3b28)
A listener defined inline in the request dispatcher or in Symbol.asyncDispose keeps the whole enclosing scope alive for as long as the socket does. Bind the promise to a module-level function instead. (cherry picked from commit 8119ca7)
(cherry picked from commit f81a61f)
…not-running code (cherry picked from commit d031fdc)
Upstream WebKit 314133b7a6 removed the UUID ObjectIdentifier, and with it the <wtf/UUID.h> include that made hex() reachable through VM.h.
…sync Promise.try returns a native promise as-is, setFromBase64 on a zero-length target reads nothing, WebAssembly.Module.imports() descriptors drop the js-types field, and the DFG keeps the overflow check of an unused ++ / --.
WEBKIT_VERSION points at the oven-sh/WebKit#501 preview build (autobuild-preview-pr-501-fabdd1db). Move it to the autobuild-<sha> release of the fork's main once that PR lands.
|
Status: Before merge: land oven-sh/WebKit#501 as a merge commit, then move |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (11)
Included review availability: Your plan provides up to 5 included reviews per hour; 3 remain after this review. WalkthroughChangesThe pull request replaces Promise capability usage with pending-promise and first-settlement intrinsics across Node HTTP, datagram, events, and abort utilities. It also updates the WebKit preview version, adds an encoding include, and adds JavaScriptCore and Node regression tests. Promise settlement intrinsics
WebKit upgrade coverage
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
| * From https://github.com/oven-sh/WebKit releases. | ||
| */ | ||
| export const WEBKIT_VERSION = "aea1f010b69783c0fc1ff24ff663691abe642c16"; | ||
| export const WEBKIT_VERSION = "autobuild-preview-pr-501-fabdd1db"; |
There was a problem hiding this comment.
🔴 WEBKIT_VERSION is pinned to autobuild-preview-pr-501-fabdd1db, an ephemeral per-push preview tag that will be pruned once oven-sh/WebKit#501 closes. As the PR description already notes, this must be updated to the fork-main autobuild-<sha> release once #501 lands, before this PR merges — flagging here as a merge-gate so it isn't accidentally landed in this state.
Extended reasoning...
What the issue is
scripts/build/deps/webkit.ts:6 sets WEBKIT_VERSION = "autobuild-preview-pr-501-fabdd1db". This is a per-push preview tag produced by oven-sh/WebKit#501's CI: every push to that PR creates a new autobuild-preview-pr-501-<head-sha-8> tag, and these preview releases are pruned once the PR merges or closes. The PR description itself is explicit about this:
Before this PR merges,
WEBKIT_VERSIONhas to move to theautobuild-<sha>release that the fork's main produces once oven-sh/WebKit#501 lands.
This comment is not surfacing a defect the author missed — it is the merge-gate the author already asked for, so the PR cannot be accidentally approved/merged before the tag is swapped.
The code path that would break
prebuiltUrl() in the same file constructs the download URL as https://github.com/oven-sh/WebKit/releases/download/${tag}/bun-webkit-${os}-${arch}${suffix}.tar.gz, where tag is WEBKIT_VERSION verbatim when it starts with autobuild-. Every CI lane and every developer running with cfg.webkit === "prebuilt" (the default) fetches from that URL. prebuiltDestDir() also keys the extraction cache on the same string.
Step-by-step: what happens if this merges as-is
- This PR merges to
mainwithWEBKIT_VERSION = "autobuild-preview-pr-501-fabdd1db". - Upgrade to upstream WebKit 55d9d9007f WebKit#501 subsequently merges to the fork's
main, producing the stableautobuild-<merge-sha>release. - The fork's release automation prunes the now-obsolete
autobuild-preview-pr-501-*releases (or a later push to Delete incorrect gitignore file #501 before it merges replacesfabdd1dbwith a new head sha). - Every fresh Bun build — CI on every subsequent PR, and every developer without a cached
webkit-preview-pr-501-fabdd1db*directory — hits a 404 on the tarball download and fails at the WebKit dependency step. - Because
prebuiltDestDir()keys on the tag string, developers who do have a cached extraction keep working, masking the breakage locally while CI is red for everyone.
Why nothing else prevents it
There is no fallback URL, no checksum pinning, and no guard in scripts/build/deps/webkit.ts that distinguishes a preview tag from a stable one. The only mechanism preventing this from landing is human review — hence this comment.
Fix
Once oven-sh/WebKit#501 lands on the fork's main, update this line to the resulting autobuild-<40-hex-sha> (or the full commit sha, per the file's own comment header) and re-push. No other change is needed; prebuiltUrl() and prebuiltDestDir() already handle both the autobuild--prefixed and bare-sha forms.
On severity
Two of three verifiers rated this normal; one rated it nit on the grounds that it restates what the author already wrote. Both are defensible. I'm keeping normal because the rubric reserves it for "merging without the fix causes a concrete failure" — which this does (every prebuilt download 404s) — and because the author's own description asks for exactly this gate. It is a reminder, not a criticism.
| test("node:dgram Symbol.asyncDispose closes the socket and resolves after 'close'", async () => { | ||
| const socket = dgram.createSocket("udp4"); | ||
| await new Promise(resolve => socket.bind(0, "127.0.0.1", resolve)); |
There was a problem hiding this comment.
🟡 The bind promise has no rejection path: Socket.prototype.bind's callback only fires on 'listening', so if bind fails the awaited promise never settles and the test hangs to timeout with the socket leaked. Wire socket.once('error', reject) (or Promise.withResolvers() + both events). This matches the file's existing convention and bind(0, '127.0.0.1') failing is implausible, so not blocking — just the REVIEW.md "wire EVERY failure event to reject" rule.
Extended reasoning...
What the bug is
The new test at test/js/node/dgram/node-dgram.test.js:61 awaits bind completion via:
await new Promise(resolve => socket.bind(0, "127.0.0.1", resolve));This promise has only a resolve path. Looking at Socket.prototype.bind in src/js/node/dgram.ts, when a callback is passed it registers two listeners:
function removeListeners() {
this.removeListener("error", removeListeners);
this.removeListener("listening", onListening);
}
function onListening() {
removeListeners.$call(this);
cb.$call(this);
}
this.on("error", removeListeners);
this.on("listening", onListening);On 'error', removeListeners detaches both listeners but never invokes cb. Because an 'error' listener is installed, emit('error', ...) also does not throw — the error is silently absorbed and the callback is dropped.
The code path that triggers it
socket.bind(0, "127.0.0.1", resolve)installsremoveListenerson'error'andonListeningon'listening'.- Bind fails (e.g.
startBunSocketrejects, or the DNS lookup errors) →state.bindState = BIND_STATE_UNBOUND; this.emit('error', err). removeListenersruns, detaches both listeners, returns.cb(i.e.resolve) is never called.- The awaited promise never settles. The test hangs until the harness timeout fires.
- The socket is not guarded by
using/try-finally, so it leaks on that path too.
Why existing code doesn't prevent it
The 'error' listener that bind() installs is precisely what prevents the emit from throwing synchronously — it swallows the error rather than propagating it. There is no socket.once('error', reject) in the test, and no cleanup guard around the socket.
Impact
If bind(0, '127.0.0.1') on a udp4 socket ever failed on a CI host, the test would hang to the harness timeout with no diagnostic (the error is absorbed, not surfaced), and the socket handle would leak into subsequent tests. REVIEW.md is explicit on this: "Wire EVERY failure event (error, close, abort, process exit) to reject the awaited promise" and "Release every resource via using/await using or try/finally registered BEFORE the assertions."
That said, the trigger is essentially implausible — binding a udp4 socket to loopback on an ephemeral port cannot realistically fail on any functioning host — and the identical pattern already exists in this file (the subprocess fixture at line ~18 does await new Promise(r => rx.bind(0, "127.0.0.1", r)), and the IPv6 tests at lines ~75/~87 never close their sockets at all). So this is a pattern-rule nit, not a merge blocker.
Step-by-step proof
Concrete walk-through with a forced failure:
const socket = dgram.createSocket("udp4")— state.bindState = UNBOUND, handle present.new Promise(resolve => socket.bind(0, "127.0.0.1", resolve))—bind()sets bindState = BINDING, installson('error', removeListeners)andon('listening', onListening), then callsstate.handle.lookup("127.0.0.1", ...).- Suppose
Bun.udpSocket({...})rejects (e.g. EMFILE).startBunSocket's rejection handler runs:state.bindState = BIND_STATE_UNBOUND; self.emit('error', err). emit('error', err)finds one listener (removeListeners), calls it.removeListenersremoves itself andonListening, returns. Because a listener existed,emitreturnstrue— no throw.resolvewas never called;rejectwas never wired. Theawaitin the test never returns.- Harness timeout fires;
socketis still live (bindState UNBOUND, handle present, noclose()in a finally).
Fix
const socket = dgram.createSocket("udp4");
const { promise, resolve, reject } = Promise.withResolvers();
socket.once("error", reject);
socket.bind(0, "127.0.0.1", resolve);
await promise;or equivalently await new Promise((resolve, reject) => { socket.once('error', reject); socket.bind(0, '127.0.0.1', resolve); }), and/or wrap the socket in a try { ... } finally { socket.close?.() } so it's released on failure.
…sync Four cases that fail at the current pin and pass on the oven-sh/WebKit#503 build: Promise.try returns a native promise as-is, setFromBase64 on a zero-length target reads nothing, WebAssembly.Module.imports() descriptors have the spec shape, and the DFG keeps the overflow check of an unused ++ / --. Carried over from #40263.
|
Closing as a duplicate of #40276. Both PRs carry the same Bun-side changes (the #40276 keeps going because its CI run is green (Build #104490) and oven-sh/WebKit#503 is the WebKit PR that stays open. The behavior test file from this PR is carried over there as |
…sync Four cases that fail at the current pin and pass on the oven-sh/WebKit#503 build: Promise.try returns a native promise as-is, setFromBase64 on a zero-length target reads nothing, WebAssembly.Module.imports() descriptors have the spec shape, and the DFG keeps the overflow check of an unused ++ / --. Carried over from #40263.
### 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 -->
Problem
aea1f010b6. Upstream WebKit main has moved 413 commits since the fork's merge base47f7250137c6, 90 of them in JavaScriptCore, WTF or bmalloc.@newPromiseCapabilityprivate builtin (WebKit/WebKit 38027ff0ec). Six call sites in Bun's bundled modules use it, so those modules fail to compile against the new engine. Upstream also stopped including<wtf/HexNumber.h>throughVM.h(314133b7a6), whichsrc/jsc/bindings/EncodeURIComponent.cpprelied on forhex().Fix
WEBKIT_VERSIONpoints at the Upgrade to upstream WebKit 55d9d9007f WebKit#501 build (autobuild-preview-pr-501-fabdd1db), which merges upstream55d9d9007finto the fork on top of the fork's current main (the bytecode cache work in http client causes deadlocks #490, Add react + rescript example #493,manifest.jsonreturns 404 withbun devin the react example #494, package.json requires name property to be set #497). That PR supersedes Upgrade to upstream WebKit baf4a9a7ec0b WebKit#488, and this PR supersedes Upgrade WebKit to baf4a9a7ec0b #40054. The conflict resolutions and the per-commit changelog are in Upgrade to upstream WebKit 55d9d9007f WebKit#501. Before this PR merges,WEBKIT_VERSIONhas to move to theautobuild-<sha>release that the fork's main produces once Upgrade to upstream WebKit 55d9d9007f WebKit#501 lands.node:events(once),node:util(aborted),node:dgram(Symbol.asyncDispose) and the HTTP server (CONNECT, Upgrade, the per-request completion promise) create their promise with$newPromise()and settle it with$resolvePromise/$rejectPromiseor the...WithFirstResolvingFunctionCallCheckvariants where a second settle is possible. This is what upstream's own builtins moved to: no capability record, no property lookups. These commits are carried over from Upgrade WebKit to baf4a9a7ec0b #40054 unchanged.builtins.d.tsdeclares the three intrinsics and drops$newPromiseCapability.util.abortedregisters and unregisters its FinalizationRegistry entry with the same token (the promise).EncodeURIComponent.cppincludes<wtf/HexNumber.h>itself.events.oncerejecting onerror, settling once when the event and an abort race, and resolving for anEventTarget;util.abortedresolving every waiter once;dgramSymbol.asyncDisposeresolving afterclose. Without the port these files fail at load against the new engine (Private symbol not found: newPromiseCapability).bun run build:local) runs the suites listed in the notes.bun build --bytecodeoutput from that build loads and runs.Background
scripts/build/deps/webkit.tsnames the release tag; CI downloads the matching tarball per platform.src/js/) are compiled by JavaScriptCore's builtin compiler. A$namecall becomes the private name@name, which has to exist in the engine.@newPromiseis a bytecode intrinsic and@resolvePromise/@rejectPromiseare link-time constants, so they are always available.$resolvePromiseand$rejectPromiserequire a pending promise (they assert on it in debug builds). The...WithFirstResolvingFunctionCallCheckvariants behave like the functions a Promise executor receives: the first call settles, later calls are ignored.Notes
autobuild-preview-pr-501-<first 8 of the head sha>), and this PR'sWEBKIT_VERSIONfollows it. CI lanes that fetch the prebuilt fail on the download until that tag's Actions run has published the release.test/js/bun/jsc,test/bundler/bundler_bun.test.ts,test/js/node/vm/vm.test.ts,test/js/node/events,test/js/node/util,test/js/node/dgram/node-dgram.test.js,test/js/node/http/node-http-connect.test.ts,test/js/bun/compile/standalone-madvise-tla.test.ts,test/regression/issue/26298.test.ts,test/js/web/atomics.test.ts,test/js/node/worker_threads,test/js/bun/wasm,test/js/web/url,test/js/node/module,test/js/bun/resolve,test/js/node/string_decoder,test/js/node/async_hooks,test/js/web/encoding. Alsotest/js/bun/jsc-stressand the newtest/js/bun/jsc/webkit-upgrade-55d9d9007f.test.ts. Every failure is a test that also fails on a debug build of the current pin on the same machine: the 5 s local timeouts under debug + ASAN (domjit.test.ts,worker_destruction.test.ts,parse-args.test.mjs,util-inspect.test.js, thenode-http-connect.test.tschild run, theresolve2000-file load) and the IPv6 multicastENODEVinnode-dgram.test.js.Promise.tryfollows the updated spec (PromiseResolveinstead ofNewPromiseCapability); the module map no longer caches fetch failures, so a secondimport()of a specifier whose load failed re-runs Bun's module loader instead of rejecting with the cached error;Uint8Array.prototype.setFromBase64on a zero-length target returns{ read: 0, written: 0 }without validating the input;WebAssembly.Module.imports()/exports()descriptors drop the non-standardtypefield; re-exported imported Wasm globals and tags keep object identity; an overflow-checked++/--whose result is unused is no longer dead-code-eliminated by the DFG together with its overflow check (7711916200).SymbolTableEntryno longer allocates aWatchpointSetper stored closure variable and global until something watches it (cea233cede);Object.assignwith 2 to 3 sources clones the first source's shape in one step (96ca975b2a);JSON.parseallocates arrays once at their final size;TypedArray.prototype.sort()without a comparator uses a radix sort for 2/4/8-byte element types;Map/SetforEachis inlined in the DFG and FTL; the bytecode cache emitsCodeForConstructfor class constructors so cached programs stop reparsing them;UnlinkedFunctionCodeBlockshrinks from 216 to 192 bytes;RegExpcells shrink from 96 to 80 bytes.src/jsc/bindings/NodeVMSyntheticModule.cppcallsSymbolTable::set(NoLockingNecessary, ...). After cea233cede only the locked overload exists;NoLockingNecessaryconverts to aConcurrentJSLocker, so the call compiles unchanged.sched_setattron every WTF thread,SCHED_BATCHcompiler 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. See Upgrade to upstream WebKit baf4a9a7ec0b WebKit#488 for the reasoning and how to drop that hunk.setFetchErrorfor a non-ErrorInstancefetch rejection) is superseded by upstream's module map change.no test proof · iteration 0 · 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