Skip to content

AX: Reduce parent lookups in unignoredChildren pre-order traversal#64803

Merged
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
twilco:eng/AX-Reduce-parent-lookups-in-unignoredChildren-pre-order-traversal
May 13, 2026
Merged

AX: Reduce parent lookups in unignoredChildren pre-order traversal#64803
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
twilco:eng/AX-Reduce-parent-lookups-in-unignoredChildren-pre-order-traversal

Conversation

@twilco
Copy link
Copy Markdown
Contributor

@twilco twilco commented May 13, 2026

058338e

AX: Reduce parent lookups in unignoredChildren pre-order traversal
https://bugs.webkit.org/show_bug.cgi?id=314691
rdar://176932652

Reviewed by Dominic Mazzoni.

Samples taken during AX queries showed nextSiblingIncludingIgnored
as ~95% of time in stitchedUnignoredChildren -> unignoredChildren ->
nextInPreOrder. Each call went through parentObject(), a virtual call
whose cost varies by subclass (HashMap lookup on AXIsolatedObject; DOM
traversal + axObjectCache lookup on AccessibilityRenderObject /
AccessibilityNodeObject) but is always non-trivial. The traversal was
paying for that lookup twice per ascended level. Two adjustments cut
the per-hop work:

1. nextInPreOrder: replace the pre-loop nextSiblingIncludingIgnored()
   call + in-loop parentObject() ascent with a single loop that fetches
   parent once per level. In the non-cross-frame case, the sibling-search
   parent and ascent parent are the same value, so the ascent reuses it
   via WTF::move, eliminating the duplicate parentObject() call and the
   accompanying RefPtr ref()/deref() per ascended level.

2. unignoredChildren: for ignored or invalid descendants, inline the
   descent step (matching nextInPreOrder's Column / TableHeaderContainer
   role guard via shouldSetChildIndexInParent()) instead of falling back
   to nextInPreOrder(). The function already had its own sibling-or-
   ascend loop that caches parent + siblings across sibling hops, but the
   nextInPreOrder() fallback was invalidating that cache every time the
   traversal crossed an ignored descendant. With the fallback gone,
   cached parent/siblings now survive through ignored-descendant
   traversal, and the per-hop cost drops to descendant->indexInParent() + a vector index.

* Source/WebCore/accessibility/AXCoreObject.cpp:
(WebCore::AXCoreObject::unignoredChildren):
(WebCore::AXCoreObject::nextInPreOrder):

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

05fa6d2

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win ✅ 🛠 ios-apple
✅ 🧪 bindings ✅ 🛠 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
✅ 🛠 ios-safer-cpp ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
✅ 🛠 🧪 merge ✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2
✅ 🛠 tv ✅ 🛠 mac-safer-cpp
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@twilco twilco self-assigned this May 13, 2026
@twilco twilco added the Accessibility For bugs related to accessibility. label May 13, 2026
@twilco twilco force-pushed the eng/AX-Reduce-parent-lookups-in-unignoredChildren-pre-order-traversal branch from 7358b48 to 05fa6d2 Compare May 13, 2026 01:24
@twilco twilco added the merge-queue Applied to send a pull request to merge-queue label May 13, 2026
https://bugs.webkit.org/show_bug.cgi?id=314691
rdar://176932652

Reviewed by Dominic Mazzoni.

Samples taken during AX queries showed nextSiblingIncludingIgnored
as ~95% of time in stitchedUnignoredChildren -> unignoredChildren ->
nextInPreOrder. Each call went through parentObject(), a virtual call
whose cost varies by subclass (HashMap lookup on AXIsolatedObject; DOM
traversal + axObjectCache lookup on AccessibilityRenderObject /
AccessibilityNodeObject) but is always non-trivial. The traversal was
paying for that lookup twice per ascended level. Two adjustments cut
the per-hop work:

1. nextInPreOrder: replace the pre-loop nextSiblingIncludingIgnored()
   call + in-loop parentObject() ascent with a single loop that fetches
   parent once per level. In the non-cross-frame case, the sibling-search
   parent and ascent parent are the same value, so the ascent reuses it
   via WTF::move, eliminating the duplicate parentObject() call and the
   accompanying RefPtr ref()/deref() per ascended level.

2. unignoredChildren: for ignored or invalid descendants, inline the
   descent step (matching nextInPreOrder's Column / TableHeaderContainer
   role guard via shouldSetChildIndexInParent()) instead of falling back
   to nextInPreOrder(). The function already had its own sibling-or-
   ascend loop that caches parent + siblings across sibling hops, but the
   nextInPreOrder() fallback was invalidating that cache every time the
   traversal crossed an ignored descendant. With the fallback gone,
   cached parent/siblings now survive through ignored-descendant
   traversal, and the per-hop cost drops to descendant->indexInParent() + a vector index.

* Source/WebCore/accessibility/AXCoreObject.cpp:
(WebCore::AXCoreObject::unignoredChildren):
(WebCore::AXCoreObject::nextInPreOrder):

Canonical link: https://commits.webkit.org/313164@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/AX-Reduce-parent-lookups-in-unignoredChildren-pre-order-traversal branch from 05fa6d2 to 058338e Compare May 13, 2026 15:24
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 313164@main (058338e): https://commits.webkit.org/313164@main

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

@webkit-commit-queue webkit-commit-queue merged commit 058338e into WebKit:main May 13, 2026
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Accessibility For bugs related to accessibility.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants