Skip to content

[JSC] Add Map / Set fast iteration#63622

Merged
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
Constellation:eng/JSC-Add-Map-Set-fast-iteration
Apr 27, 2026
Merged

[JSC] Add Map / Set fast iteration#63622
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
Constellation:eng/JSC-Add-Map-Set-fast-iteration

Conversation

@Constellation
Copy link
Copy Markdown
Member

@Constellation Constellation commented Apr 26, 2026

4337048

[JSC] Add Map / Set fast iteration
https://bugs.webkit.org/show_bug.cgi?id=313340
rdar://175613242

Reviewed by Yijia Huang.

Previously our iterator_open / iterator_next supports JSArray. This
patch extends this fast iteration protocol to JSMap and JSSet.

1. LLInt / Baseline JIT should just simply add JSMap and JSMapIterator
   / JSSet and JSSetIterator iteration code. We extend IterationMode to
   have FastMap and FastSet. We also make constructArrayPair always
   using Contiguous (or Slow ArrayStorage when have-a-bad-time happens)
   to avoid frequent speculation failures when we inline them in DFG / FTL.
2. In DFG ByteCodeParser, we support JSMap / JSSet in iterator_open /
   iterator_next DFG nodes emission. One of the most subtle thing is OSR
   exit: MapIteratorNext changes the iterator, so after that, we cannot
   do OSR exit except for throwing an error, otherwise, OSR exit will
   advance the iterator again. We carefully emit DFG nodes which never
   does normal OSR exits, so this is fine.

                                         ToT                     Patched

    for-of-map-entries-small        7.3828+-0.1328     ^      6.4153+-0.1580        ^ definitely 1.1508x faster
    set-for-of                      1.3589+-0.0724     ^      0.6633+-0.0403        ^ definitely 2.0486x faster
    for-of-set-values               2.4183+-0.0569     ^      1.7421+-0.1980        ^ definitely 1.3881x faster
    for-of-map-entries              6.9321+-0.1456     ^      5.7206+-0.1448        ^ definitely 1.2118x faster
    map-for-of                      1.8342+-0.0780     ^      1.1539+-0.0725        ^ definitely 1.5896x faster
    for-of-set-values-small         2.5314+-0.0253     ^      1.9055+-0.0841        ^ definitely 1.3285x faster

Tests: JSTests/microbenchmarks/for-of-map-entries-small.js
       JSTests/microbenchmarks/for-of-map-entries.js
       JSTests/microbenchmarks/for-of-set-values-small.js
       JSTests/microbenchmarks/for-of-set-values.js
       JSTests/stress/iterator-dfg-fast-path-bad-time.js
       JSTests/stress/iterator-dfg-fast-path-mixed-modes.js
       JSTests/stress/iterator-dfg-fast-path-no-generic.js

* JSTests/microbenchmarks/for-of-map-entries-small.js: Added.
(test):
* JSTests/microbenchmarks/for-of-map-entries.js: Added.
(test):
* JSTests/microbenchmarks/for-of-set-values-small.js: Added.
* JSTests/microbenchmarks/for-of-set-values.js: Added.
* JSTests/stress/iterator-dfg-fast-path-bad-time.js: Added.
(shouldBe):
(sumMapEntries):
(sumSetValues):
(set add):
(set Object):
(set get for):
* JSTests/stress/iterator-dfg-fast-path-mixed-modes.js: Added.
(shouldBe):
(sumIterable):
(makeGeneric):
* JSTests/stress/iterator-dfg-fast-path-no-generic.js: Added.
(shouldBe):
(sumAny):
(runArrayMap):
(runArraySet.sumArrOrSet):
(runArraySet):
(runAllFastNoGeneric):
* Source/JavaScriptCore/builtins/MapIteratorPrototype.js:
(next):
* Source/JavaScriptCore/builtins/SetIteratorPrototype.js:
(next):
* Source/JavaScriptCore/bytecode/IterationModeMetadata.h:
* Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::handleIteratorOpen):
(JSC::DFG::ByteCodeParser::handleIteratorNext):
* Source/JavaScriptCore/dfg/DFGMayExit.cpp:
* Source/JavaScriptCore/jit/JITOperations.cpp:
(JSC::JSC_DEFINE_JIT_OPERATION):
* Source/JavaScriptCore/jit/JITOperations.h:
* Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:
(JSC::iteratorOpenTryFastImpl):
(JSC::iteratorNextTryFastImpl):
* Source/JavaScriptCore/runtime/IteratorOperations.cpp:
(JSC::getIterationMode):
* Source/JavaScriptCore/runtime/JSArray.cpp:
(JSC::constructArrayPair):
* Source/JavaScriptCore/runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildrenImpl):
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
* Source/JavaScriptCore/runtime/MapPrototype.cpp:
(JSC::MapPrototype::finishCreation):
* Source/JavaScriptCore/runtime/MapPrototype.h:
* Source/JavaScriptCore/runtime/SetPrototype.cpp:
(JSC::SetPrototype::finishCreation):
* Source/JavaScriptCore/runtime/SetPrototype.h:

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

a4269d5

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win ⏳ 🛠 ios-apple
✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ✅ 🧪 win-tests ⏳ 🛠 mac-apple
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe ⏳ 🛠 vision-apple
✅ 🧪 ios-wk2-wpt ✅ 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
✅ 🛠 🧪 jsc ✅ 🧪 api-ios ✅ 🧪 mac-wk1 ✅ 🛠 gtk
✅ 🛠 🧪 jsc-debug-arm64 ✅ 🛠 ios-safer-cpp ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🛠 🧪 unsafe-merge ✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2 ✅ 🛠 jsc-armv7
✅ 🛠 tv ✅ 🛠 mac-safer-cpp ✅ 🧪 jsc-armv7-tests
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@Constellation Constellation self-assigned this Apr 26, 2026
@Constellation Constellation requested a review from a team as a code owner April 26, 2026 07:58
@Constellation Constellation added the JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. label Apr 26, 2026
@Constellation Constellation force-pushed the eng/JSC-Add-Map-Set-fast-iteration branch from 4e91010 to 8a9874d Compare April 26, 2026 07:58
@Constellation Constellation force-pushed the eng/JSC-Add-Map-Set-fast-iteration branch from 8a9874d to 74bcc28 Compare April 26, 2026 08:08
@Constellation Constellation force-pushed the eng/JSC-Add-Map-Set-fast-iteration branch from 74bcc28 to a4269d5 Compare April 26, 2026 10:54
@Constellation Constellation added the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Apr 27, 2026
https://bugs.webkit.org/show_bug.cgi?id=313340
rdar://175613242

Reviewed by Yijia Huang.

Previously our iterator_open / iterator_next supports JSArray. This
patch extends this fast iteration protocol to JSMap and JSSet.

1. LLInt / Baseline JIT should just simply add JSMap and JSMapIterator
   / JSSet and JSSetIterator iteration code. We extend IterationMode to
   have FastMap and FastSet. We also make constructArrayPair always
   using Contiguous (or Slow ArrayStorage when have-a-bad-time happens)
   to avoid frequent speculation failures when we inline them in DFG / FTL.
2. In DFG ByteCodeParser, we support JSMap / JSSet in iterator_open /
   iterator_next DFG nodes emission. One of the most subtle thing is OSR
   exit: MapIteratorNext changes the iterator, so after that, we cannot
   do OSR exit except for throwing an error, otherwise, OSR exit will
   advance the iterator again. We carefully emit DFG nodes which never
   does normal OSR exits, so this is fine.

                                         ToT                     Patched

    for-of-map-entries-small        7.3828+-0.1328     ^      6.4153+-0.1580        ^ definitely 1.1508x faster
    set-for-of                      1.3589+-0.0724     ^      0.6633+-0.0403        ^ definitely 2.0486x faster
    for-of-set-values               2.4183+-0.0569     ^      1.7421+-0.1980        ^ definitely 1.3881x faster
    for-of-map-entries              6.9321+-0.1456     ^      5.7206+-0.1448        ^ definitely 1.2118x faster
    map-for-of                      1.8342+-0.0780     ^      1.1539+-0.0725        ^ definitely 1.5896x faster
    for-of-set-values-small         2.5314+-0.0253     ^      1.9055+-0.0841        ^ definitely 1.3285x faster

Tests: JSTests/microbenchmarks/for-of-map-entries-small.js
       JSTests/microbenchmarks/for-of-map-entries.js
       JSTests/microbenchmarks/for-of-set-values-small.js
       JSTests/microbenchmarks/for-of-set-values.js
       JSTests/stress/iterator-dfg-fast-path-bad-time.js
       JSTests/stress/iterator-dfg-fast-path-mixed-modes.js
       JSTests/stress/iterator-dfg-fast-path-no-generic.js

* JSTests/microbenchmarks/for-of-map-entries-small.js: Added.
(test):
* JSTests/microbenchmarks/for-of-map-entries.js: Added.
(test):
* JSTests/microbenchmarks/for-of-set-values-small.js: Added.
* JSTests/microbenchmarks/for-of-set-values.js: Added.
* JSTests/stress/iterator-dfg-fast-path-bad-time.js: Added.
(shouldBe):
(sumMapEntries):
(sumSetValues):
(set add):
(set Object):
(set get for):
* JSTests/stress/iterator-dfg-fast-path-mixed-modes.js: Added.
(shouldBe):
(sumIterable):
(makeGeneric):
* JSTests/stress/iterator-dfg-fast-path-no-generic.js: Added.
(shouldBe):
(sumAny):
(runArrayMap):
(runArraySet.sumArrOrSet):
(runArraySet):
(runAllFastNoGeneric):
* Source/JavaScriptCore/builtins/MapIteratorPrototype.js:
(next):
* Source/JavaScriptCore/builtins/SetIteratorPrototype.js:
(next):
* Source/JavaScriptCore/bytecode/IterationModeMetadata.h:
* Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::handleIteratorOpen):
(JSC::DFG::ByteCodeParser::handleIteratorNext):
* Source/JavaScriptCore/dfg/DFGMayExit.cpp:
* Source/JavaScriptCore/jit/JITOperations.cpp:
(JSC::JSC_DEFINE_JIT_OPERATION):
* Source/JavaScriptCore/jit/JITOperations.h:
* Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:
(JSC::iteratorOpenTryFastImpl):
(JSC::iteratorNextTryFastImpl):
* Source/JavaScriptCore/runtime/IteratorOperations.cpp:
(JSC::getIterationMode):
* Source/JavaScriptCore/runtime/JSArray.cpp:
(JSC::constructArrayPair):
* Source/JavaScriptCore/runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildrenImpl):
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
* Source/JavaScriptCore/runtime/MapPrototype.cpp:
(JSC::MapPrototype::finishCreation):
* Source/JavaScriptCore/runtime/MapPrototype.h:
* Source/JavaScriptCore/runtime/SetPrototype.cpp:
(JSC::SetPrototype::finishCreation):
* Source/JavaScriptCore/runtime/SetPrototype.h:

Canonical link: https://commits.webkit.org/312127@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/JSC-Add-Map-Set-fast-iteration branch from a4269d5 to 4337048 Compare April 27, 2026 19:57
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 312127@main (4337048): https://commits.webkit.org/312127@main

Reviewed commits have been landed. Closing PR #63622 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit 4337048 into WebKit:main Apr 27, 2026
@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants