Title: [104880] branches/safari-534.54-branch/Source/WebCore

Diff

Modified: branches/safari-534.54-branch/Source/WebCore/ChangeLog (104879 => 104880)


--- branches/safari-534.54-branch/Source/WebCore/ChangeLog	2012-01-13 00:30:55 UTC (rev 104879)
+++ branches/safari-534.54-branch/Source/WebCore/ChangeLog	2012-01-13 00:31:36 UTC (rev 104880)
@@ -1,5 +1,33 @@
 2011-1-12  Lucas Forschler  <lforsch...@apple.com>
 
+    Merge 103082
+
+    2011-12-15  Alexey Proskuryakov  <a...@apple.com>
+
+            Poor XPath performance when evaluating an _expression_ that returns a lot of nodes
+            https://bugs.webkit.org/show_bug.cgi?id=74665
+            <rdar://problem/10517146>
+
+            Reviewed by Darin Adler.
+
+            No change in funcitonality. Well covered by existing tests (ran them with zero cutoff to
+            execute the new code path).
+
+            Our sorting function is optimized for small node sets in large documents, and this is the
+            opposite of it. Added another one that traverses the whole document, adding nodes from the
+            node set to sorted list. That doesn't grow with the number of nodes nearly as fast.
+
+            Cutoff amount chosen for the document referenced in bug - this is roughly where the algorithms
+            have the same performance on it.
+
+            * xml/XPathNodeSet.cpp:
+            (WebCore::XPath::NodeSet::sort):
+            (WebCore::XPath::findRootNode):
+            (WebCore::XPath::NodeSet::traversalSort):
+            * xml/XPathNodeSet.h:
+
+2011-1-12  Lucas Forschler  <lforsch...@apple.com>
+
     Merge 102024
 
     2011-12-02  Jer Noble  <jer.no...@apple.com>

Modified: branches/safari-534.54-branch/Source/WebCore/xml/XPathNodeSet.cpp (104879 => 104880)


--- branches/safari-534.54-branch/Source/WebCore/xml/XPathNodeSet.cpp	2012-01-13 00:30:55 UTC (rev 104879)
+++ branches/safari-534.54-branch/Source/WebCore/xml/XPathNodeSet.cpp	2012-01-13 00:31:36 UTC (rev 104880)
@@ -35,6 +35,10 @@
 namespace WebCore {
 namespace XPath {
 
+// When a node set is large, sorting it by traversing the whole document is better (we can
+// assume that we aren't dealing with documents that we cannot even traverse in reasonable time).
+const unsigned traversalSortCutoff = 10000;
+
 static inline Node* parentWithDepth(unsigned depth, const Vector<Node*>& parents)
 {
     ASSERT(parents.size() >= depth + 1);
@@ -142,7 +146,12 @@
         const_cast<bool&>(m_isSorted) = true;
         return;
     }
-    
+
+    if (nodeCount > traversalSortCutoff) {
+        traversalSort();
+        return;
+    }
+
     bool containsAttributeNodes = false;
     
     Vector<Vector<Node*> > parentMatrix(nodeCount);
@@ -166,9 +175,62 @@
     for (unsigned i = 0; i < nodeCount; ++i)
         sortedNodes.append(parentMatrix[i][0]);
     
-    const_cast<Vector<RefPtr<Node> >& >(m_nodes).swap(sortedNodes);
+    const_cast<Vector<RefPtr<Node> >&>(m_nodes).swap(sortedNodes);
 }
 
+static Node* findRootNode(Node* node)
+{
+    if (node->isAttributeNode())
+        node = static_cast<Attr*>(node)->ownerElement();
+    if (node->inDocument())
+        node = node->document();
+    else {
+        while (Node* parent = node->parentNode())
+            node = parent;
+    }
+    return node;
+}
+
+void NodeSet::traversalSort() const
+{
+    HashSet<Node*> nodes;
+    bool containsAttributeNodes = false;
+
+    unsigned nodeCount = m_nodes.size();
+    ASSERT(nodeCount > 1);
+    for (unsigned i = 0; i < nodeCount; ++i) {
+        Node* node = m_nodes[i].get();
+        nodes.add(node);
+        if (node->isAttributeNode())
+            containsAttributeNodes = true;
+    }
+
+    Vector<RefPtr<Node> > sortedNodes;
+    sortedNodes.reserveInitialCapacity(nodeCount);
+
+    for (Node* n = findRootNode(m_nodes.first().get()); n; n = n->traverseNextNode()) {
+        if (nodes.contains(n))
+            sortedNodes.append(n);
+
+        if (!containsAttributeNodes || !n->isElementNode())
+            continue;
+
+        NamedNodeMap* attributes = toElement(n)->attributes(true /* read-only */);
+        if (!attributes)
+            continue;
+
+        unsigned attributeCount = attributes->length();
+        for (unsigned i = 0; i < attributeCount; ++i) {
+            Attr* attribute = attributes->attributeItem(i)->attr();
+            if (attribute && nodes.contains(attribute))
+                sortedNodes.append(attribute);
+        }
+    }
+
+    ASSERT(sortedNodes.size() == nodeCount);
+    const_cast<Vector<RefPtr<Node> >&>(m_nodes).swap(sortedNodes);
+}
+
 void NodeSet::reverse()
 {
     if (m_nodes.isEmpty())

Modified: branches/safari-534.54-branch/Source/WebCore/xml/XPathNodeSet.h (104879 => 104880)


--- branches/safari-534.54-branch/Source/WebCore/xml/XPathNodeSet.h	2012-01-13 00:30:55 UTC (rev 104879)
+++ branches/safari-534.54-branch/Source/WebCore/xml/XPathNodeSet.h	2012-01-13 00:31:36 UTC (rev 104880)
@@ -73,6 +73,8 @@
             void reverse();
         
         private:
+            void traversalSort() const;
+
             bool m_isSorted;
             bool m_subtreesAreDisjoint;
             Vector<RefPtr<Node> > m_nodes;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to