Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: c7a6997ebbb97fe9be83987597e69c3d25324fba
https://github.com/WebKit/WebKit/commit/c7a6997ebbb97fe9be83987597e69c3d25324fba
Author: Tyler Wilcock <[email protected]>
Date: 2026-05-31 (Sun, 31 May 2026)
Changed paths:
M Source/WebCore/accessibility/AXObjectCache.cpp
M Source/WebCore/accessibility/AXObjectCache.h
M Source/WebCore/accessibility/AXObjectCacheInlines.h
M Source/WebCore/accessibility/AXUtilities.cpp
M Source/WebCore/accessibility/AXUtilities.h
M Source/WebCore/accessibility/AccessibilityScrollView.cpp
M Source/WebCore/accessibility/AccessibilityScrollView.h
Log Message:
-----------
AX: Reduce per-call allocations and recomputation in the accessibility
isIgnored() hot path
https://bugs.webkit.org/show_bug.cgi?id=315867
rdar://178267741
Reviewed by Dominic Mazzoni.
This patch features a few optimizations based on a sample taken from a
page that exercised isIgnored() a lot:
- ARIA role checks (AXListHelpers::isAccessibilityList, AXTableHelpers::
isTableCellElement -> hasCellARIARole) allocated a lowercased copy of the role
attribute on every comparison, via
SpaceSplitString::spaceSplitStringContainsValue()
with ShouldFoldCase::Yes -- and hasAnyRole() did so once per candidate role,
so a
single isTableCellElement() check could allocate four times. hasAnyRole() also
heap-allocated a Vector for its candidate list on every call.
- AccessibilityScrollView::isRoot() recomputed a downcast plus a virtual
document()
comparison on every call, even though the answer is invariant for the object's
lifetime. It is called from many hot paths (computeIsIgnored, parentObject,
isARIAHidden, isWithinHiddenWebArea, elementRect, ...).
- AXObjectCache::getOrCreate(Widget&) was out-of-line, so even cache hits (the
common
case from parentObject()/containingWebArea()) paid a cross-function call
before
reaching the already-inline get().
This patch addresses each with no change in observable behavior:
- hasRole()/hasAnyRole() now lowercase the role value once via
AtomString::convertToASCIILowercase() -- which returns *this without
allocating
when the string is already lowercase, the common case for ARIA roles -- and
match
with ShouldFoldCase::No. This is equivalent to the previous
ShouldFoldCase::Yes
path (which folded the haystack internally) since all callers pass lowercase
values. hasAnyRole() takes a std::initializer_list<StringView> instead of a
Vector,
removing the per-call backing-store allocation. SpaceSplitString is left
untouched.
- AccessibilityScrollView::isRoot() is memoized in a std::optional<bool>. The
value
is invariant for the object's lifetime: AXObjectCache::m_document is const,
there is
one cache per document under ACCESSIBILITY_LOCAL_FRAME (computeIsIgnored
relies on
this), and isMainFrame() is fixed for a given frame otherwise. The
cache-is-null
teardown case is intentionally not memoized.
- AXObjectCache::getOrCreate(Widget&) is now an inline fast path (get() +
getOrCreateSlow(Widget&)), matching the existing getOrCreate(Node&)/(Element&)
pattern in AXObjectCacheInlines.h.
These yield a 0.79% improvement on our Speedometer 3.1 score.
* Source/WebCore/accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::getOrCreateSlow):
* Source/WebCore/accessibility/AXObjectCache.h:
* Source/WebCore/accessibility/AXObjectCacheInlines.h:
(WebCore::AXObjectCache::getOrCreate):
* Source/WebCore/accessibility/AXUtilities.cpp:
(WebCore::hasRole):
(WebCore::hasAnyRole):
* Source/WebCore/accessibility/AXUtilities.h:
* Source/WebCore/accessibility/AccessibilityScrollView.cpp:
(WebCore::AccessibilityScrollView::isRoot const):
* Source/WebCore/accessibility/AccessibilityScrollView.h:
Canonical link: https://commits.webkit.org/314234@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications