[JSC] Add Array#concat DFG nodes
Component: JSC | 94e35cf
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
The DFG is JSC's speculative mid-tier compiler: it lowers bytecode into an IR of typed nodes, runs type-prediction-driven optimization phases (parsing, fixup, abstract interpretation, codegen), and emits machine code that OSR-exits back to the interpreter when its assumptions fail. Watchpoints are the invalidation signals backing those assumptions. This commit adds two new DFG/FTL intrinsic nodes, ArrayConcatArray and ArrayConcatAppendOne, enabling JIT compilation of Array.prototype.concat. The fixup phase uses type predictions to specialize the generic append node into the array-specific variant; fast paths are guarded by arrayIsConcatSpreadableWatchpointSet and original-structure checks (isJSArrayWithOriginalStructure). When complicated side effects turn up at runtime the operation returns nullptr and the JIT OSR-exits via ExoticObjectMode. concat is unusually hard to fast-path because the ES spec lets arbitrary objects opt in or out of spreading via [Symbol.isConcatSpreadable] — ruling that hook out is exactly what the watchpoint does. COW (copy-on-write) butterflies add the other half of the optimization: array-literal backing stores are shared and read-only until a write forces a copy, which lets concat of an empty array with a COW source return an array reusing the same butterfly.
Bytecode: array.concat(arg)
│
▼
DFGByteCodeParser
└─► emit ArrayConcatAppendOne(array, arg)
│
▼
DFGFixupPhase (type prediction check)
├─[arg predicted Array]──► ArrayConcatArray (COW-reuse fast path)
└─[arg unknown]──────────► ArrayConcatAppendOne (generic path)
│
▼
Runtime operation (DFGOperations.cpp)
├─[watchpoints valid, no isConcatSpreadable]──► fast path, may reuse COW butterfly
└─[side effects / exotic object detected]──────► return nullptr
│
▼
DFG/FTL checks nullptr
└─[nullptr]──► OSR exit (ExoticObjectMode) ──► Interpreter
Significance
A new heavily optimized path now runs through one of the most frequently called Array builtins, combining COW butterfly reuse, watchpoint-guarded speculation, and multi-phase type-driven node conversion. Each of those three is independently a historical source of JIT correctness bugs and type confusion; here they compose.
Audit directions
The regression test itself documents a crash that existed in tryConcatOneArgFast — a non-array object argument reached an uncheckedDowncast to JSArray, dereferencing a bogus butterfly pointer. That fix is fresh, and adjacent logic may still carry the same assumption, so the neighbouring downcast sites are the first stop.
COW butterfly reuse is the second. When concat of an empty array plus a COW source returns an array backed by the same butterfly, correctness depends on COW tracking staying sound across the abstract interpreter, fixup, and codegen phases. The COW test explicitly calls out that if the DFG abstract result structure set omits CopyOnWrite variants, downstream speculation is unsound — meaning there was at least one window where the abstract interpreter diverged from actual runtime state. Any other node whose result structure set is written by hand deserves the same check.
Third, the watchpoint invalidation path: if [Symbol.isConcatSpreadable] is installed between watchpoint registration and the JIT-compiled call, the ordering of invalidation versus in-flight execution matters. Fourth, the fixup phase converts ArrayConcatAppendOne to ArrayConcatArray based on type prediction — crafting inputs that change their type after the fixup decision, e.g. via prototype manipulation, is a classic JIT type confusion vector and applies to every prediction-driven node conversion in the fixup phase, not just this one. Fifth, the OSR exit via ExoticObjectMode on a nullptr return creates a two-path split at codegen time; verify both paths preserve object identity, array length, and index bounds.