[JSC] New DFG node for StringIteratorPrototype.next
93518ed
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
+ case JSStringIteratorNextIntrinsic: {
+ if (!is64Bit())
+ return CallOptimizationResult::DidNothing;
+
+ Node* iterator = get(virtualRegisterForArgumentIncludingThis(0, registerOffset));
+ addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(globalObject->stringIteratorStructure())), iterator);
+
+ Node* position = addToGraph(GetInternalField, OpInfo(static_cast<uint32_t>(JSStringIterator::Field::Index)), OpInfo(SpecInt32Only), iterator);
+ Node* string = addToGraph(GetInternalField, OpInfo(static_cast<uint32_t>(JSStringIterator::Field::IteratedString)), OpInfo(SpecString), iterator);
+
+ Node* tuple = addToGraph(StringIteratorNextWithUndefined, Edge(string), Edge(position));
+ Node* value = addToGraph(ExtractFromTuple, OpInfo(0), tuple);
+ value->setResult(NodeResultJS);
+ Node* nextPosition = addToGraph(ExtractFromTuple, OpInfo(1), tuple);
+ nextPosition->setResult(NodeResultInt32);
+ ...
+ // Advance the iterator only after all nodes that can OSR exit
+ addToGraph(PutInternalField, OpInfo(static_cast<uint32_t>(JSStringIterator::Field::Index)), iterator, nextPosition);
+ setResult(resultObject);
+ return CallOptimizationResult::Inlined;
+ }
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
Aaa Aaaaa Aa Aaaaaaaa Aaaaa Aaa Aaaaaaaaaaaa Aaaaaa Aaa Aaa Aaaaaa Aaaaa Aaaaaaaaa a Aaa Aaaaaaaaaaa Aaaa Aaaaa Aaa Aaaaa Aaaaa Aaaaaaaa Aaaaaa Aaaa Aaaaaaaaa a Aaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaa Aa Aaa Aaaaaaaaaaa Aaaa Aa Aaa Aaaaaaaa Aaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaa Aaaaaaa Aaaaaaaaa Aaaaaaaaaaaa a Aaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaa Aaaa Aaaaa Aaaaaaa Aaaaaaaaaaa Aaaa a Aaaaaaaaaaaaaaaaaa Aaaaaa Aaaaa a Aaaa Aaaaaaaaa Aaaaaaaaaaa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaaaa Aa Aaaaaa Aaaaa Aaa Aa Aaaaa a Aaaa Aaaaaaaaa Aaaa Aa Aaaaa Aaaaaaa Aaaa Aaa Aaaaaaaa Aaa Aaa Aaaaaa Aaaaaa Aa Aaa Aaaaaaaa Aa a Aaa Aaaaaaaaaaa Aaaaa Aaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaa Aaa Aaa Aaaaaaaaaaa Aaaaa Aaaaa Aaa Aaaaaaaaa Aaaa Aa Aaaaa Aaaaaaaaa Aa Aaaaaaa
🔒New JIT-expanded intrinsic with OSR exit ordering constraints and novel tuple node infrastructure — several audit directions included.
Subscribe to read more