Bump WebKit (oven-sh/WebKit#425 preview): coverage of if bodies that only break or continue - #38321
Bump WebKit (oven-sh/WebKit#425 preview): coverage of if bodies that only break or continue#38321robobun wants to merge 1 commit into
Conversation
… path that ran
JSC folds `if (c) { break; }` / `if (c) { continue; }` into the condition's
jump and left the body's op_profile_control_flow on the fall-through path, so
the body's block was recorded as executed exactly when it was skipped. Bun
reports those blocks as line coverage: a break/continue line that ran on
every iteration showed up as uncovered and one that never ran as covered.
The engine fix is oven-sh/WebKit#425 (the fold is skipped while profiler
hooks are being emitted). Pin WEBKIT_VERSION to it and add a coverage test
covering both directions for for-of, while, for, braceless, switch and the
constant-condition shape from #20141.
|
Warning Review limit reached
Next review available in: 3 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
Updated 10:05 PM PT - Aug 13th, 2026
❌ @robobun, your commit 6225017 has 2 failures in
🧪 To try this PR locally: bunx bun-pr 38321That installs a local version of the PR into your bun-38321 --bun |
|
Status
|
There was a problem hiding this comment.
I reviewed this and didn't find any bugs — the new coverage test is well-constructed and the fixture line numbers check out. Since this is a WebKit engine bump and WEBKIT_VERSION is still pointing at the preview tag (pending oven-sh/WebKit#425 merging and the repin you mentioned), a human should sign off before this lands.
What was reviewed:
- Verified the 14 asserted line numbers in
lib.jsmap to the intendedbreak;/continue;and skipped-statement lines. lineCoveragehelper: drains stdout/stderr/exited concurrently,await usingfor the subprocess, lcov record lookup by bare filename (no path-separator concerns).prebuiltUrl/prebuiltDestDiralready handleautobuild--prefixed tags, so the preview pin resolves correctly.
Extended reasoning...
Overview
This PR bumps WEBKIT_VERSION in scripts/build/deps/webkit.ts from the stable sha caad865e… to the preview tag autobuild-preview-pr-425-01bb96e5, and adds a test in test/cli/test/coverage.test.ts covering lcov line-coverage status for if bodies that contain only break or continue. The actual behavioral fix lives in oven-sh/WebKit#425 (disabling tryFoldBreakAndContinue when the control-flow profiler is on); this PR is the bun-side pin bump plus regression test.
Security risks
None. The change is a dependency version pin plus a hermetic test that spawns bun test --coverage in a temp dir. No new attack surface, no untrusted input handling.
Level of scrutiny
High — any WebKit bump changes the JS engine that all of bun runs on, so even a one-commit bump warrants a maintainer's sign-off and a full CI pass. Additionally, the PR description is explicit that this is not yet in its final landable state: the pin targets an autobuild-preview-pr-* release that will disappear once the upstream PR merges, and the author plans to push a repin to the resulting main sha before landing. Approving now would risk merging a build pinned to an ephemeral artifact.
Other factors
- The test itself is solid: I hand-counted the fixture and confirmed lines 5/7, 15/17, 25/27, 35/37, 45/46, 55/57, 66/68 are the correct
break/continueand skipped-statement pairs. The helper follows harness conventions (tempDir,bunEnv,bunExe, concurrent pipe drain,await using,test.concurrent). scripts/build/deps/webkit.tsalready special-casesautobuild--prefixed versions in bothprebuiltUrl(uses the tag as-is) andprebuiltDestDir(strips the prefix for the cache key), so the preview pin is handled correctly by existing machinery.- The lcov record lookup uses
SF:lib.js\n— a bare filename with no directory separator, so no Windows path-normalization concern; consistent with the existing lcov snapshot in the same file. - No prior reviews from me on this PR.
Fixes #20141
Problem
bun test --coveragereports anifbody that consists only ofbreak;orcontinue;with the opposite of its real status: abreak;/continue;line that ran on every iteration is listed as uncovered, and one that never ran is listed as covered. Thewhile (true) { if (2 === 2) { break; } }function from [With test] Test coverage incorrect #20141 reports itsbreak;line as uncovered.The engine records the wrong block.
IfElseNode::emitBytecode(Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp,tryFoldBreakAndContinue) folds such a body into the condition's jump: the condition jumps straight to the break/continue target when true and falls through when false, and the body gets no bytecode of its own. Theop_profile_control_flowfor the body's text range is still emitted right after the condition, which makes it the first instruction on the fall-through path. With the profiler on,for (...) { if (xs[i]) { continue; } n++; }compiled to:src/sourcemap_jsc/CodeCoverage.rsreports what the profiler recorded, so there is nothing to change on the bun side. (test(coverage): attribute basic blocks to the lines of their code, not the lines around them #38282 is about which lines a block is charged to, a separate problem; it does not change this one.)Fix
tryFoldBreakAndContinuereturns false while profiler hooks are being emitted, so the body is emitted in full (profile op, jump, and the dead profile op after the jump). That is the shape{ f(); continue; }already produces, so nothing after bytecode generation sees anything new, and bytecode generated without the profiler is unchanged (dumped from both shells and compared).trivialTarget()already skips the same fold for the debugger, for the same reason: the statement needs bytecode of its own for the hook to sit in.WEBKIT_VERSIONat that PR's preview build (autobuild-preview-pr-425-01bb96e5) so CI runs against it. Before landing, Do not fold if-break/if-continue when emitting control flow profiler hooks WebKit#425 has to merge andWEBKIT_VERSIONhas to be repointed at the resulting main sha, which will be the current pincaad865eplus that one commit (the build prints this instruction itself once the preview release disappears). I will push the repin when Bun to an organization project #425 merges.test/cli/test/coverage.test.ts, "coverage of if bodies that only break or continue reflects whether they ran". One fixture function per shape: for-ofcontinuetaken and skipped,whilebreaktaken,forbreakskipped, bracelesscontinue,breakout of aswitchcase, and the constant-condition shape from [With test] Test coverage incorrect #20141. For each it asserts the lcov status of thebreak;/continue;line and of the statement the jump skips. The WebKit PR addsJSTests/controlFlowProfiler/if-break-continue.js, which checks the same shapes pluselsebranches, labeled targets and do-while at the basic-block level ($vmis not available under bun, so that half stays engine-side).bun bd --webkit-version=caad865eb1a6e5ca4427f5ea1f066140b11953e7 test test/cli/test/coverage.test.ts(current pin): the new test fails with exactly the sevenbreak;/continue;lines inverted; the seven lines after the jumps are already right.bun bd test test/cli/test/coverage.test.ts(preview pin): all 13 tests pass, existing snapshots unchanged.src/changes applied give the same two results, so the test does not care which of the two PRs lands first: it only asserts lines that hold a statement, and the fixture keeps a statement between each asserted line and the closing braces whose attribution test(coverage): attribute basic blocks to the lines of their code, not the lines around them #38282 changes.jscshell (continueTaken: 'continue;' executed 0 times, expected 3.) and passes, along with the rest ofJSTests/controlFlowProfiler, on a local build of the patched engine, with and without the JIT.Background
scripts/build/deps/webkit.tspins which build. An engine fix lands as a WebKit PR plus a pin bump here, and theautobuild-preview-pr-*tags are how a bump PR runs bun's suite against a WebKit PR before it merges.--coverageturns on JSC's control flow profiler. The bytecode generator then emits anop_profile_control_flowat the start of every basic block it knows about, and executing one marks that block as executed.CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler). The ranges were right here; the op for the body was just placed on the wrong path.CodeCoverage.rsasks JSC for these ranges and marks every line touched by an executed range as hit, so a misplaced op becomes a wrong line status directly.