Skip to content

test: add JSC stress fixture for the DFG fast ArrayIterator entries path - #33260

Open
robobun wants to merge 2 commits into
mainfrom
farm/eda942d9/jsc-stress-array-entries
Open

test: add JSC stress fixture for the DFG fast ArrayIterator entries path#33260
robobun wants to merge 2 commits into
mainfrom
farm/eda942d9/jsc-stress-array-entries

Conversation

@robobun

@robobun robobun commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

What

Ports WebKit's regression test JSTests/stress/array-iterator-fast-entries-double-array-fixup-exit-ok.js (added by WebKit/WebKit@ae69ef2) into test/js/bun/jsc-stress/, and runs it with --useConcurrentJIT=false --validateGraphAtEachPhase=true.

Why

Bun builds whose WebKit pin was in the range cd821fecca0d (#32437, Jun 16) through f72c0151d39e (#32184, Jun 27) could abort on the JIT worker thread while DFG-compiling any hot function containing:

for (const [i, v] of someDoubleArray.entries()) { ... }

Native stack of the abort:

WTFCrashWithInfo
WTF::Vector<unsigned int, 64, CrashOnOverflow>::expandCapacity<FailureAction::Crash>
JSC::DFG::performVirtualRegisterAllocation(JSC::DFG::Graph&)
JSC::DFG::Plan::compileInThreadImpl()

Root cause (upstream WebKit/WebKit@3d1bebd): the fast path for ArrayIterator with kind entries emits GetByVal (which clobbers exit state) immediately followed by NewArray([index, value]) in the same bytecode origin, with no ExitOK in between, so the NewArray is exit-invalid. When the array has double storage, FixupPhase gives the GetByVal an unboxed Double result and must insert a ValueRep to re-box it for NewArray's edge. Fixup inserts such conversions at the most recent exit-OK node, which here is the GetByVal itself, so the ValueRep lands one slot above the node that defines its operand. The use-before-def graph then crashes virtual register allocation: the child's VirtualRegister is still the invalid sentinel, and toLocal() of it indexes the ScoreBoard's Vector<uint32_t, 64> at about 3.2e9, which trips CrashOnOverflow.

Upstream fixed this in WebKit/WebKit@ae69ef2 ("entries" ArrayIterator should emit ExitOK before NewArray, webkit.org/b/317327). That commit is in bun's current WebKit pin (d81bcc3d833c, picked up by #33133), so bun main is not affected today, and no tagged release was ever affected (1.3.14 predates the regression). Only canary/main builds between Jun 16 and Jun 29 were.

This fixture keeps the shape covered by bun's own CI so a future WebKit upgrade that drops or reintroduces the bug fails deterministically (graph validation aborts right after fixup) instead of as a probabilistic SIGABRT on a concurrent compiler thread.

Verification

  • bun bd test test/js/bun/jsc-stress/jsc-stress.test.ts -t array-iterator-fast-entries passes (debug build).
  • Same with USE_SYSTEM_BUN=1 (release).
  • The fixture reaches the intended shape: with reportDFGCompileTimes=1, inner is DFG-compiled, and the post-fixup graph shows the boxing conversion being required and correctly placed after its operand.
post-fixup DFG excerpt (block 5 of inner)
10: D@81  GetByVal(Check:KnownCell:D@80, Check:Int32:D@76, Check:KnownStorage:D@185, Double|MustGen|VarArgs, Double+OriginalCopyOnWriteArray+InBounds+AsIs+Read, bc#40, ExitValid)
11: D@82  ExitOK(MustGen, W:SideState, bc#40, ExitValid)
12: D@183 ValueRep(Check:DoubleRep:D@81<Double>, JS|PureInt, BytecodeDouble, bc#40, ExitValid)
13: D@83  NewArray(Check:Untyped:D@76, Check:Untyped:D@183, Array, vectorLengthHint = 2, ArrayWithContiguous, bc#40, ExitValid)

Without the upstream fix the ExitOK at index 11 does not exist and the ValueRep is inserted at the GetByVal's own index, above its operand, which --validateGraphAtEachPhase rejects with validation failed: block->isInPhis(child) || seenNodes.contains(child).

Ports WebKit's JSTests/stress/array-iterator-fast-entries-double-array-fixup-exit-ok.js
into the jsc-stress suite.

Iterating doubleArray.entries() through the DFG's fast array-iterator path
produced a use-before-def graph: the bytecode parser emitted GetByVal (which
clobbers exit state) directly followed by NewArray([index, value]) with no
ExitOK in between, so FixupPhase inserted the ValueRep that re-boxes the
double element one slot before the GetByVal that defines it. In release
builds the malformed graph reached virtual register allocation and aborted
the JIT worker thread:

  WTF::Vector<unsigned int, 64, CrashOnOverflow>::expandCapacity
  JSC::DFG::performVirtualRegisterAllocation

Introduced by WebKit/WebKit@3d1bebd7930d, which reached bun with the WebKit
bump in #32437, and fixed upstream by WebKit/WebKit@ae69ef2312c0, which is
in the current pin (picked up by #33133). The fixture runs with
useConcurrentJIT=false and validateGraphAtEachPhase=true so a future WebKit
bump that loses the fix fails deterministically at the fixup phase instead
of probabilistically on a concurrent compiler thread.
@github-actions github-actions Bot added the claude label Jul 2, 2026
@robobun

robobun commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 1:09 PM PT - Jul 2nd, 2026

@robobun, your commit 0dbac99 has 2 failures in Build #67998 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 33260

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

bun-33260 --bun

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: 44846241-540d-4c00-94f6-9309c4e7078d

📥 Commits

Reviewing files that changed from the base of the PR and between 1498d7b and fbea09e.

📒 Files selected for processing (2)
  • test/js/bun/jsc-stress/fixtures/array-iterator-fast-entries-double-array-fixup-exit-ok.js
  • test/js/bun/jsc-stress/jsc-stress.test.ts

Walkthrough

Adds a new Bun/JSC stress test fixture that reproduces an ArrayIterator entries() double-array-fixup scenario, disabling concurrent JIT and enabling graph validation, and registers the fixture in the existing jsc-stress test fixture list.

Changes

New stress fixture and registration

Layer / File(s) Summary
Add fixture and wire into test suite
test/js/bun/jsc-stress/fixtures/array-iterator-fast-entries-double-array-fixup-exit-ok.js, test/js/bun/jsc-stress/jsc-stress.test.ts
New fixture defines inner()/driver() functions iterating a double-array's .entries() under validateGraphAtEachPhase, and it is added to the jsFixtures array for execution.

Sequence Diagram(s)

Not applicable; the change is a test fixture addition with no interaction flow worth diagramming.

Estimated code review effort: 1 (trivial addition of a test fixture and its registration)

Suggested labels: test, javascript-jit

Suggested reviewers: N/A

Poem
A rabbit hops through JIT-lit fields,
A double array, its secret yields.
With graphs validated, phase by phase,
The iterator loops through entries' maze.
One new fixture, safely stowed—
Another stress test down the road! 🐇

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a JSC stress fixture for the ArrayIterator entries path.
Description check ✅ Passed It covers the change, rationale, and verification steps, though the headings differ slightly from the template.
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.

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.

LGTM — test-only port of an upstream WebKit JSC stress fixture, following the existing pattern in this directory.

Extended reasoning...

Overview

This PR adds a single JSC stress-test fixture (array-iterator-fast-entries-double-array-fixup-exit-ok.js, 31 lines) ported directly from WebKit's JSTests/stress/, and appends its filename to the jsFixtures array in test/js/bun/jsc-stress/jsc-stress.test.ts. No production code is touched.

Security risks

None. The change is entirely within the test tree, adds a self-contained JS fixture that only iterates an array in a hot loop, and is executed via the existing spawn harness with bunEnv. There is no network, filesystem, auth, or crypto surface.

Level of scrutiny

Low. This is a mechanical addition to an established fixture-list pattern: the //@ runDefault("--useConcurrentJIT=false", "--validateGraphAtEachPhase=true") directive is already handled by parseJSCFlags, testLoopCount is provided by the existing preload.js, and the test driver loop is identical to the ~60 other fixtures already in the list. The fixture is a near-verbatim upstream port with a clear provenance comment.

Other factors

The PR description thoroughly documents the root cause, the upstream fix commit, and verification (debug build pass, DFG graph excerpt confirming the intended shape is reached). The bug-hunting system found no issues. There are no outstanding reviewer comments and no prior reviews from me on this PR.

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

LGTM — straightforward port of an upstream JSC stress fixture into the existing harness.

Extended reasoning...

Overview

This PR adds a single JSC stress-test fixture (array-iterator-fast-entries-double-array-fixup-exit-ok.js) ported directly from WebKit's JSTests/stress/, and appends its filename to the jsFixtures array in test/js/bun/jsc-stress/jsc-stress.test.ts. No runtime, native, or production code is touched.

Security risks

None. The change is entirely test-only: a new fixture file executed in a spawned subprocess by the existing test runner, plus a one-line array entry. No untrusted input handling, no auth/crypto/permissions surface.

Level of scrutiny

Low. This follows the exact established pattern for the ~70 other fixtures in this directory: a // @bun marker, a //@ runDefault(...) directive that parseJSCFlags translates into BUN_JSC_useConcurrentJIT=false / BUN_JSC_validateGraphAtEachPhase=true, and a loop over the preload-defined testLoopCount global. The fixture body is a near-verbatim copy of the upstream WebKit regression test.

Other factors

I verified that preload.js defines testLoopCount and that the //@ runDefault(...) directive parses correctly with the existing regex (both flags are captured before the parser breaks on the following comment lines). The PR description documents that the test was verified to pass under both bun bd and USE_SYSTEM_BUN=1, and explains precisely why the fixture is deterministic (--validateGraphAtEachPhase fails right after fixup rather than probabilistically at register allocation). The bug-hunting system found no issues, and there are no outstanding reviewer comments.

@robobun

robobun commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

CI status across both runs (67993, 67998): the new fixture, jsc-stress.test.ts > array-iterator-fast-entries-double-array-fixup-exit-ok.js, passes on every lane that executed it. The remaining failures are in suites this test-only change does not touch:

  • test/napi/napi.test.ts (exit 1 on Windows x64-baseline in 67993, SIGABRT on macOS 26 aarch64 in 67998)
  • test/js/bun/http/serve-body-leak.test.ts (timeout, macOS 26 aarch64)
  • test/cli/hot/hot.test.ts (Windows x64-baseline, passed on retry)
  • the two darwin-14 jobs expired without running

One retrigger already spent on this, so leaving it as is. Ready for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant