[JSC] Add foundation of handling builtin iterators in fast-iteration-protocol
YarrJIT now compiles `{m,n}` with `m>0` — every regex with a non-zero minimum just left the safe interpreter for handwritten backtracking.
// Source/JavaScriptCore/runtime/VM.h
+ JSValue fastArrayValuesSentinel() const { return m_fastArrayValuesSentinel.get(); }
+ JSValue fastArrayKeysSentinel() const { return m_fastArrayKeysSentinel.get(); }
+ JSValue fastArrayEntriesSentinel() const { return m_fastArrayEntriesSentinel.get(); }
JSC's bytecode includes op_iterator_open and op_iterator_next, which the baseline JIT and DFG can fast-path when a built-in iterator (e.g., Array's @@iterator) is recognized. Previously, the fast path handled only a single 'FastArray' (values) mode and passed an empty JS value as the sentinel between the two opcodes — a slot the DFG used solely to detect that the fast path was active.
This commit introduces JSSentinel — a new VM-level heap object — to carry iterator kind (values/keys/entries) between op_iterator_open and op_iterator_next. The empty-value sentinel is replaced with typed JSSentinel singletons stored on the VM (one per kind), so DFG/FTL can emit specialized inline code for FastArrayKeys and FastArrayEntries in addition to values, yielding 14–37% speedups. TypedArrays share ArrayIteratorPrototype and are intentionally excluded; a future FastTypedArrayXXX extension will handle them.
Significance
This is a foundational architectural change: it decouples iterator kind from the iterator object itself, enabling DFG specialization of keys and entries without touching the JS heap object, and paves the way for fully eliminating JS-side ArrayIterator#next, MapIterator#next, and SetIterator#next builtins in favor of C++/DFG implementations.
Audit directions
- Cross-realm sentinel identity checks.
JSSentinelobjects are VM singletons checked by object identity. The guard filtering cross-realm iterators checksarrayIteratorStructure— if any path can smuggle a cross-realm iterator through before that check, DFG will emit JSArray-specific memory access against a foreign realm's object under potentially different structure assumptions. - Watchpoint invalidation window. DFG has already speculated on the sentinel kind when
ArrayIterator.prototype.nextorArray.prototype[Symbol.iterator]is replaced mid-execution. Any incomplete invalidation (e.g., only invalidating one kind while another is active) could leave stale JIT code running after prototype mutation. - TypedArray misclassification. Audit
iteratorOpenTryFastImpldirectly — a classification error would cause DFG to emit JSArray butterfly-based element loads on a TypedArray, accessing the wrong memory layout. - DFG boolean-to-number coercion in entries path.
dfg-boolean-to-number-known-boolean-use-via-iterator-fast-path.jstargetsKnownBooleanUsevia the entries fast path; incorrectUseKindspeculation here could lead to type confusion in JIT-generated arithmetic on iteration results. - Mid-iteration structural mutations. Verify the DFG-emitted inline index tracking rechecks array structure (holes, length shrinkage) correctly between iterations across all three kinds.