Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 35637c64339145f2920db0b6aee2dd8717109e63
https://github.com/WebKit/WebKit/commit/35637c64339145f2920db0b6aee2dd8717109e63
Author: Sosuke Suzuki <[email protected]>
Date: 2026-09-23 (Wed, 23 Sep 2026)
Changed paths:
A JSTests/stress/for-of-fast-array-aliasing-assignments.js
A JSTests/stress/for-of-fast-array-aliasing-eval-and-with.js
A JSTests/stress/for-of-fast-array-aliasing-parameters.js
A JSTests/stress/for-of-fast-array-close-destructuring.js
A JSTests/stress/for-of-fast-array-close-exits.js
A JSTests/stress/for-of-fast-array-close-fresh-realm-destructuring.js
A JSTests/stress/for-of-fast-array-close-fresh-realm-loops.js
A JSTests/stress/for-of-fast-array-close-nested.js
A JSTests/stress/for-of-fast-array-close-throw-and-completion.js
A JSTests/stress/for-of-fast-array-generator-finally-and-async.js
A JSTests/stress/for-of-fast-array-generator-nested.js
A JSTests/stress/for-of-fast-array-generator.js
A JSTests/stress/for-of-fast-array-mutation.js
A JSTests/stress/for-of-fast-array-osr-late-close.js
A JSTests/stress/for-of-fast-array-osr-long-loop.js
A JSTests/stress/for-of-fast-array-realms.js
M Source/JavaScriptCore/bytecode/BytecodeList.rb
M Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp
M Source/JavaScriptCore/bytecode/CodeBlock.cpp
M Source/JavaScriptCore/bytecode/Opcode.h
M Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h
M Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
M Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
M Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
M Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
M Source/JavaScriptCore/jit/JIT.cpp
M Source/JavaScriptCore/jit/JIT.h
M Source/JavaScriptCore/jit/JITCall.cpp
M Source/JavaScriptCore/jit/JITOperations.cpp
M Source/JavaScriptCore/jit/JITOperations.h
M Source/JavaScriptCore/llint/LowLevelInterpreter.asm
M Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
M Source/JavaScriptCore/lol/LOLJIT.cpp
M Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
M Source/JavaScriptCore/runtime/CommonSlowPaths.h
M Source/JavaScriptCore/runtime/IteratorOperations.h
M Source/JavaScriptCore/runtime/JSArrayIterator.h
M Source/JavaScriptCore/runtime/JSArrayIteratorInlines.h
M Source/JavaScriptCore/runtime/JSGlobalObject.h
M Source/JavaScriptCore/runtime/VM.cpp
M Source/JavaScriptCore/runtime/VM.h
Log Message:
-----------
[JSC] Iterate Arrays without allocating a `JSArrayIterator`
https://bugs.webkit.org/show_bug.cgi?id=324224
Reviewed by Yusuke Suzuki.
Currently, when op_iterator_open is in FastArray mode (for-of and destructuring
over an Array, which are very common), it allocates a JSArrayIterator. FTL
sinks it, but LLInt, Baseline and DFG allocate it every time, even though this
JSArrayIterator is unobservable: the next method was already looked up when the
iterator was opened, and while arrayIteratorProtocolWatchpointSet is valid,
"return" is guaranteed to be absent from the prototype chain.
This patch removes this allocation.
In the current implementation, the JSArrayIterator is used as the place to keep
the state of the iteration (the array and the index). This patch keeps the
state in registers instead, by changing what the operands of op_iterator_open
and op_iterator_next mean in FastArray mode:
- iterator holds a new sentinel instead of the JSArrayIterator, which is no
longer allocated.
- next holds the index as an Int32 instead of the sentinel it holds today (-1
once the iteration is done).
- iterable holds the array as before.
op_iterator_open stores these values to the operands. op_iterator_next looks at
next and iterator to tell whether it is in FastArray mode, reads the length and
the element from the array in iterable, and increments next.
Once the state is in registers, the JSArrayIterator can only be needed when the
iterator is closed (to call the return method). So a new opcode,
op_iterator_close_check, is emitted right before the bytecodes that close the
iterator. When iterator is the sentinel, it skips them if the watchpoint set is
still valid, and otherwise creates the JSArrayIterator and then proceeds to
them. The opcode has a metadata field, hasSeenFastArray, and DFG only emits
Check(ObjectUse) for it when it has not seen the sentinel.
Tests: JSTests/stress/for-of-fast-array-aliasing.js
JSTests/stress/for-of-fast-array-close-fresh-realm.js
JSTests/stress/for-of-fast-array-close.js
JSTests/stress/for-of-fast-array-generator.js
JSTests/stress/for-of-fast-array-mutation.js
JSTests/stress/for-of-fast-array-osr.js
JSTests/stress/for-of-fast-array-realms.js
* JSTests/stress/for-of-fast-array-aliasing.js: Added.
(shouldBe):
(sloppySimple):
(sloppySimpleLoop):
(sloppyPatternDefault):
(strictSimple):
(viaEval):
(viaEvalLoop):
(viaWith):
(viaClosure.set c):
(selfAssign):
(selfAssignLoop):
(nestedSame):
(catchParameter):
(viaGlobal):
(arrowWithRest):
(viaClosure.set return):
* JSTests/stress/for-of-fast-array-close-fresh-realm.js: Added.
(shouldBe):
(installReturn.where.return):
(installReturn):
(breakOut):
(returnOut):
(throwOut):
(continueOuter):
(breakOuter):
(finallyOut):
(runToEnd):
(nested):
(destructureDefault):
(destructureDefault3):
(destructureThrow):
(destructureNested):
(destructureAssign):
(let.o.set a):
(destructureSetter):
(ArrayIteratorPrototype.next):
(nextReplacedMidLoop):
(const.noHook):
(run):
(closedAt):
* JSTests/stress/for-of-fast-array-close.js: Added.
(shouldBe):
(installReturn.where.return):
(removeReturn):
(breakOut):
(returnOut):
(throwOut):
(continueOuter):
(breakOuter):
(finallyOut):
(runToEnd):
(nested):
(destructure2):
(destructureDefault):
(destructureEmpty):
(destructureRest):
(const.noHook):
(ArrayIteratorPrototype.return):
(removeReturn.patchedNextMidLoop.ArrayIteratorPrototype.next):
(removeReturn.patchedNextMidLoop):
* JSTests/stress/for-of-fast-array-generator.js: Added.
(shouldBe):
(eachWithFinally):
(nestedLoops):
(destructureAcrossYield):
(async eachAsync):
(drain):
(async suspendedAsync):
(ArrayIteratorPrototype.return):
* JSTests/stress/for-of-fast-array-mutation.js: Added.
(shouldBe):
(show):
(viaForOf):
(viaIterator):
(viaDestructuring):
(step):
(viaDestructuringByHand):
(sumWithHoles):
(throwingGetter):
* JSTests/stress/for-of-fast-array-osr.js: Added.
(shouldBe):
(makeLong):
(sumLong):
(joinLong):
(growWhileLooping):
(findLong):
(noInline):
(swap):
(first3):
(ArrayIteratorPrototype.return):
* JSTests/stress/for-of-fast-array-realms.js: Added.
(shouldBe):
(firstTwo):
(pair):
(other.eval.Object.prototype.return):
(Array.prototype.Symbol.iterator):
(Object.prototype.return):
* Source/JavaScriptCore/bytecode/BytecodeList.rb:
* Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp:
(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):
* Source/JavaScriptCore/bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* Source/JavaScriptCore/bytecode/Opcode.h:
(JSC::isBranch):
* Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h:
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::GenericLabel<JSGeneratorTraits>::setLocation):
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::emitIteratorNext):
(JSC::BytecodeGenerator::emitIteratorClose):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h:
* Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:
(JSC::ArrayPatternNode::bindValue const):
* Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::handleIteratorOpen):
(JSC::DFG::ByteCodeParser::handleIteratorNext):
* Source/JavaScriptCore/jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* Source/JavaScriptCore/jit/JIT.h:
* Source/JavaScriptCore/jit/JITCall.cpp:
(JSC::JIT::emit_op_iterator_next):
(JSC::JIT::emit_op_iterator_close_check):
* Source/JavaScriptCore/jit/JITOperations.cpp:
(JSC::JSC_DEFINE_JIT_OPERATION):
* Source/JavaScriptCore/jit/JITOperations.h:
* Source/JavaScriptCore/llint/LowLevelInterpreter.asm:
* Source/JavaScriptCore/llint/LowLevelInterpreter64.asm:
* Source/JavaScriptCore/lol/LOLJIT.cpp:
(JSC::LOL::LOLJIT::privateCompileMainPass):
* Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:
(JSC::iteratorOpenTryFastImpl):
(JSC::JSC_DEFINE_COMMON_SLOW_PATH):
* Source/JavaScriptCore/runtime/CommonSlowPaths.h:
* Source/JavaScriptCore/runtime/IteratorOperations.h:
(JSC::iteratorNextFastArray):
* Source/JavaScriptCore/runtime/JSArrayIterator.h:
* Source/JavaScriptCore/runtime/JSArrayIteratorInlines.h:
(JSC::JSArrayIterator::nextWithAdvance):
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::offsetOfArrayIteratorProtocolWatchpointSet):
* Source/JavaScriptCore/runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::visitAggregateImpl):
* Source/JavaScriptCore/runtime/VM.h:
(JSC::VM::fastArraySentinel):
Canonical link: https://commits.webkit.org/321765@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications