DFG node for `String.fromCodePoint`
The DFG abstract interpreter still folded `[...set]` as side-effect-free after a slow path was added that runs a user-defined Symbol.iterator.
Source/JavaScriptCore/dfg/DFGOperations.cpp
JSC's tiered JIT (Baseline → DFG → FTL) recognises specific built-in functions at the bytecode parsing stage and emits purpose-built IR nodes. String.fromCodePoint is harder than String.fromCharCode because (1) it must throw RangeError for non-integer, negative, or >0x10FFFF inputs — even when the JIT has proven the argument is an Int32 — and (2) supplementary-plane code points require emitting a two-unit surrogate pair.
This commit adds a StringFromCodePoint DFG node and FromCodePointIntrinsic. For Int32 arguments in [0, 0xFF], the fast path is shared with StringFromCharCode via a unified compileStringFromCharCodeOrCodePoint. Larger code points, surrogate pairs, and RangeError cases fall back to operationStringFromCodePoint (Int32 slow path) or operationStringFromCodePointUntyped. The node keeps NodeMustGenerate set and models itself as write(SideState) to prevent the optimiser from treating it as side-effect-free.
Significance
The change delivers a measured ~5.2x speedup for Latin-1 code points and brings String.fromCodePoint into the JIT intrinsic tier. Every new DFG intrinsic must be wired through clobberize, doesGC, safeToExecute, prediction propagation, loop unrolling, and both 32-bit and 64-bit speculative JIT backends, making each of those phase interactions a potential miscompilation surface.
Audit directions
- Shared fast path with
StringFromCharCode. The Latin-1 branch inheritsfromCharCodeassumptions — any divergence in preconditions (signed vs unsigned Int32 treatment, negative values reaching the fast path) could produce incorrect output instead of aRangeError. write(SideState)andNodeMustGenerateretention. These are the only guards preventing the optimiser from reordering or eliminating theRangeErrorthrow — verify all code paths through fixup that assignInt32Usestill retainNodeMustGenerateand cannot be stripped by later phases.- Double-to-uint32 conversion in
operationStringFromCodePointUntyped. Usesstatic_cast<uint32_t>(codePointAsDouble)and then checkscodePoint != codePointAsDouble— worth scrutinising for negative zero, very large doubles, NaN truncation behaviour. - Surrogate-pair boundary at 0x10000 inside the untyped operation — classic fuzz target for off-by-one in the high/low surrogate calculation or buffer allocation.