Title: [270238] trunk/Source/WebCore
Revision
270238
Author
[email protected]
Date
2020-11-30 06:11:02 -0800 (Mon, 30 Nov 2020)

Log Message

AXIsolatedTree::m_axObjectCache should not be accessed on the secondary AX thread.
https://bugs.webkit.org/show_bug.cgi?id=219223

Reviewed by Chris Fleizach.

AXIsolatedTree::m_axObjectCache was being set on the main thread and
also accessed on the AX thread in the nodeForID and applyPendingChanges
methods. This problem is fixed with this change by adding the member
variable m_usedOnAXThread that is initialized on the main thread and only
used on the AX thread. This means also a performance optimization since
nodeForID and applyPendingChanges are called very frequently.
In addition, the change to AXIsolatedTree::create fixes a possible race
condition between the time the newly created tree was added to the map
of trees on the main thread, and the time that the tree is ready to be
used on the AX thread. Now the newly created tree is not added to the
trees map until it is fully functional.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::getOrCreateIsolatedTree const):
(WebCore::AXObjectCache::generateIsolatedTree): Deleted, the creation
and initialization of the isolated tree is now done in
AXIsolatedTree::create.

* accessibility/AXObjectCache.h:
(WebCore::AXObjectCache::pageID const): Getter for the m_pageID member
variable.

* accessibility/isolatedtree/AXIsolatedObject.cpp:
(WebCore::AXIsolatedObject::AXIsolatedObject): Now takes a pointer t the
tree instead of a tree ID.
(WebCore::AXIsolatedObject::create): Same as above.
(WebCore::AXIsolatedObject::associatedAXObject const):
(WebCore::AXIsolatedObject::setSelectedChildren): Check for nullity of
the AXObjectCache.
* accessibility/isolatedtree/AXIsolatedObject.h:
* accessibility/isolatedtree/AXIsolatedTree.cpp:
(WebCore::AXIsolatedTree::AXIsolatedTree): Takes an AXObjectCache.
(WebCore::AXIsolatedTree::clear):
(WebCore::AXIsolatedTree::create): Takes an AXObjectCache.
(WebCore::AXIsolatedTree::nodeForID const):
(WebCore::AXIsolatedTree::createSubtree):
(WebCore::AXIsolatedTree::updateNode):
(WebCore::AXIsolatedTree::applyPendingChanges):
(WebCore::AXIsolatedTree::createTreeForPageID): Deleted, became
AXIsolatedTree::create.
* accessibility/isolatedtree/AXIsolatedTree.h:
(WebCore::AXIsolatedTree::axObjectCache const):
(WebCore::AXIsolatedTree::setAXObjectCache): Deleted, can be set only at
construction time.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (270237 => 270238)


--- trunk/Source/WebCore/ChangeLog	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/ChangeLog	2020-11-30 14:11:02 UTC (rev 270238)
@@ -1,3 +1,55 @@
+2020-11-30  Andres Gonzalez  <[email protected]>
+
+        AXIsolatedTree::m_axObjectCache should not be accessed on the secondary AX thread.
+        https://bugs.webkit.org/show_bug.cgi?id=219223
+
+        Reviewed by Chris Fleizach.
+
+        AXIsolatedTree::m_axObjectCache was being set on the main thread and
+        also accessed on the AX thread in the nodeForID and applyPendingChanges
+        methods. This problem is fixed with this change by adding the member
+        variable m_usedOnAXThread that is initialized on the main thread and only
+        used on the AX thread. This means also a performance optimization since
+        nodeForID and applyPendingChanges are called very frequently.
+        In addition, the change to AXIsolatedTree::create fixes a possible race
+        condition between the time the newly created tree was added to the map
+        of trees on the main thread, and the time that the tree is ready to be
+        used on the AX thread. Now the newly created tree is not added to the
+        trees map until it is fully functional.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::getOrCreateIsolatedTree const):
+        (WebCore::AXObjectCache::generateIsolatedTree): Deleted, the creation
+        and initialization of the isolated tree is now done in
+        AXIsolatedTree::create.
+
+        * accessibility/AXObjectCache.h:
+        (WebCore::AXObjectCache::pageID const): Getter for the m_pageID member
+        variable.
+
+        * accessibility/isolatedtree/AXIsolatedObject.cpp:
+        (WebCore::AXIsolatedObject::AXIsolatedObject): Now takes a pointer t the
+        tree instead of a tree ID.
+        (WebCore::AXIsolatedObject::create): Same as above.
+        (WebCore::AXIsolatedObject::associatedAXObject const):
+        (WebCore::AXIsolatedObject::setSelectedChildren): Check for nullity of
+        the AXObjectCache.
+        * accessibility/isolatedtree/AXIsolatedObject.h:
+        * accessibility/isolatedtree/AXIsolatedTree.cpp:
+        (WebCore::AXIsolatedTree::AXIsolatedTree): Takes an AXObjectCache.
+        (WebCore::AXIsolatedTree::clear):
+        (WebCore::AXIsolatedTree::create): Takes an AXObjectCache.
+        (WebCore::AXIsolatedTree::nodeForID const):
+        (WebCore::AXIsolatedTree::createSubtree):
+        (WebCore::AXIsolatedTree::updateNode):
+        (WebCore::AXIsolatedTree::applyPendingChanges):
+        (WebCore::AXIsolatedTree::createTreeForPageID): Deleted, became
+        AXIsolatedTree::create.
+        * accessibility/isolatedtree/AXIsolatedTree.h:
+        (WebCore::AXIsolatedTree::axObjectCache const):
+        (WebCore::AXIsolatedTree::setAXObjectCache): Deleted, can be set only at
+        construction time.
+
 2020-11-30  Xabier Rodriguez Calvar  <[email protected]>
 
         [GStreamer] Media player does not properly inhibit, uninhibit sleep

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (270237 => 270238)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2020-11-30 14:11:02 UTC (rev 270238)
@@ -790,7 +790,7 @@
     auto tree = AXIsolatedTree::treeForPageID(*m_pageID);
     if (!tree) {
         tree = Accessibility::retrieveValueFromMainThread<RefPtr<AXIsolatedTree>>([this] () -> RefPtr<AXIsolatedTree> {
-            return generateIsolatedTree(*m_pageID, m_document);
+            return AXIsolatedTree::create(const_cast<AXObjectCache*>(this));
         });
         AXObjectCache::initializeSecondaryAXThread();
     }
@@ -3162,31 +3162,6 @@
 }
     
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
-Ref<AXIsolatedTree> AXObjectCache::generateIsolatedTree(PageIdentifier pageID, Document& document)
-{
-    AXTRACE("AXObjectCache::generateIsolatedTree");
-    RELEASE_ASSERT(isMainThread());
-
-    RefPtr<AXIsolatedTree> tree(AXIsolatedTree::createTreeForPageID(pageID));
-
-    // Set the root and focused objects in the isolated tree. For that, we need
-    // the root and the focused object in the AXObject tree.
-    auto* axObjectCache = document.axObjectCache();
-    if (!axObjectCache)
-        return makeRef(*tree);
-    tree->setAXObjectCache(axObjectCache);
-
-    auto* axRoot = axObjectCache->getOrCreate(document.view());
-    if (axRoot)
-        tree->generateSubtree(*axRoot, nullptr, true);
-
-    auto* axFocus = axObjectCache->focusedObjectForPage(document.page());
-    if (axFocus)
-        tree->setFocusedNodeID(axFocus->objectID());
-
-    return makeRef(*tree);
-}
-
 void AXObjectCache::updateIsolatedTree(AXCoreObject& object, AXNotification notification)
 {
     AXTRACE("AXObjectCache::updateIsolatedTree");

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (270237 => 270238)


--- trunk/Source/WebCore/accessibility/AXObjectCache.h	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h	2020-11-30 14:11:02 UTC (rev 270238)
@@ -352,6 +352,7 @@
     AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); }
 
     Document& document() const { return m_document; }
+    Optional<PageIdentifier> pageID() const { return m_pageID; }
 
 #if PLATFORM(MAC)
     static void setShouldRepostNotificationsForTests(bool value);
@@ -372,7 +373,6 @@
     AXCoreObject* isolatedTreeRootObject();
     AXCoreObject* isolatedTreeFocusedObject();
     void setIsolatedTreeFocusedObject(Node*);
-    static Ref<AXIsolatedTree> generateIsolatedTree(PageIdentifier, Document&);
     RefPtr<AXIsolatedTree> getOrCreateIsolatedTree() const;
     void updateIsolatedTree(AXCoreObject&, AXNotification);
     void updateIsolatedTree(AXCoreObject*, AXNotification);
@@ -432,7 +432,6 @@
 
 private:
     AccessibilityObject* rootWebArea();
-
     static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*);
 
     AXID getAXID(AccessibilityObject*);

Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp (270237 => 270238)


--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp	2020-11-30 14:11:02 UTC (rev 270238)
@@ -36,14 +36,12 @@
 
 namespace WebCore {
 
-AXIsolatedObject::AXIsolatedObject(AXCoreObject& object, AXIsolatedTreeID treeID, AXID parentID)
-    : m_treeID(treeID)
+AXIsolatedObject::AXIsolatedObject(AXCoreObject& object, AXIsolatedTree* tree, AXID parentID)
+    : m_cachedTree(tree)
     , m_parentID(parentID)
     , m_id(object.objectID())
 {
     ASSERT(isMainThread());
-    if (auto tree = AXIsolatedTree::treeForID(m_treeID))
-        m_cachedTree = tree;
     if (m_id != InvalidAXID)
         initializeAttributeData(object, parentID == InvalidAXID);
     else {
@@ -52,9 +50,9 @@
     }
 }
 
-Ref<AXIsolatedObject> AXIsolatedObject::create(AXCoreObject& object, AXIsolatedTreeID treeID, AXID parentID)
+Ref<AXIsolatedObject> AXIsolatedObject::create(AXCoreObject& object, AXIsolatedTree* tree, AXID parentID)
 {
-    return adoptRef(*new AXIsolatedObject(object, treeID, parentID));
+    return adoptRef(*new AXIsolatedObject(object, tree, parentID));
 }
 
 AXIsolatedObject::~AXIsolatedObject()
@@ -405,6 +403,14 @@
     initializePlatformProperties(object);
 }
 
+AXCoreObject* AXIsolatedObject::associatedAXObject() const
+{
+    ASSERT(isMainThread());
+
+    auto* axObjectCache = this->axObjectCache();
+    return axObjectCache && m_id != InvalidAXID ? axObjectCache->objectFromAXID(m_id) : nullptr;
+}
+
 void AXIsolatedObject::setMathscripts(AXPropertyName propertyName, AXCoreObject& object)
 {
     AccessibilityMathMultiscriptPairs pairs;
@@ -511,10 +517,12 @@
             return;
         }
 
-        ASSERT(axObjectCache());
+        auto* axObjectCache = this->axObjectCache();
+        if (!axObjectCache)
+            return;
 
         auto axIDs = tree()->idsForObjects(selectedChildren);
-        auto axSelectedChildren = axObjectCache()->objectsForIDs(axIDs);
+        auto axSelectedChildren = axObjectCache->objectsForIDs(axIDs);
         object->setSelectedChildren(axSelectedChildren);
     });
 }

Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h (270237 => 270238)


--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h	2020-11-30 14:11:02 UTC (rev 270238)
@@ -47,7 +47,7 @@
 class AXIsolatedObject final : public AXCoreObject {
     friend class AXIsolatedTree;
 public:
-    static Ref<AXIsolatedObject> create(AXCoreObject&, AXIsolatedTreeID, AXID parentID);
+    static Ref<AXIsolatedObject> create(AXCoreObject&, AXIsolatedTree*, AXID parentID);
     ~AXIsolatedObject();
 
     void setObjectID(AXID id) override { m_id = id; }
@@ -58,14 +58,6 @@
     bool isDetached() const override;
 
     void setParent(AXID);
-    void setChildrenIDs(Vector<AXID>&& childrenIDs)
-    {
-        // FIXME: The following ASSERT should be met but it is commented out at the
-        // moment because of <rdar://problem/63985646> After calling _AXUIElementUseSecondaryAXThread(true),
-        // still receives client request on main thread.
-        // ASSERT(axObjectCache()->canUseSecondaryAXThread() ? !isMainThread() : isMainThread());
-        m_childrenIDs = childrenIDs;
-    }
 
 private:
     void detachRemoteParts(AccessibilityDetachmentType) override;
@@ -73,19 +65,14 @@
 
     AXID parent() const { return m_parentID; }
 
-    AXIsolatedTreeID treeIdentifier() const { return m_treeID; }
     AXIsolatedTree* tree() const { return m_cachedTree.get(); }
 
     AXIsolatedObject() = default;
-    AXIsolatedObject(AXCoreObject&, AXIsolatedTreeID, AXID parentID);
+    AXIsolatedObject(AXCoreObject&, AXIsolatedTree*, AXID parentID);
     bool isAXIsolatedObjectInstance() const override { return true; }
     void initializeAttributeData(AXCoreObject&, bool isRoot);
     void initializePlatformProperties(const AXCoreObject&);
-    AXCoreObject* associatedAXObject() const
-    {
-        ASSERT(isMainThread());
-        return m_id != InvalidAXID ? axObjectCache()->objectFromAXID(m_id) : nullptr;
-    }
+    AXCoreObject* associatedAXObject() const;
 
     void setProperty(AXPropertyName, AXPropertyValueVariant&&, bool shouldRemove = false);
     void setObjectProperty(AXPropertyName, AXCoreObject*);
@@ -650,7 +637,6 @@
     String innerHTML() const override;
     String outerHTML() const override;
 
-    AXIsolatedTreeID m_treeID;
     RefPtr<AXIsolatedTree> m_cachedTree;
     AXID m_parentID { InvalidAXID };
     AXID m_id { InvalidAXID };

Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp (270237 => 270238)


--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp	2020-11-30 14:11:02 UTC (rev 270238)
@@ -55,10 +55,13 @@
     return map;
 }
 
-AXIsolatedTree::AXIsolatedTree()
+AXIsolatedTree::AXIsolatedTree(AXObjectCache* axObjectCache)
     : m_treeID(newTreeID())
+    , m_axObjectCache(axObjectCache)
+    , m_usedOnAXThread(axObjectCache->canUseSecondaryAXThread())
 {
     AXTRACE("AXIsolatedTree::AXIsolatedTree");
+    ASSERT(isMainThread());
 }
 
 AXIsolatedTree::~AXIsolatedTree()
@@ -70,21 +73,14 @@
 {
     AXTRACE("AXIsolatedTree::clear");
     ASSERT(isMainThread());
+    m_axObjectCache = nullptr;
 
     LockHolder locker { m_changeLogLock };
     m_pendingSubtreeRemovals.append(m_rootNode->objectID());
     m_rootNode = nullptr;
     m_nodeMap.clear();
-    m_axObjectCache = nullptr;
 }
 
-Ref<AXIsolatedTree> AXIsolatedTree::create()
-{
-    AXTRACE("AXIsolatedTree::create");
-    ASSERT(isMainThread());
-    return adoptRef(*new AXIsolatedTree());
-}
-
 RefPtr<AXIsolatedTree> AXIsolatedTree::treeForID(AXIsolatedTreeID treeID)
 {
     AXTRACE("AXIsolatedTree::treeForID");
@@ -91,16 +87,32 @@
     return treeIDCache().get(treeID);
 }
 
-Ref<AXIsolatedTree> AXIsolatedTree::createTreeForPageID(PageIdentifier pageID)
+Ref<AXIsolatedTree> AXIsolatedTree::create(AXObjectCache* axObjectCache)
 {
-    AXTRACE("AXIsolatedTree::createTreeForPageID");
+    AXTRACE("AXIsolatedTree::create");
+    ASSERT(isMainThread());
+    ASSERT(axObjectCache && axObjectCache->pageID());
+
+    auto tree = adoptRef(*new AXIsolatedTree(axObjectCache));
+
+    // Generate the nodes of the tree and set its root and focused objects.
+    // For this, we need the root and focused objects of the AXObject tree.
+    auto* axRoot = axObjectCache->getOrCreate(axObjectCache->document().view());
+    if (axRoot)
+        tree->generateSubtree(*axRoot, nullptr, true);
+    auto* axFocus = axObjectCache->focusedObjectForPage(axObjectCache->document().page());
+    if (axFocus)
+        tree->setFocusedNodeID(axFocus->objectID());
+
+    // Now that the tree is ready to take client requests, add it to the tree
+    // maps so that it can be found.
+    auto pageID = axObjectCache->pageID();
     LockHolder locker(s_cacheLock);
-    ASSERT(!treePageCache().contains(pageID));
+    ASSERT(!treePageCache().contains(*pageID));
+    treePageCache().set(*pageID, tree.copyRef());
+    treeIDCache().set(tree->treeID(), tree.copyRef());
 
-    auto newTree = AXIsolatedTree::create();
-    treePageCache().set(pageID, newTree.copyRef());
-    treeIDCache().set(newTree->treeID(), newTree.copyRef());
-    return newTree;
+    return tree;
 }
 
 void AXIsolatedTree::removeTreeForPageID(PageIdentifier pageID)
@@ -128,7 +140,7 @@
 RefPtr<AXIsolatedObject> AXIsolatedTree::nodeForID(AXID axID) const
 {
     // In isolated tree mode 2, only access m_readerThreadNodeMap on the AX thread.
-    if (axObjectCache()->canUseSecondaryAXThread() && isMainThread())
+    if (m_usedOnAXThread && isMainThread())
         return nullptr;
 
     return axID != InvalidAXID ? m_readerThreadNodeMap.get(axID) : nullptr;
@@ -187,7 +199,7 @@
     AXTRACE("AXIsolatedTree::createSubtree");
     ASSERT(isMainThread());
 
-    auto object = AXIsolatedObject::create(axObject, m_treeID, parentID);
+    auto object = AXIsolatedObject::create(axObject, this, parentID);
     if (object->objectID() == InvalidAXID) {
         // Either the axObject has an invalid ID or something else went terribly wrong. Don't bother doing anything else.
         ASSERT_NOT_REACHED();
@@ -229,7 +241,7 @@
     auto* axParent = axObject.parentObject();
     AXID parentID = axParent ? axParent->objectID() : InvalidAXID;
 
-    auto newObject = AXIsolatedObject::create(axObject, m_treeID, parentID);
+    auto newObject = AXIsolatedObject::create(axObject, this, parentID);
     newObject->m_childrenIDs = axObject.childrenIDs();
 
     LockHolder locker { m_changeLogLock };
@@ -419,7 +431,7 @@
     AXTRACE("AXIsolatedTree::applyPendingChanges");
 
     // In isolated tree mode 2, only apply pending changes on the AX thread.
-    if (axObjectCache()->canUseSecondaryAXThread() && isMainThread())
+    if (m_usedOnAXThread && isMainThread())
         return;
 
     LockHolder locker { m_changeLogLock };
@@ -487,7 +499,7 @@
     for (auto& update : m_pendingChildrenUpdates) {
         AXLOG(makeString("updating children for axID ", update.first));
         if (auto object = nodeForID(update.first))
-            object->setChildrenIDs(WTFMove(update.second));
+            object->m_childrenIDs = WTFMove(update.second);
     }
     m_pendingChildrenUpdates.clear();
 

Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h (270237 => 270238)


--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h	2020-11-30 12:49:33 UTC (rev 270237)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h	2020-11-30 14:11:02 UTC (rev 270238)
@@ -322,16 +322,14 @@
     WTF_MAKE_NONCOPYABLE(AXIsolatedTree); WTF_MAKE_FAST_ALLOCATED;
     friend WTF::TextStream& operator<<(WTF::TextStream&, AXIsolatedTree&);
 public:
-    static Ref<AXIsolatedTree> create();
+    static Ref<AXIsolatedTree> create(AXObjectCache*);
     virtual ~AXIsolatedTree();
 
-    static Ref<AXIsolatedTree> createTreeForPageID(PageIdentifier);
     static void removeTreeForPageID(PageIdentifier);
 
     static RefPtr<AXIsolatedTree> treeForPageID(PageIdentifier);
     static RefPtr<AXIsolatedTree> treeForID(AXIsolatedTreeID);
-    AXObjectCache* axObjectCache() const { return m_axObjectCache; }
-    void setAXObjectCache(AXObjectCache* axObjectCache) { m_axObjectCache = axObjectCache; }
+    AXObjectCache* axObjectCache() const;
 
     RefPtr<AXIsolatedObject> rootNode();
     RefPtr<AXIsolatedObject> focusedNode();
@@ -368,7 +366,7 @@
     AXIsolatedTreeID treeID() const { return m_treeID; }
 
 private:
-    AXIsolatedTree();
+    AXIsolatedTree(AXObjectCache*);
     void clear();
 
     static HashMap<AXIsolatedTreeID, Ref<AXIsolatedTree>>& treeIDCache();
@@ -381,6 +379,7 @@
 
     AXIsolatedTreeID m_treeID;
     AXObjectCache* m_axObjectCache { nullptr };
+    bool m_usedOnAXThread { true };
 
     // Only accessed on main thread.
     HashMap<AXID, Vector<AXID>> m_nodeMap;
@@ -399,6 +398,12 @@
     Lock m_changeLogLock;
 };
 
+inline AXObjectCache* AXIsolatedTree::axObjectCache() const
+{
+    ASSERT(isMainThread());
+    return m_axObjectCache;
+}
+
 } // namespace WebCore
 
 #endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to