[JSC] New DFG node for StringIteratorPrototype.next
JSC's DFG JIT can replace known host-function calls with "intrinsic" nodes that expand inline to optimized machine code. StringIteratorPrototype.next() was previously a JS builtin inlined at the call site; this commit moves it to a C++ host function tagged JSStringIteratorNextIntrinsic so DFGByteCodeParser can recognize the callsite and emit a custom node graph.
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
The DFG expands the call into straight-line nodes: a CheckStructure guard, two GetInternalField reads, a new StringIteratorNextWithUndefined node producing a (char|undefined, nextIndex) tuple, NewObject/PutByOffset for the result object, and finally a PutInternalField to advance the index — emitted after all OSR-exit-capable nodes so a deopt cannot replay next() with an already-advanced index. The path is 64-bit only. StringIteratorNextWithUndefined is a sibling of the existing StringIteratorNext (used in for-of), differing only in returning undefined instead of an empty-string sentinel at exhaustion, preserving SpecString typing in the for-of path.
Significance
Manual iterator.next() calls — prevalent in babel-transpiled code — now compile to a tight JIT fast path instead of an interpreted builtin, around 1.7x faster (105ms to 61ms in the benchmark). The change also introduces the first DFG tuple node with a boxed JSValue element, infrastructure future intrinsics will reuse.
Audit directions
The index is advanced after all exit-capable nodes, but any future patch inserting a new OSR-exiting node after the index write silently breaks this invariant — audit PutInternalField ordering relative to any speculating node in the expanded sequence. StringIteratorNextWithUndefined and StringIteratorNext share codegen but produce different done-values; a type-speculation error conflating them could smuggle undefined into a SpecString-typed for-of slot, a type confusion downstream. The new jsValueTupleResultWithoutUsingChildren() use-chain bookkeeping, if wrong, could let GC treat a live JSValue slot as dead. Sinking both the iterator and the result object in one sequence is a new combination worth checking against alias analysis, and the 64-bit-only split means the intrinsic path is never exercised on 32-bit.