[JSC] Add DFG MultiGetByVal and MultiPutByVal
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
JSC's JIT pipeline has three tiers: Baseline → DFG → FTL. DFG (Data Flow Graph) is a speculative JIT that compiles relatively quickly using a node-based IR; FTL sits above it with LLVM-backed IR and additional optimization passes including the ValueRep phase, which annotates each value's representation (tagged JSValue, unboxed int32, int52, double). MultiGetByVal/MultiPutByVal are "polymorphic merge" nodes: when a GetByVal site has observed multiple array shapes (e.g., Int32 JSArray, Float64Array, Contiguous JSArray), the JIT emits a branch tree that dispatches to a specialized fast path per observed type, avoiding the generic IC slow path on every call.
This commit ports MultiGetByVal and MultiPutByVal from FTL into the DFG tier. Int32Result and Int52Result representations are intentionally excluded — DFG lacks the ValueRep annotation phase that FTL uses to track unboxed integer representations — so only JSResult and DoubleResult are supported. The fixup phase falls a node back to plain GetByVal when a case demands an Int32/Int52 result.
Before: After:
DFG tier DFG tier
GetByVal (polymorphic site) MultiGetByVal (NEW)
└─► IC miss → slow path ├─► Int32 array fast path
├─► Double array fast path
├─► Contiguous fast path
├─► TypedArray fast paths
└─► OOB → undefined (sane chain)
(JSResult / DoubleResult only)
Significance
Array accesses against mixed observed types can now be optimized with inlined multi-shape dispatch at the DFG tier without waiting for FTL promotion, expanding the attack surface of type-specialized JIT code paths that are historically rich with bugs. The same multi-shape fast-path logic is now generated by a separate, less-tested code emitter (SpeculativeJIT) with its own OOB and speculation mechanics.
Audit directions
- Per-shape type check and fast-path branches. An incorrect or missing check for one array type could allow a misspeculation that reaches the wrong fast path, enabling type confusion.
- The "sane chain" OOB path. It returns
undefinedwithout a slow-path call by speculating the index is non-negative — any miscategorization here yields an OOB read with no trap. - The fixup phase logic that decides whether to convert a
MultiGetByValnode back to a plainGetByVal. If the condition is wrong, a DFG node with anInt32/Int52result (which DFG cannot correctly represent without ValueRep) could survive into code generation. - The result-type bifurcation itself. Where
JSResultandDoubleResultdiverge in the emitter, off-by-one tag handling or a missing unbox step is a classic JIT confusion source. Five new stress tests cover the main paths but they run with--useFTLJIT=0, meaning differential coverage between DFG and FTL paths is not yet verified.