← All issues

[JSC] Add Array#concat DFG nodes

94e35cf

Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

+ case ArrayConcatIntrinsic: {
+ if (argumentCountIncludingThis != 2)
+ return CallOptimizationResult::DidNothing;
+
+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, ExoticObjectMode))
+ return CallOptimizationResult::DidNothing;
+
+ ArrayMode arrayMode = getArrayMode(Array::Read);
+ if (!arrayMode.isJSArray())
+ return CallOptimizationResult::DidNothing;
+
+ if (!arrayMode.isJSArrayWithOriginalStructure())
+ return CallOptimizationResult::DidNothing;

Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

+ case ArrayConcatArray:
+ case ArrayConcatAppendOne:
+ setTypeForNode(node, SpecArray);
+ break;

JSC's DFG (Data Flow Graph) JIT is a speculative mid-tier compiler that lowers bytecode to an IR of typed nodes, applies type-prediction-driven optimizations in phases, and emits speculative machine code that can OSR-exit when assumptions fail. COW (Copy-on-Write) butterfly arrays are a storage optimization for array literals: the backing store is shared and marked read-only until a write triggers a copy. Array.prototype.concat is particularly complex because the spec allows arbitrary objects to opt in or out of spreading via [Symbol.isConcatSpreadable], making any fast path contingent on ruling out that hook.

This commit adds two new DFG/FTL intrinsic IR 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 watchpoints on arrayIsConcatSpreadableWatchpointSet and original-structure checks (isJSArrayWithOriginalStructure); when complicated side effects are detected at runtime, the operation returns nullptr and the JIT OSR-exits via ExoticObjectMode. The runtime test that motivated the patch documents an existing crash in tryConcatOneArgFast where a non-array object reached an uncheckedDowncast to JSArray and dereferenced a bogus butterfly pointer.

The fixup phase converts ArrayConcatAppendOne to ArrayConcatArray based on type prediction; crafting inputs whose type changes after the fixup decision is the canonical JIT type-confusion lever. Combined with COW butterfly reuse and a fresh OSR-exit boundary, this is one of the most fertile correctness surfaces JSC has added this year.

🔒

New JIT fast paths for a complex builtin — edge cases in type specialization and COW handling are worth close inspection.

Subscribe to read more