Skip to content

WebKit upgrade to 46525dbf2abb#29897

Merged
Jarred-Sumner merged 16 commits into
mainfrom
jarred/webkit-upgrade-46525dbf2abb
May 1, 2026
Merged

WebKit upgrade to 46525dbf2abb#29897
Jarred-Sumner merged 16 commits into
mainfrom
jarred/webkit-upgrade-46525dbf2abb

Conversation

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator

WebKit upgrade: aac4aed489d1 → 46525dbf2abb (264 commits, 40 in JSC/WTF/bmalloc)

This upgrade pulls in Yusuke's libpas Windows cleanup (which we consolidate with our local Windows patches — see PR body), a JSPromiseReactionJSSlimPromiseReaction/JSFullPromiseReaction split that shifts JSType enum values, further module-loader spec alignment, Map/Set fast iteration in DFG/FTL, and several Intl/String/Array micro-optimizations.

⚠️ Bun-affecting

  • 61a88753e9e4 JSPromiseReactionType split into JSSlimPromiseReactionType + JSFullPromiseReactionType. Shifts every JSType value after it by +1. src/bun.js/bindings/JSType.zig must be regenerated. Any Bun binding referencing JSPromiseReaction directly needs updating.
  • 8af021fef543 More module-loader spec alignment (touches JSModuleLoader.cpp, ModuleGraphLoadingState.h). Conflicted with our recent module-loader perf work; merged.
  • 78682e818cf8 Avoid per-edge ModuleLoaderPayload allocation in graph loading — overlaps the same area as our loadRequestedModules memoization drop.
  • 0e74ad95db8e libpas Windows cleanup — see "libpas consolidation" section below.
  • 99779db9ef0c libpas: remove partial views. Renames kind_and_rolekind across segregated-view types; auto-merged into our TLC code.
  • 723db2e10e02 CMake: match Xcode's bmalloc/WTF/JSC build approach. May affect build.ts if it relied on old target layout.

Runtime / builtins

  • 433704897995 Map/Set fast iteration (new DFG/FTL path)
  • aa6c00c696e6 Inline String#localeCompare tight loop in FTL
  • f6d1b6eb589d padStart/padEnd produce flat strings for short results
  • bf720cf23f89 More truncate-double-to-int adoption in ArrayPrototype
  • 370fcab2a837 Remove @isArraySlow
  • e14f98504927 Move Symbol.hasInstance to C++
  • d1ec7b5323ad Remove createSuppressedError builtin
  • 10c13e90401d Refine clobberize rule for ObjectCreate
  • bfab8953b9ed emitBytecodeInConditionContext for optional chaining

Intl

  • 5da32d944f90 Lazily resolve default calendar/numberingSystem in Intl constructors
  • 3d3f4763409e Delay intlAvailableTimeZoneIndex init
  • a60e76055b01 Initialize IANA TimeZone data at VM creation

Parser / Yarr

  • 1088aa8bd998 YARR: reject dangling hyphen in /v class set
  • d4029d5d9a79 Build-speed fixes in JSC headers (forward decls / include hygiene — caused several trivial conflicts)

Wasm

  • b05d16f9ce83 Save source offset for Wasm const-expr evaluation (better error locations)
  • 008ce40466bc OMG: only emit WasmBoundsCheck overflow guard for Int64 pointers
  • 475a14fe4091 JSPI: change return-PC signing in EvacuatedStackSlices

Heap / GC

  • 5ade7c0d6d20 Remove printInternal(ConstraintVolatility) overload
  • 0d7053c9c316 Introduce UnbarrieredMonotonicTime

libpas / bmalloc

  • 0e74ad95db8e Windows cleanup: is_symmetric commit/decommit flag, virtual_query_checked, hardened pthread_cond_timedwait, proper pthread_create/detach split. We adopt this wholesale and re-layer our is_exiting flag, RtlDllShutdownInProgress guard, pas_thread_suspender, compact-heap lazy-commit, and TLC-decommit OS-gate widening on top — none subsumed.
  • 99779db9ef0c Remove partial views (segregated-view simplification)
  • 0e0e65cf0c2e Upgrade libpas to gnu++23

WTF

  • f69c4f5d8453 WTF::Liveness uses worklist
  • fd0db67fd877 Fix utf8ForCharacters crash on trailing unpaired surrogate
  • 9b4359d195c9 Adopt LIFETIME_BOUND in downcast family
  • f55db8dff653 Web-content hang fix (timer-related; touches WTF run-loop)
  • 41ae266227a4 Codegen: emit basenames not abs paths in generated comments (reproducible builds)

Build / misc

  • b1b0e820cdf6 Fix LLIntAssembly.h jsCast undeclared (regression fix)
  • 21ce77b3d34b / 466ee713fc9c / a24949c80905 UnifiedBuild grouping churn (landed, reverted, relanded)

WebKit PR: oven-sh/WebKit#203
WebKit pin: f7b52b080538

Binding adaptations

  • JSType.zig: PromiseReaction → Slim/Full split (+1 enum shift)
  • bindings.cpp: reaction->context()JSPromiseReaction::tryGetContext()
  • NodeVM.cpp: promiseEmptyOnRejectedFunction() removed → jsUndefined()
  • NodeVMSourceTextModule.cpp / BunAnalyzeTranspiledModule.cpp: status()/hasTLA() setters → setStatus()/setHasTLA()

Drive-by fixes (pre-existing, surfaced during validation)

  • dns.zig: c-ares can flip a TCP socket between writable↔readable; FilePoll is single-direction, so unregister before re-registering instead of stacking both flags (asserts on close after conn error)
  • test/harness.ts: expectMaxObjectTypeCount treated undefined as not-yet-collected (undefined <= n is false) → looped 50 sync GCs even when fully collected
  • sourcetextmodule-leak.test: 50k iterations on debug ASAN can't fit in 5s — scale to 2k/60s on debug

Adopts upstream's libpas Windows is_symmetric design (WebKit/WebKit#63762)
while keeping Bun's TLC suspender / shutdown-guard / lazy-commit patches.

Binding updates:
- JSType.zig: PromiseReaction split into Slim/Full (+1 enum shift)
- bindings.cpp: JSPromiseReaction::context() -> tryGetContext()
- NodeVM.cpp: promiseEmptyOnRejectedFunction() removed -> jsUndefined()
- NodeVMSourceTextModule.cpp / BunAnalyzeTranspiledModule.cpp: status()/hasTLA()
  setters renamed to setStatus()/setHasTLA()

Unrelated fixes surfaced while validating:
- dns.zig: c-ares can flip a TCP socket between writable/readable; FilePoll
  is single-direction, so unregister before re-registering instead of
  stacking both flags (tripped unregister assertion on conn error)
- test/harness.ts: expectMaxObjectTypeCount treated 'undefined' count as
  not-yet-collected (undefined <= n is false), looping the full wait
- sourcetextmodule-leak.test: scale iterations on debug builds
@robobun

robobun commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator
Updated 10:07 AM PT - May 1st, 2026

@Jarred-Sumner, your commit 039dd63 has 4 failures in Build #49715 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 29897

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

bun-29897 --bun

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

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

Walkthrough

Updates the pinned WebKit commit used for prebuilt downloads; makes DNS FilePoll registrations single-directional; splits PromiseReaction into SlimPromiseReaction and FullPromiseReaction (renumbering subsequent JSType values); adjusts several promise/module binding APIs; and tightens test null-handling and leak-test parameters.

Changes

Cohort / File(s) Summary
WebKit Version
scripts/build/deps/webkit.ts
Updated exported WEBKIT_VERSION constant to a new commit hash, changing the derived prebuilt WebKit tag for downloads.
DNS Socket Handling
src/bun.js/api/bun/dns.zig
Make FilePoll registration directional: compute desired readable/writable, unregister conflicting registration first, then register based on computed desires.
JSType enum
src/bun.js/bindings/JSType.zig
Replace single PromiseReaction variant with SlimPromiseReaction and FullPromiseReaction, renumbering subsequent JSType discriminants and updating isHidden logic.
Promise / Module Bindings
src/bun.js/bindings/BunAnalyzeTranspiledModule.cpp, src/bun.js/bindings/NodeVM.cpp, src/bun.js/bindings/bindings.cpp
Set top-level-await via JSModuleRecord::setHasTLA(...); pass jsUndefined() as then rejection argument; capture promise reactions into a JSValue and obtain context via JSPromiseReaction::tryGetContext(...).
Cyclic Module Status API
src/bun.js/bindings/NodeVMSourceTextModule.cpp
Use setStatus(...) to update CyclicModuleRecord status instead of calling status(...) directly.
Tests & Harness
test/harness.ts, test/js/node/vm/sourcetextmodule-leak.test.ts
expectMaxObjectTypeCount now uses nullish coalescing (?? 0) for missing counts; leak test parameters (iterations, RSS threshold, timeouts) are conditional on debug mode.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'WebKit upgrade to 46525dbf2abb' is a clear and concise single sentence that directly summarizes the main change: upgrading WebKit to a specific commit hash.
Description check ✅ Passed The PR description is comprehensive and covers what the PR does (WebKit upgrade with specific commits and changes) and verification approach through binding adaptations and drive-by fixes, matching the template structure despite not using explicit markdown headers.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/bun.js/api/bun/dns.zig`:
- Around line 2557-2559: The conditional that flips directions (checking
have_readable/want_readable and have_writable/want_writable) currently calls
poll.unregister(vm.event_loop_handle.?, false) which allows
FilePoll.unregisterWithFd’s fast path to skip kernel unregister and leaves
.poll_writable set; change the call to poll.unregister(vm.event_loop_handle.?,
true) (force unregister) so the kernel unregister always runs and poll direction
state is cleared when flipping from writable to readable; update the call site
in the block that uses have_readable/want_readable/have_writable/want_writable
to pass true.

In `@test/js/node/vm/sourcetextmodule-leak.test.ts`:
- Line 3: Replace the runtime require call with a module-scope import: change
the top-level "const { isDebug } = require('harness');" to a static import
statement "import { isDebug } from 'harness';" so the test uses module-scope
imports instead of require; locate the require for isDebug and update it
accordingly (ensure there are no other require usages in the file that should
also be converted).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2b9314c0-e887-4af8-be9e-ce770b0b23a3

📥 Commits

Reviewing files that changed from the base of the PR and between c027bf3 and ebfe4d0.

📒 Files selected for processing (9)
  • scripts/build/deps/webkit.ts
  • src/bun.js/api/bun/dns.zig
  • src/bun.js/bindings/BunAnalyzeTranspiledModule.cpp
  • src/bun.js/bindings/JSType.zig
  • src/bun.js/bindings/NodeVM.cpp
  • src/bun.js/bindings/NodeVMSourceTextModule.cpp
  • src/bun.js/bindings/bindings.cpp
  • test/harness.ts
  • test/js/node/vm/sourcetextmodule-leak.test.ts

Comment thread src/bun.js/api/bun/dns.zig Outdated
@@ -1,30 +1,40 @@
const vm = require("vm");
const { describe, it, expect } = require("bun:test");
const { isDebug } = require("harness");

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n test/js/node/vm/sourcetextmodule-leak.test.ts | head -50

Repository: oven-sh/bun

Length of output: 1593


Use module-scope import syntax instead of require in this test file.

Lines 1–3 use require() statements when the test is not specifically testing dynamic import/require behavior. Per coding guidelines, always use module-scope imports in such cases.

Suggested change
-const vm = require("vm");
-const { describe, it, expect } = require("bun:test");
-const { isDebug } = require("harness");
+import * as vm from "node:vm";
+import { describe, it, expect } from "bun:test";
+import { isDebug } from "harness";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { isDebug } = require("harness");
import * as vm from "node:vm";
import { describe, it, expect } from "bun:test";
import { isDebug } from "harness";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/js/node/vm/sourcetextmodule-leak.test.ts` at line 3, Replace the runtime
require call with a module-scope import: change the top-level "const { isDebug }
= require('harness');" to a static import statement "import { isDebug } from
'harness';" so the test uses module-scope imports instead of require; locate the
require for isDebug and update it accordingly (ensure there are no other require
usages in the file that should also be converted).

@github-actions

Copy link
Copy Markdown
Contributor

Found 5 issues this PR may fix:

  1. DNS option use-vc in /etc/resolv.conf / RES_USEVC is not respected #18694 - The dns.zig fix for c-ares TCP socket direction flipping (writable→readable) directly addresses DNS-over-TCP (use-vc) queries that were timing out
  2. Inconsistent escape character requirement for - in vnicode regular expressions #29003 - The upstream YARR dangling hyphen fix in /v class sets fixes the bug where /[a-]/v incorrectly succeeds instead of throwing a SyntaxError
  3. Crash in DFG JIT: Illegal instruction in pas_utils.h (WTF::Vector<DFG::AbstractValue> resize) #29412 - Crash in libpas (pas_utils.h assertion) during DFG CFA phase; upstream libpas memory allocator changes target this class of crash
  4. Segfault in JIT worker thread during DFG LICM phase on macOS aarch64 (Bun v1.3.11) #28842 - Segfault in libpas during DFG LICM phase allocation; addressed by the libpas memory allocator changes in the WebKit upgrade
  5. panic: Illegal instruction at address 0x7FF6A36B31F0 on Windows x64 (v1.3.13) #29827 - Illegal instruction crash in bmalloc allocation during DFG-compiled operationToLowerCase; libpas allocator changes in the WebKit upgrade could address this

If this is helpful, copy the block below into the PR description to auto-close these issues on merge.

Fixes #18694
Fixes #29003
Fixes #29412
Fixes #28842
Fixes #29827

🤖 Generated with Claude Code

Comment on lines +7 to +8
const ITERATIONS = isDebug ? 2_000 : 50_000;
const THRESHOLD_MB = isDebug ? 300 : 3000;

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.

🟡 nit: the debug-mode threshold (300MB) is looser per-iteration than release — 2,000 × ~50KB ≈ 100MB of source text, so even a 100% source-string leak wouldn't trip it. If the debug variant is intended to be a leak gate (vs. just a smoke/timeout fix), consider lowering THRESHOLD_MB to ~150 for isDebug; otherwise a comment that debug is intentionally just a crash/assert check would clarify.

Extended reasoning...

What this is

The new debug-mode constants are:

const ITERATIONS = isDebug ? 2_000 : 50_000;
const THRESHOLD_MB = isDebug ? 300 : 3000;

The comment immediately above explains the test's intent: "50k×50KB ≈ 2.5 GB of source text — if module records leak their source we blow past the threshold." In release that holds (2.5GB of source vs a 3GB threshold, ratio ~0.83). In debug it doesn't: 2,000 × ~50KB ≈ 100MB of total source text against a 300MB threshold (ratio ~0.33). Put another way, the per-iteration budget went from ~60KB/iter (release) to ~150KB/iter (debug) — about 2.5× more permissive.

How it manifests

Concretely, walk one debug iteration:

  1. source is a ~50,000-byte string (Buffer.alloc(50_000, ...) plus a few bytes of wrapper).
  2. Each go(i) constructs a vm.SourceTextModule with a unique copy of that source (source + "//" + i), links and evaluates it.
  3. After 2,000 iterations and a forced GC, RSS delta is compared to THRESHOLD_MB.

If the regression this test guards against returned — i.e. each module's SourceProvider/source string is never released — the raw source bytes alone total ~100MB. That sits comfortably below 300MB, so the assertion would still pass and the leak would be invisible on debug runs. The release variant (unchanged) remains the actual gate.

Why nothing else catches it

There's no other check in the debug path: the test computes (rss after − rss before) and asserts < THRESHOLD_MB. With the threshold at 3× the worst-case raw-source footprint, the only way the debug assertion fires is if a leak retains substantially more than the source string per module (record + executable + provider + ASAN redzones may or may not push it over, but the test no longer guarantees it the way the comment implies).

Why this is only a nit

  • The PR's stated goal for the debug branch is to make a previously-timing-out test runnable ("50k iterations on debug ASAN can't fit in 5s"). It's a strict improvement over a test that never finished on debug; release CI is the real leak signal and is unchanged.
  • Debug+ASAN has real RSS overhead (shadow memory, redzones, quarantine) that justifies extra headroom — a tight 100–120MB threshold could flake even with no leak.
  • A real leaked module retains more than the 50KB source string (JSModuleRecord, ModuleProgramExecutable, identifier, etc.), so a full leak would likely still exceed 300MB under ASAN — it's just no longer guaranteed by the arithmetic the comment relies on.

This is the same objection the refutation raises, and it's fair: the change is intentional and net-positive. The point being flagged is narrower — the threshold and the comment are now inconsistent on debug, which can mislead a future reader into thinking the debug assertion bounds the source-leak case when it doesn't.

Suggested fix

Either lower the debug threshold so it still bounds a pure source leak with reasonable ASAN headroom, e.g.:

const THRESHOLD_MB = isDebug ? 150 : 3000;

or, if 300MB is deliberately chosen for ASAN noise, add a one-line note that the debug variant is primarily a crash/assert smoke check and the leak gate is the release run. Non-blocking either way.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/build/deps/webkit.ts`:
- Line 6: The current WEBKIT_VERSION value mixes a prebuilt tag with what tools
expect to be a commit hash; split it into two constants (e.g., WEBKIT_COMMIT for
the canonical git commit hash and WEBKIT_PREBUILT_TAG for the autobuild download
tag), update the export in webkit.ts to expose both symbols, and change
consumers: have scripts/sync-webkit-source.ts use WEBKIT_COMMIT for git checkout
and have scripts/build/depVersionsHeader.ts (and any process.versions.WEBKIT
reporting) read WEBKIT_COMMIT for version metadata while using
WEBKIT_PREBUILT_TAG only when resolving/download prebuilt binaries. Ensure names
match exactly (WEBKIT_COMMIT, WEBKIT_PREBUILT_TAG) so updates are
straightforward.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8bff775b-2b03-40cd-aa8e-630ba1679684

📥 Commits

Reviewing files that changed from the base of the PR and between ebfe4d0 and f36e82a.

📒 Files selected for processing (1)
  • scripts/build/deps/webkit.ts

Comment thread scripts/build/deps/webkit.ts Outdated
* From https://github.com/oven-sh/WebKit releases.
*/
export const WEBKIT_VERSION = "137c59666cfb02c45d04dcfd4b3852e27f78cffc";
export const WEBKIT_VERSION = "autobuild-preview-pr-203-f7b52b08";

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.

⚠️ Potential issue | 🟠 Major

Split source commit from prebuilt tag; current value breaks commit-based consumers.

Line 6 changes WEBKIT_VERSION from a commit-like value to an autobuild-* tag, but downstream tooling still treats it as a git commit (scripts/sync-webkit-source.ts does git checkout ${expectedCommit}) and version metadata logic expects a clean commit hash (scripts/build/depVersionsHeader.ts). This will break local source sync and muddies process.versions.WEBKIT.

Please keep a commit-hash source-of-truth (for checkout/version reporting) and introduce a separate prebuilt release-tag field for download resolution.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/build/deps/webkit.ts` at line 6, The current WEBKIT_VERSION value
mixes a prebuilt tag with what tools expect to be a commit hash; split it into
two constants (e.g., WEBKIT_COMMIT for the canonical git commit hash and
WEBKIT_PREBUILT_TAG for the autobuild download tag), update the export in
webkit.ts to expose both symbols, and change consumers: have
scripts/sync-webkit-source.ts use WEBKIT_COMMIT for git checkout and have
scripts/build/depVersionsHeader.ts (and any process.versions.WEBKIT reporting)
read WEBKIT_COMMIT for version metadata while using WEBKIT_PREBUILT_TAG only
when resolving/download prebuilt binaries. Ensure names match exactly
(WEBKIT_COMMIT, WEBKIT_PREBUILT_TAG) so updates are straightforward.

@Jarred-Sumner Jarred-Sumner force-pushed the jarred/webkit-upgrade-46525dbf2abb branch from 94ed419 to e17dbd3 Compare April 29, 2026 02:01

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
scripts/build/deps/webkit.ts (1)

6-6: ⚠️ Potential issue | 🟠 Major

Split commit identity from prebuilt tag; current constant conflates both.

Line 6 changes WEBKIT_VERSION to an autobuild-* tag even though this constant is documented as the checkout commit/hash source-of-truth. That can break commit-based local source sync/version metadata flows. Keep a commit field and a separate prebuilt tag field, then use each in the appropriate consumer path.

Proposed direction
- export const WEBKIT_VERSION = "autobuild-preview-pr-203-a5bf2e31";
+ export const WEBKIT_COMMIT = "a5bf2e31"; // or full commit hash used for checkout/version metadata
+ export const WEBKIT_PREBUILT_TAG = "autobuild-preview-pr-203-a5bf2e31";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/build/deps/webkit.ts` at line 6, The current WEBKIT_VERSION constant
conflates the source commit and an autobuild prebuilt tag; split these into two
constants: restore WEBKIT_VERSION (or introduce WEBKIT_COMMIT) to contain the
actual checkout commit/hash as the source-of-truth, and add a new
WEBKIT_PREBUILT_TAG (or WEBKIT_BUILD_TAG) set to
"autobuild-preview-pr-203-a5bf2e31"; then update any consumers to use
WEBKIT_COMMIT/WEBKIT_VERSION for checkout/sync logic and WEBKIT_PREBUILT_TAG for
prebuilt artifact resolution (search for usages of WEBKIT_VERSION to ensure each
consumer references the correct new symbol).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@scripts/build/deps/webkit.ts`:
- Line 6: The current WEBKIT_VERSION constant conflates the source commit and an
autobuild prebuilt tag; split these into two constants: restore WEBKIT_VERSION
(or introduce WEBKIT_COMMIT) to contain the actual checkout commit/hash as the
source-of-truth, and add a new WEBKIT_PREBUILT_TAG (or WEBKIT_BUILD_TAG) set to
"autobuild-preview-pr-203-a5bf2e31"; then update any consumers to use
WEBKIT_COMMIT/WEBKIT_VERSION for checkout/sync logic and WEBKIT_PREBUILT_TAG for
prebuilt artifact resolution (search for usages of WEBKIT_VERSION to ensure each
consumer references the correct new symbol).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ae641ccb-269d-4043-b143-19a67bb65031

📥 Commits

Reviewing files that changed from the base of the PR and between f36e82a and e17dbd3.

📒 Files selected for processing (1)
  • scripts/build/deps/webkit.ts

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
src/bun.js/api/bun/dns.zig (1)

2566-2567: ⚠️ Potential issue | 🟠 Major

Force unregister when flipping poll direction.

Line 2567 still uses poll.unregister(..., false). In the non-forced path, FilePoll can retain the previous direction flag, so the subsequent register() may leave stale poll state and violate the single-direction invariant this block is trying to enforce.

Suggested change
-            if ((have_readable and !want_readable) or (have_writable and !want_writable)) {
-                _ = poll.unregister(vm.event_loop_handle.?, false);
-            }
+            if ((have_readable and !want_readable) or (have_writable and !want_writable)) {
+                _ = poll.unregister(vm.event_loop_handle.?, true);
+            }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bun.js/api/bun/dns.zig` around lines 2566 - 2567, The unregister call in
the direction-flip branch still passes false causing FilePoll to possibly retain
previous direction; change the call to force-unregister so the old poll state is
removed (i.e., call poll.unregister(vm.event_loop_handle.?, true)) before
re-registering to ensure register() doesn't inherit stale direction flags (refer
to poll.unregister, vm.event_loop_handle, FilePoll and the subsequent register()
call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/bun.js/api/bun/dns.zig`:
- Around line 2566-2567: The unregister call in the direction-flip branch still
passes false causing FilePoll to possibly retain previous direction; change the
call to force-unregister so the old poll state is removed (i.e., call
poll.unregister(vm.event_loop_handle.?, true)) before re-registering to ensure
register() doesn't inherit stale direction flags (refer to poll.unregister,
vm.event_loop_handle, FilePoll and the subsequent register() call).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d1dd1ddf-6f9e-44f9-b7a5-7bb6efcdc8cc

📥 Commits

Reviewing files that changed from the base of the PR and between e17dbd3 and 67737fe.

📒 Files selected for processing (2)
  • scripts/build/deps/webkit.ts
  • src/bun.js/api/bun/dns.zig

Comment thread test/harness.ts
Comment on lines +145 to +152
if ((heapStats().objectTypeCounts[type] ?? 0) <= count) return;
gc(true);
for (const wait = 20; maxWait > 0; maxWait -= wait) {
if (heapStats().objectTypeCounts[type] <= count) break;
if ((heapStats().objectTypeCounts[type] ?? 0) <= count) break;
await Bun.sleep(wait);
gc();
}
expect(heapStats().objectTypeCounts[type] || 0).toBeLessThanOrEqual(count);
expect(heapStats().objectTypeCounts[type] ?? 0).toBeLessThanOrEqual(count);

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.

🟡 Pre-existing nit: test/js/web/abort/abort.ts:5-20 has an inlined copy of expectMaxObjectTypeCount with the same undefined <= count pattern this fixes (lines 12/15/19 — line 19 lacks even the old || 0, so a fully-collected type would fail the assertion outright). Might be worth giving it the same ?? 0 treatment, or just replacing it with import { expectMaxObjectTypeCount } from "harness". Non-blocking — test-perf only and not touched by this PR.

Extended reasoning...

What this is

This PR's drive-by fix to test/harness.ts:145-152 adds ?? 0 to the three heapStats().objectTypeCounts[type] lookups in expectMaxObjectTypeCount, so that an absent type (lookup returns undefined) is treated as 0 rather than falling through the comparison. The PR description explicitly calls out the bug being fixed: "expectMaxObjectTypeCount treated undefined as not-yet-collected (undefined <= n is false) → looped 50 sync GCs even when fully collected."

test/js/web/abort/abort.ts:5-20 contains an inlined private copy of the same helper with the identical defect:

async function expectMaxObjectTypeCount(expect, type, count, maxWait = 1000) {
  gc(true);
  if (heapStats().objectTypeCounts[type] <= count) return;       // line 12
  gc(true);
  for (const wait = 20; maxWait > 0; maxWait -= wait) {
    if (heapStats().objectTypeCounts[type] <= count) break;      // line 15
    await new Promise(resolve => setTimeout(resolve, wait));
    gc(true);
  }
  expect(heapStats().objectTypeCounts[type]).toBeLessThanOrEqual(count);  // line 19
}

None of the three lookups have a ?? 0 guard. Line 19 is actually slightly worse than the pre-PR harness.ts version, which at least had || 0 on the final expect — abort.ts has no fallback at all.

How it manifests

Walk through one call with type = "AbortSignal" and count = 10, assuming the GC has fully collected every AbortSignal so the key is absent from heapStats().objectTypeCounts:

  1. Line 12: undefined <= 10 → coerces to NaN <= 10false. The early-return is skipped even though 0 ≤ 10.
  2. Loop runs ~50 iterations (1000ms / 20ms). Line 15 evaluates undefined <= 10false every time, so the loop never breaks early. Each iteration does a sync gc(true) plus a 20ms sleep.
  3. Line 19: expect(undefined).toBeLessThanOrEqual(10) — this fails the assertion (Bun's matcher does not coerce undefined to 0), so a fully-collected type would actually make the test fail rather than pass.

The harness.ts fix in this PR addresses exactly steps 1-3 for the shared helper; the abort.ts copy retains all three.

Why nothing else catches it

abort.ts defines its own private expectMaxObjectTypeCount rather than importing from harness, so the harness.ts fix doesn't reach it. There's no shared abstraction — it's a copy-paste duplicate. The two callers in abort.ts (lines ~175-176, for "AbortController" and "AbortSignal") hit this local copy directly.

Why this is only a nit / pre-existing

  • Not introduced by this PR: abort.ts is untouched in the diff; the bug predates this change.
  • Unlikely to fire in practice: AbortController and AbortSignal are essentially always present in heapStats().objectTypeCounts (the test harness/runtime keeps some alive), so the undefined case probably never triggers in CI — which is why line 19's missing || 0 hasn't been failing.
  • Test-perf only when it does trigger (lines 12/15): ~1s of wasted gc(true) + sleep per call, not a correctness issue for the leak-check itself.
  • The PR is a WebKit upgrade, not a "fix all expectMaxObjectTypeCount copies" PR; the harness.ts change was a drive-by surfaced during validation. The author isn't obligated to grep for copy-pasted duplicates.

That said, since the PR explicitly identifies and documents this exact pattern as a bug worth fixing, flagging the identical inlined duplicate is reasonable review feedback — the author is already in the mindset and may want to apply it (or de-duplicate) in the same pass.

Suggested fix

Either apply the same ?? 0 to abort.ts:12/15/19, or (better) delete the local copy and import { expectMaxObjectTypeCount } from "harness". Non-blocking either way.

Comment thread src/bun.js/api/bun/dns.zig Outdated

@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.

Additional findings (outside current diff — PR may have been updated during review):

  • 🟣 src/bun.js/api/bun/dns.zig:2572-2574 — Re: CodeRabbit's suggestion to pass force_unregister=true here — that's unnecessary for DNS polls: .needs_rearm is only ever set when .one_shot is set (posix_event_loop.zig:338-339), and dns.zig registers with one_shot=false, so this unregister() call can never reach the needs_rearm fast path. That said, looking at that fast path did surface a real pre-existing copy-paste typo at src/async/posix_event_loop.zig:1067-1070: .poll_process is removed twice and .poll_writable is never removed (compare lines 1211-1214 which correctly remove all four). Not introduced or reachable from this PR's change — just worth a one-line fix while in the area.

    Extended reasoning...

    What this is

    CodeRabbit's inline comment on this line claims that poll.unregister(vm.event_loop_handle.?, false) can hit FilePoll.unregisterWithFd's needs_rearm fast path, which "skips kernel unregister and currently does not clear .poll_writable", and suggests passing true to force the kernel unregister. Investigating that claim surfaces a real copy-paste typo in src/async/posix_event_loop.zig:1067-1070:

    if (this.flags.contains(.needs_rearm) and !force_unregister) {
        log("unregister: {s} ({f}) skipped due to needs_rearm", .{ @tagName(flag), fd });
        this.flags.remove(.poll_process);
        this.flags.remove(.poll_readable);
        this.flags.remove(.poll_process);   // <-- duplicate; should be .poll_writable
        this.flags.remove(.poll_machport);
        return .success;
    }

    .poll_process is removed twice and .poll_writable is never removed. Compare to the full unregister path at lines 1211-1214, which correctly removes .poll_readable, .poll_writable, .poll_process, .poll_machport.

    Why the dns.zig change cannot reach this path

    .needs_rearm is inserted in exactly one place — FilePoll.onUpdate at posix_event_loop.zig:338-339:

    if (poll.flags.contains(.one_shot) and !poll.flags.contains(.needs_rearm)) {
        poll.flags.insert(.needs_rearm);
    }

    It is gated on .one_shot. The dns.zig register() calls at lines 2577/2580 pass one_shot=false (third arg), so DNS polls never have .one_shot set, never get .needs_rearm set, and therefore the if (this.flags.contains(.needs_rearm) and !force_unregister) branch at line 1065 is always false for them. The new unregister(..., false) call falls through to the full kernel-unregister path (lines 1076+ / 1207-1214), which correctly clears all four direction flags. CodeRabbit's suggested force_unregister=true is therefore a no-op for dns.zig correctness.

    Step-by-step proof (hypothetical one-shot writable poll, not DNS)

    For a poll that is one-shot — e.g. some other FilePoll consumer that calls register(loop, .writable, true):

    1. register(.writable, one_shot=true) sets .poll_writable and .one_shot.
    2. The fd becomes writable; onUpdate runs. Line 338-339: .one_shot is set, so .needs_rearm is inserted.
    3. Caller invokes unregister(loop, false). Line 1065: .needs_rearm is set and force_unregister=false, so the fast path runs.
    4. Lines 1067-1070 remove .poll_process, .poll_readable, .poll_process (again), .poll_machport. .poll_writable remains set.
    5. A subsequent register(loop, .readable, ...) would set .poll_readable, leaving the poll holding both .poll_readable and .poll_writable, which trips the bun.assert(!(... .poll_readable and ... .poll_writable)) at line 1210 the next time the full unregister path runs.

    This is a real latent bug for one-shot writable polls elsewhere in the codebase; it just isn't the dns.zig case.

    Why nothing else catches it

    The fast path is specifically the "kernel already auto-removed this one-shot registration, just clear our bookkeeping" branch, so there's no kernel state to disagree with — the only thing wrong is the in-memory .poll_writable flag lingering. It only manifests when the same FilePoll is reused with a different direction after a one-shot writable cycle, which is exactly the pattern this dns.zig change introduces (direction flips on a reused poll) — but dns.zig is non-one-shot, so it dodges the bug entirely.

    Suggested fix

    One-line, in src/async/posix_event_loop.zig:

                 this.flags.remove(.poll_process);
                 this.flags.remove(.poll_readable);
    -            this.flags.remove(.poll_process);
    +            this.flags.remove(.poll_writable);
                 this.flags.remove(.poll_machport);

    Pre-existing and not in a file this PR touches; non-blocking, but trivially fixable while you're already looking at the FilePoll direction-flag invariant.

Comment thread scripts/build/deps/webkit.ts Outdated
Jarred-Sumner added a commit that referenced this pull request Apr 30, 2026
… assertion) (#29955)

c-ares can request both readable and writable on the same TCP DNS fd —
writable while connecting or when a send hits EAGAIN, readable for the
response. `dns.zig:onDNSSocketState` registered both directions on a
single `FilePoll`, which set both `.poll_readable` and `.poll_writable`;
on close, `unregisterWithFd` tripped `bun.assert(!(poll_readable &&
poll_writable))`. On epoll the second `register` was also a `CTL_MOD`
that silently overwrote the first direction's mask.

### Changes

`src/async/posix_event_loop.zig`:
- **`registerWithFd` (epoll):** when the other direction is already
registered on this poll, OR its event mask into the `CTL_MOD` so both
stay armed. `debugAssert` against bidirectional + one-shot (EPOLLONESHOT
disarms the whole fd on the first event in either direction — not hit by
the DNS path, which passes one_shot=false).
- **`registerWithFd` (kqueue):** unchanged. kqueue keys on `(ident,
filter)`, so the second `register()` call's `EV_ADD` creates a separate
knote for the new filter without touching the existing one — there is no
"already registered → modify" branch on kqueue.
- **`unregisterWithFd` (kqueue mac/freebsd):** when both directions are
set, submit two `EV_DELETE` changes (`EVFILT_READ` + `EVFILT_WRITE`) in
one kevent call. epoll's `CTL_DEL` keys on fd alone so already removes
both. Dropped the both-directions assertion.
- macOS: changelist is `[2]kevent64_s`. The rc<0 global-error check now
runs before per-entry `EV_ERROR` checks, which are guarded on `rc >= N`
(with `KEVENT_FLAG_ERROR_EVENTS` error events are packed from index 0,
not positionally matched to changes).
- FreeBSD: `nevents=0`, so per-entry errors surface as rc=-1/errno for
the first failing change; a silent miss on the second `EV_DELETE`
(ENOENT) is harmless.
- `needs_rearm` early-return now also clears `.poll_writable` (was only
clearing readable/process/machport).

`src/bun.js/api/bun/dns.zig:onDNSSocketState` (POSIX): when c-ares's
desired direction set differs from what's registered:
- **Adding only** (e.g. W → R+W): just `register()` the new direction —
one `CTL_MOD` on epoll, one `EV_ADD` on kqueue.
- **Dropping a direction** (e.g. W → R): `unregister()` then
re-`register()` the remaining direction(s). FilePoll has no
per-direction unregister, and leaving writable armed on a
level-triggered connected socket would busy-loop. c-ares DNS fds are
short-lived so the extra syscall is acceptable.

`activate`/`deactivate` are already idempotent via
`has_incremented_poll_count`, so registering twice keeps the loop
refcount correct.

### Tests

- `bun run zig:check-all`: all platforms compile (Linux/macOS/Windows ×
debug/release, x64/arm64).
- `test/js/node/dns/` + `test/js/bun/dns/`: 137 pass / 2 fail (both
pre-existing env-dependent: `dns.prefetch` cache-hit timing,
`dns.getServers` resolv.conf — fail identically on parent of this
commit).
- `test/js/node/async_hooks/`: 110 pass / 3 todo / 1 fail (pre-existing
`http-clientrequest` timeout, unrelated).
- `async-context-dns-resolveTxt.js` fixture (original repro): exit 0.

Split out of #29897 per review.

---------

Co-authored-by: robobun <robobun@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
@Jarred-Sumner Jarred-Sumner merged commit 4e34db2 into main May 1, 2026
73 of 77 checks passed
@Jarred-Sumner Jarred-Sumner deleted the jarred/webkit-upgrade-46525dbf2abb branch May 1, 2026 20:59
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
… assertion) (oven-sh#29955)

c-ares can request both readable and writable on the same TCP DNS fd —
writable while connecting or when a send hits EAGAIN, readable for the
response. `dns.zig:onDNSSocketState` registered both directions on a
single `FilePoll`, which set both `.poll_readable` and `.poll_writable`;
on close, `unregisterWithFd` tripped `bun.assert(!(poll_readable &&
poll_writable))`. On epoll the second `register` was also a `CTL_MOD`
that silently overwrote the first direction's mask.

### Changes

`src/async/posix_event_loop.zig`:
- **`registerWithFd` (epoll):** when the other direction is already
registered on this poll, OR its event mask into the `CTL_MOD` so both
stay armed. `debugAssert` against bidirectional + one-shot (EPOLLONESHOT
disarms the whole fd on the first event in either direction — not hit by
the DNS path, which passes one_shot=false).
- **`registerWithFd` (kqueue):** unchanged. kqueue keys on `(ident,
filter)`, so the second `register()` call's `EV_ADD` creates a separate
knote for the new filter without touching the existing one — there is no
"already registered → modify" branch on kqueue.
- **`unregisterWithFd` (kqueue mac/freebsd):** when both directions are
set, submit two `EV_DELETE` changes (`EVFILT_READ` + `EVFILT_WRITE`) in
one kevent call. epoll's `CTL_DEL` keys on fd alone so already removes
both. Dropped the both-directions assertion.
- macOS: changelist is `[2]kevent64_s`. The rc<0 global-error check now
runs before per-entry `EV_ERROR` checks, which are guarded on `rc >= N`
(with `KEVENT_FLAG_ERROR_EVENTS` error events are packed from index 0,
not positionally matched to changes).
- FreeBSD: `nevents=0`, so per-entry errors surface as rc=-1/errno for
the first failing change; a silent miss on the second `EV_DELETE`
(ENOENT) is harmless.
- `needs_rearm` early-return now also clears `.poll_writable` (was only
clearing readable/process/machport).

`src/bun.js/api/bun/dns.zig:onDNSSocketState` (POSIX): when c-ares's
desired direction set differs from what's registered:
- **Adding only** (e.g. W → R+W): just `register()` the new direction —
one `CTL_MOD` on epoll, one `EV_ADD` on kqueue.
- **Dropping a direction** (e.g. W → R): `unregister()` then
re-`register()` the remaining direction(s). FilePoll has no
per-direction unregister, and leaving writable armed on a
level-triggered connected socket would busy-loop. c-ares DNS fds are
short-lived so the extra syscall is acceptable.

`activate`/`deactivate` are already idempotent via
`has_incremented_poll_count`, so registering twice keeps the loop
refcount correct.

### Tests

- `bun run zig:check-all`: all platforms compile (Linux/macOS/Windows ×
debug/release, x64/arm64).
- `test/js/node/dns/` + `test/js/bun/dns/`: 137 pass / 2 fail (both
pre-existing env-dependent: `dns.prefetch` cache-hit timing,
`dns.getServers` resolv.conf — fail identically on parent of this
commit).
- `test/js/node/async_hooks/`: 110 pass / 3 todo / 1 fail (pre-existing
`http-clientrequest` timeout, unrelated).
- `async-context-dns-resolveTxt.js` fixture (original repro): exit 0.

Split out of oven-sh#29897 per review.

---------

Co-authored-by: robobun <robobun@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
# WebKit upgrade: aac4aed489d1 → 46525dbf2abb (264 commits, 40 in
JSC/WTF/bmalloc)

This upgrade pulls in Yusuke's libpas Windows cleanup (which we
consolidate with our local Windows patches — see PR body), a
`JSPromiseReaction` → `JSSlimPromiseReaction`/`JSFullPromiseReaction`
split that shifts `JSType` enum values, further module-loader spec
alignment, Map/Set fast iteration in DFG/FTL, and several
Intl/String/Array micro-optimizations.

## ⚠️ Bun-affecting

- **61a88753e9e4** `JSPromiseReactionType` split into
`JSSlimPromiseReactionType` + `JSFullPromiseReactionType`. Shifts every
`JSType` value after it by +1. **`src/bun.js/bindings/JSType.zig` must
be regenerated.** Any Bun binding referencing `JSPromiseReaction`
directly needs updating.
- **8af021fef543** More module-loader spec alignment (touches
`JSModuleLoader.cpp`, `ModuleGraphLoadingState.h`). Conflicted with our
recent module-loader perf work; merged.
- **78682e818cf8** Avoid per-edge `ModuleLoaderPayload` allocation in
graph loading — overlaps the same area as our `loadRequestedModules`
memoization drop.
- **0e74ad95db8e** libpas Windows cleanup — see "libpas consolidation"
section below.
- **99779db9ef0c** libpas: remove partial views. Renames `kind_and_role`
→ `kind` across segregated-view types; auto-merged into our TLC code.
- **723db2e10e02** CMake: match Xcode's bmalloc/WTF/JSC build approach.
May affect `build.ts` if it relied on old target layout.

## Runtime / builtins

- 433704897995 Map/Set fast iteration (new DFG/FTL path)
- aa6c00c696e6 Inline `String#localeCompare` tight loop in FTL
- f6d1b6eb589d `padStart`/`padEnd` produce flat strings for short
results
- bf720cf23f89 More truncate-double-to-int adoption in `ArrayPrototype`
- 370fcab2a837 Remove `@isArraySlow`
- e14f98504927 Move `Symbol.hasInstance` to C++
- d1ec7b5323ad Remove `createSuppressedError` builtin
- 10c13e90401d Refine `clobberize` rule for `ObjectCreate`
- bfab8953b9ed `emitBytecodeInConditionContext` for optional chaining

## Intl

- 5da32d944f90 Lazily resolve default calendar/numberingSystem in Intl
constructors
- 3d3f4763409e Delay `intlAvailableTimeZoneIndex` init
- a60e76055b01 Initialize IANA TimeZone data at VM creation

## Parser / Yarr

- 1088aa8bd998 YARR: reject dangling hyphen in `/v` class set
- d4029d5d9a79 Build-speed fixes in JSC headers (forward decls / include
hygiene — caused several trivial conflicts)

## Wasm

- b05d16f9ce83 Save source offset for Wasm const-expr evaluation (better
error locations)
- 008ce40466bc OMG: only emit `WasmBoundsCheck` overflow guard for Int64
pointers
- 475a14fe4091 JSPI: change return-PC signing in `EvacuatedStackSlices`

## Heap / GC

- 5ade7c0d6d20 Remove `printInternal(ConstraintVolatility)` overload
- 0d7053c9c316 Introduce `UnbarrieredMonotonicTime`

## libpas / bmalloc

- **0e74ad95db8e** Windows cleanup: `is_symmetric` commit/decommit flag,
`virtual_query_checked`, hardened `pthread_cond_timedwait`, proper
`pthread_create`/`detach` split. **We adopt this wholesale and re-layer
our `is_exiting` flag, `RtlDllShutdownInProgress` guard,
`pas_thread_suspender`, compact-heap lazy-commit, and TLC-decommit
OS-gate widening on top — none subsumed.**
- 99779db9ef0c Remove partial views (segregated-view simplification)
- 0e0e65cf0c2e Upgrade libpas to gnu++23

## WTF

- f69c4f5d8453 `WTF::Liveness` uses worklist
- fd0db67fd877 Fix `utf8ForCharacters` crash on trailing unpaired
surrogate
- 9b4359d195c9 Adopt `LIFETIME_BOUND` in `downcast` family
- f55db8dff653 Web-content hang fix (timer-related; touches WTF
run-loop)
- 41ae266227a4 Codegen: emit basenames not abs paths in generated
comments (reproducible builds)

## Build / misc

- b1b0e820cdf6 Fix `LLIntAssembly.h` `jsCast` undeclared (regression
fix)
- 21ce77b3d34b / 466ee713fc9c / a24949c80905 UnifiedBuild grouping churn
(landed, reverted, relanded)

---

WebKit PR: oven-sh/WebKit#203
WebKit pin: `f7b52b080538`

## Binding adaptations
- `JSType.zig`: PromiseReaction → Slim/Full split (+1 enum shift)
- `bindings.cpp`: `reaction->context()` →
`JSPromiseReaction::tryGetContext()`
- `NodeVM.cpp`: `promiseEmptyOnRejectedFunction()` removed →
`jsUndefined()`
- `NodeVMSourceTextModule.cpp` / `BunAnalyzeTranspiledModule.cpp`:
`status()`/`hasTLA()` setters → `setStatus()`/`setHasTLA()`

## Drive-by fixes (pre-existing, surfaced during validation)
- **dns.zig**: c-ares can flip a TCP socket between writable↔readable;
FilePoll is single-direction, so unregister before re-registering
instead of stacking both flags (asserts on close after conn error)
- **test/harness.ts**: `expectMaxObjectTypeCount` treated `undefined` as
not-yet-collected (`undefined <= n` is `false`) → looped 50 sync GCs
even when fully collected
- **sourcetextmodule-leak.test**: 50k iterations on debug ASAN can't fit
in 5s — scale to 2k/60s on debug
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