Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 5330149c555921d5eefddaa34d3c8a6a1fbd55ce
      
https://github.com/WebKit/WebKit/commit/5330149c555921d5eefddaa34d3c8a6a1fbd55ce
  Author: Sosuke Suzuki <[email protected]>
  Date:   2026-09-29 (Tue, 29 Sep 2026)

  Changed paths:
    A JSTests/microbenchmarks/destructuring-string.js
    A JSTests/microbenchmarks/for-of-string-break.js
    A JSTests/microbenchmarks/for-of-string-small.js
    A JSTests/stress/for-of-fast-string-and-iterator-with-known-structure.js
    A JSTests/stress/for-of-fast-string-and-other-iterables.js
    A JSTests/stress/for-of-fast-string-close-fresh-realm-assignment.js
    A JSTests/stress/for-of-fast-string-close-fresh-realm-destructuring.js
    A JSTests/stress/for-of-fast-string-close-fresh-realm-loops.js
    A JSTests/stress/for-of-fast-string-close-fresh-realm-replaced-methods.js
    A JSTests/stress/for-of-fast-string-code-points.js
    A JSTests/stress/for-of-fast-string-destructuring.js
    A JSTests/stress/for-of-fast-string-generator.js
    A JSTests/stress/for-of-fast-string-osr-late-close.js
    A JSTests/stress/for-of-fast-string-osr-long-loop.js
    A JSTests/stress/for-of-fast-string-wide-operands.js
    M Source/JavaScriptCore/bytecode/BytecodeList.rb
    M Source/JavaScriptCore/bytecode/IterationModeMetadata.h
    M Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
    M Source/JavaScriptCore/jit/BaselineJITRegisters.h
    M Source/JavaScriptCore/jit/JITCall.cpp
    M Source/JavaScriptCore/jit/JITOperations.cpp
    M Source/JavaScriptCore/jit/JITOperations.h
    M Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
    M Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
    M Source/JavaScriptCore/runtime/CommonSlowPaths.h
    M Source/JavaScriptCore/runtime/JSGlobalObject.h
    M Source/JavaScriptCore/runtime/JSStringIterator.h
    M Source/JavaScriptCore/runtime/VM.cpp
    M Source/JavaScriptCore/runtime/VM.h

  Log Message:
  -----------
  [JSC] Iterate Strings without allocating a `JSStringIterator`
https://bugs.webkit.org/show_bug.cgi?id=325452

Reviewed by Yusuke Suzuki.

321765@main stopped allocating a JSArrayIterator in FastArray mode by keeping
the state of the iteration in registers. FastString mode (for-of and
destructuring over a String) still allocates a JSStringIterator every time in
LLInt, Baseline and DFG, and it is unobservable for the same reason: the next
method was already looked up when the iterator was opened, and while
stringIteratorProtocolWatchpointSet is valid, "return" is guaranteed to be
absent from the prototype chain.

This patch does the same for FastString mode. iterator holds a sentinel of its
own, next holds the index as an Int32, and iterable holds the string as before.
op_iterator_next and op_iterator_close_check compare iterator with the sentinel
for Arrays first and then with the one for Strings. When it is the latter,
op_iterator_close_check looks at stringIteratorProtocolWatchpointSet, and
creates the JSStringIterator if it is no longer valid.

With JSC_useDFGJIT=false:

                                                 Baseline                  
Patched

for-of-string-small                           7.5573+-0.1228     ^      
6.6576+-0.1222        ^ definitely 1.1351x faster
for-of-string-break                           4.6593+-0.0620     ^      
4.2070+-0.1624        ^ definitely 1.1075x faster
destructuring-string                         25.8768+-0.2164     ^     
21.5336+-0.2443        ^ definitely 1.2017x faster
string-iterator-for-of-ascii                149.8134+-1.0006     ^    
140.7087+-1.9843        ^ definitely 1.0647x faster

With JSC_useFTLJIT=false:

                                                 Baseline                  
Patched

for-of-string-small                           2.2048+-0.0344     ^      
1.7072+-0.0611        ^ definitely 1.2914x faster
for-of-string-break                           1.7627+-0.0699     ^      
1.3706+-0.0314        ^ definitely 1.2860x faster
destructuring-string                          7.4364+-0.1370     ^      
5.9434+-0.1328        ^ definitely 1.2512x faster
string-iterator-for-of-ascii                 44.7161+-0.6120     ^     
37.0484+-0.3477        ^ definitely 1.2070x faster

Tests: JSTests/microbenchmarks/destructuring-string.js
       JSTests/microbenchmarks/for-of-string-break.js
       JSTests/microbenchmarks/for-of-string-small.js
       JSTests/stress/for-of-fast-string-and-iterator-with-known-structure.js
       JSTests/stress/for-of-fast-string-and-other-iterables.js
       JSTests/stress/for-of-fast-string-close-fresh-realm-assignment.js
       JSTests/stress/for-of-fast-string-close-fresh-realm-destructuring.js
       JSTests/stress/for-of-fast-string-close-fresh-realm-loops.js
       JSTests/stress/for-of-fast-string-close-fresh-realm-replaced-methods.js
       JSTests/stress/for-of-fast-string-code-points.js
       JSTests/stress/for-of-fast-string-destructuring.js
       JSTests/stress/for-of-fast-string-generator.js
       JSTests/stress/for-of-fast-string-osr-late-close.js
       JSTests/stress/for-of-fast-string-osr-long-loop.js
       JSTests/stress/for-of-fast-string-wide-operands.js

* JSTests/microbenchmarks/destructuring-string.js: Added.
(test):
* JSTests/microbenchmarks/for-of-string-break.js: Added.
(test):
* JSTests/microbenchmarks/for-of-string-small.js: Added.
(test):
* JSTests/stress/for-of-fast-string-and-iterator-with-known-structure.js: Added.
(shouldBe):
(second):
(collect):
(breakAtTwo):
(firstTwo):
* JSTests/stress/for-of-fast-string-and-other-iterables.js: Added.
(shouldBe):
(breakAt):
(firstTwo):
(Symbol.iterator):
(breakAtTwo):
(breakAtTwoAgain):
(shouldThrowTypeError):
* JSTests/stress/for-of-fast-string-close-fresh-realm-assignment.js: Added.
(shouldBe):
(installReturn.where.return):
(installReturn):
(destructureAssign):
(let.o.set a):
(destructureSetter):
(destructureThrow):
(destructureNested):
(const.noHook):
(run):
* JSTests/stress/for-of-fast-string-close-fresh-realm-destructuring.js: Added.
(shouldBe):
(installReturn.StringIteratorPrototype.return):
(installReturn):
(firstTwo):
(firstOnly):
(none):
(const.noHook):
(run):
* JSTests/stress/for-of-fast-string-close-fresh-realm-loops.js: Added.
(shouldBe):
(installReturn.where.return):
(installReturn):
(breakOut):
(returnOut):
(throwOut):
(continueOuter):
(finallyOut):
(runToEnd):
(nested):
(each):
(generatorReturn):
(const.noHook):
(run):
* JSTests/stress/for-of-fast-string-close-fresh-realm-replaced-methods.js: 
Added.
(shouldBe):
(installReturn.StringIteratorPrototype.return):
(installReturn):
(StringIteratorPrototype.next):
(nextReplacedMidLoop):
(String.prototype.Symbol.iterator):
(symbolIteratorReplacedMidLoop):
(breakAtTwo):
(const.noHook):
* JSTests/stress/for-of-fast-string-code-points.js: Added.
(shouldBe):
(breakAt):
(nested):
(reassigned):
(rope):
* JSTests/stress/for-of-fast-string-destructuring.js: Added.
(shouldBe):
(firstAndRest):
(third):
(none):
(swapped):
(parameter):
* JSTests/stress/for-of-fast-string-generator.js: Added.
(shouldBe):
(eachTwice):
(firstTwo):
(async eachAwaited):
* JSTests/stress/for-of-fast-string-osr-late-close.js: Added.
(shouldBe):
(find):
(swap):
(StringIteratorPrototype.return):
* JSTests/stress/for-of-fast-string-osr-long-loop.js: Added.
(shouldBe):
(makeLong):
(count):
(find):
(swap):
(noInline):
* JSTests/stress/for-of-fast-string-wide-operands.js: Added.
(shouldBe):
(installReturn.StringIteratorPrototype.return):
(const.noHook):
* Source/JavaScriptCore/bytecode/BytecodeList.rb:
* Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::handleIteratorOpen):
(JSC::DFG::ByteCodeParser::handleIteratorNext):
* 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/LowLevelInterpreter64.asm:
* Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:
(JSC::iteratorOpenTryFastImpl):
(JSC::iteratorNextTryFastImpl):
(JSC::iteratorNextFastStringImpl):
(JSC::JSC_DEFINE_COMMON_SLOW_PATH):
* Source/JavaScriptCore/runtime/CommonSlowPaths.h:
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::offsetOfStringIteratorProtocolWatchpointSet):
* Source/JavaScriptCore/runtime/JSStringIterator.h:
* Source/JavaScriptCore/runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::visitAggregateImpl):
* Source/JavaScriptCore/runtime/VM.h:
(JSC::VM::fastStringSentinel):
(JSC::VM::fastStringValuesSentinel): Deleted.

Canonical link: https://commits.webkit.org/322172@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to